> ## Documentation Index

> Fetch the complete documentation index at: /llms.txt

> Use this file to discover all available pages before exploring further.

Skip to main content
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

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

    from fastmcp import Client

    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

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

    from fastmcp import Client
    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

    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

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

    from fastmcp import Client
    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

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

- Sampling requests: Use `sampling_handler`
- Elicitation requests: Use `elicitation_handler`
- Progress updates: Use `progress_handler`
- Log messages: Use `log_handler`

The message handler is primarily for monitoring and handling notifications rather than responding to requests.
Client Roots
Previous
OAuth Authentication
Next
Ctrl+I
Assistant
Responses are generated using AI and may contain mistakes.
\n\n
\n
\n \n
\n
","contacts":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","dashboard":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","data-table":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","hitchhikers":" \n
\n\n Prefab Showcase\n \n \n \n \n\n
\n
\n \n
\n
","pie-chart":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","reactive":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","team-directory-reactive":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
","team-directory":" \n
\n\n Prefab\n \n \n \n \n\n
\n
\n \n
\n
"};