---
schema: rendered-html/v1
title: "Notifications - FastMCP"
source_url: https://gofastmcp.com/clients/notifications
generated_at: 2026-06-11T19:38:27.290300+00:00
---




[FastMCP home page![light logo](images/gofastmcp__com__clients__notifications__wordmark.avif)![dark logo](images/gofastmcp__com__clients__notifications__wordmark-white.avif)](gofastmcp__com.md)







Operations

Notifications

















  - [Tools](gofastmcp__com__clients__tools.md)
  - [Resources](gofastmcp__com__clients__resources.md)
  - [Prompts](gofastmcp__com__clients__prompts.md)
  - [Sampling](gofastmcp__com__clients__sampling.md)
  - [Elicitation](gofastmcp__com__clients__elicitation.md)
  - [Tasks

    NEW](gofastmcp__com__clients__tasks.md)
  - [Progress](gofastmcp__com__clients__progress.md)
  - [Logging](gofastmcp__com__clients__logging.md)
  - [Roots](gofastmcp__com__clients__roots.md)
  - [Notifications](/clients/notifications)






- [Handling Notifications](#handling-notifications)
- [MessageHandler Class](#messagehandler-class)
  - [Handler Template](#handler-template)
- [List Change Notifications](#list-change-notifications)
- [Server Requests](#server-requests)

Operations

# Notifications


Handle server-sent notifications for list changes and other events.


New in version `2.9.1`
Use this when you need to react to server-side changes like tool list updates or resource modifications.
MCP servers can send notifications to inform clients about state changes. The message handler provides a unified way to process these notifications.

## [​](#handling-notifications) Handling Notifications

The simplest approach is a function that receives all messages and filters for the notifications you care about:


async def message_handler(message):
    """Handle MCP notifications from the server."""
    if hasattr(message, 'root'):
        method = message.root.method

        if method == "notifications/tools/list_changed":
            print("Tools have changed - refresh tool cache")
        elif method == "notifications/resources/list_changed":
            print("Resources have changed")
        elif method == "notifications/prompts/list_changed":
            print("Prompts have changed")

client = Client(
    "my_mcp_server.py",
    message_handler=message_handler,

## [​](#messagehandler-class) MessageHandler Class

For fine-grained targeting, subclass `MessageHandler` to use specific hooks:

from fastmcp.client.messages import MessageHandler
import mcp.types

class MyMessageHandler(MessageHandler):
    async def on_tool_list_changed(
        self, notification: mcp.types.ToolListChangedNotification
    ) -> None:
        """Handle tool list changes."""
        print("Tool list changed - refreshing available tools")

    async def on_resource_list_changed(
        self, notification: mcp.types.ResourceListChangedNotification
    ) -> None:
        """Handle resource list changes."""
        print("Resource list changed")

    async def on_prompt_list_changed(
        self, notification: mcp.types.PromptListChangedNotification
    ) -> None:
        """Handle prompt list changes."""
        print("Prompt list changed")

client = Client(
    "my_mcp_server.py",
    message_handler=MyMessageHandler(),

### [​](#handler-template) Handler Template

from fastmcp.client.messages import MessageHandler
import mcp.types

class MyMessageHandler(MessageHandler):
    async def on_message(self, message) -> None:
        """Called for ALL messages (requests and notifications)."""
        pass

    async def on_notification(
        self, notification: mcp.types.ServerNotification
    ) -> None:
        """Called for notifications (fire-and-forget)."""
        pass

    async def on_tool_list_changed(
        self, notification: mcp.types.ToolListChangedNotification
    ) -> None:
        """Called when the server's tool list changes."""
        pass

    async def on_resource_list_changed(
        self, notification: mcp.types.ResourceListChangedNotification
    ) -> None:
        """Called when the server's resource list changes."""
        pass

    async def on_prompt_list_changed(
        self, notification: mcp.types.PromptListChangedNotification
    ) -> None:
        """Called when the server's prompt list changes."""
        pass

    async def on_progress(
        self, notification: mcp.types.ProgressNotification
    ) -> None:
        """Called for progress updates during long-running operations."""
        pass

    async def on_logging_message(
        self, notification: mcp.types.LoggingMessageNotification
    ) -> None:
        """Called for log messages from the server."""
        pass

## [​](#list-change-notifications) List Change Notifications

A practical example of maintaining a tool cache that refreshes when tools change:

from fastmcp.client.messages import MessageHandler
import mcp.types

class ToolCacheHandler(MessageHandler):
    def __init__(self):
        self.cached_tools = []

    async def on_tool_list_changed(
        self, notification: mcp.types.ToolListChangedNotification
    ) -> None:
        """Clear tool cache when tools change."""
        print("Tools changed - clearing cache")
        self.cached_tools = []  # Force refresh on next access

client = Client("server.py", message_handler=ToolCacheHandler())

## [​](#server-requests) Server Requests

While the message handler receives server-initiated requests, you should use dedicated callback parameters for most interactive scenarios:

- **Sampling requests**: Use [`sampling_handler`](gofastmcp__com__clients__sampling.md)
- **Elicitation requests**: Use [`elicitation_handler`](gofastmcp__com__clients__elicitation.md)
- **Progress updates**: Use [`progress_handler`](gofastmcp__com__clients__progress.md)
- **Log messages**: Use [`log_handler`](gofastmcp__com__clients__logging.md)

The message handler is primarily for monitoring and handling notifications rather than responding to requests.

[Client Roots

Previous](gofastmcp__com__clients__roots.md)[OAuth Authentication

Next](gofastmcp__com__clients__auth__oauth.md)






