Meet Prefect Horizon, the enterprise MCP gateway built by the team behind FastMCP

v2.14.5

These are the docs for FastMCP 2.0. FastMCP 3.0 is now available.

Function-Based Handler

The simplest way to handle messages is with a function that receives all messages:

from fastmcp import Client

async def message_handler(message):
    """Handle all MCP messages from the server."""
    if hasattr(message, 'root'):
        method = message.root.method
        print(f"Received: {method}")

# Handle specific notifications
        if method == "notifications/tools/list_changed":
            print("Tools have changed - might want to refresh tool cache")
        elif method == "notifications/resources/list_changed":
            print("Resources have changed")

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

Message Handler Class

For fine-grained targeting, FastMCP provides a MessageHandler class you can subclass to take advantage of 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 specifically."""
        print("Tool list changed - refreshing available tools")

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

Available Handler Methods

All handler methods receive a single argument - the specific message type:

Message Handler Methods

on_message(message)

Any MCP message Called for ALL messages (requests and notifications)

on_request(request)

mcp.types.ClientRequest Called for requests that expect responses

on_notification(notification)

mcp.types.ServerNotification Called for notifications (fire-and-forget)

on_tool_list_changed(notification)

mcp.types.ToolListChangedNotification Called when the server’s tool list changes

on_resource_list_changed(notification)

mcp.types.ResourceListChangedNotification Called when the server’s resource list changes

on_prompt_list_changed(notification)

mcp.types.PromptListChangedNotification Called when the server’s prompt list changes

on_progress(notification)

mcp.types.ProgressNotification Called for progress updates during long-running operations

on_logging_message(notification)

mcp.types.LoggingMessageNotification Called for log messages from the server

Example: Handling Tool Changes

Here’s a practical example of handling tool list changes:

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())

Handling Requests

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

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