mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-17 11:09:11 +02:00
129 lines
No EOL
4.2 KiB
Text
129 lines
No EOL
4.2 KiB
Text
---
|
|
title: Message Handling
|
|
sidebarTitle: Messages
|
|
description: Handle MCP messages, requests, and notifications with custom message handlers.
|
|
icon: envelope
|
|
---
|
|
|
|
import { VersionBadge } from "/snippets/version-badge.mdx";
|
|
|
|
<VersionBadge version="2.9.1" />
|
|
|
|
MCP clients can receive various types of messages from servers, including requests that need responses and notifications that don't. The message handler provides a unified way to process all these messages.
|
|
|
|
## Function-Based Handler
|
|
|
|
The simplest way to handle messages is with a function that receives all messages:
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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:
|
|
|
|
<Card icon="code" title="Message Handler Methods">
|
|
<ResponseField name="on_message(message)" type="Any MCP message">
|
|
Called for ALL messages (requests and notifications)
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_request(request)" type="mcp.types.ClientRequest">
|
|
Called for requests that expect responses
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_notification(notification)" type="mcp.types.ServerNotification">
|
|
Called for notifications (fire-and-forget)
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_tool_list_changed(notification)" type="mcp.types.ToolListChangedNotification">
|
|
Called when the server's tool list changes
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_resource_list_changed(notification)" type="mcp.types.ResourceListChangedNotification">
|
|
Called when the server's resource list changes
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_prompt_list_changed(notification)" type="mcp.types.PromptListChangedNotification">
|
|
Called when the server's prompt list changes
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_progress(notification)" type="mcp.types.ProgressNotification">
|
|
Called for progress updates during long-running operations
|
|
</ResponseField>
|
|
|
|
<ResponseField name="on_logging_message(notification)" type="mcp.types.LoggingMessageNotification">
|
|
Called for log messages from the server
|
|
</ResponseField>
|
|
</Card>
|
|
|
|
## Example: Handling Tool Changes
|
|
|
|
Here's a practical example of handling tool list changes:
|
|
|
|
```python
|
|
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:
|
|
|
|
- **Sampling requests**: Use [`sampling_handler`](/v2/clients/sampling)
|
|
- **Progress requests**: Use [`progress_handler`](/v2/clients/progress)
|
|
- **Log requests**: Use [`log_handler`](/v2/clients/logging)
|
|
|
|
The message handler is primarily for monitoring and handling notifications rather than responding to requests. |