Add cross-cutting functionality to your MCP server with middleware that can inspect, modify, and respond to all MCP requests and responses.
New in version: 2.9.0
MCP middleware is a powerful concept that allows you to add cross-cutting functionality to your FastMCP server. Unlike traditional web middleware, MCP middleware is designed specifically for the Model Context Protocol, providing hooks for different types of MCP operations like tool calls, resource reads, and prompt requests.
call_next()
__call__
method on the Middleware
base class:
__call__
method, you can override specific hook methods that are called only for certain types of operations, allowing you to target exactly the level of specificity you need for your middleware logic.
on_message
- Called for ALL MCP messages (both requests and notifications)on_request
or on_notification
- Called based on the message typeon_call_tool
on_message
and on_request
for any initial tool discovery operations (list_tools)on_message
(because it’s any MCP message) for the tool call itselfon_request
(because tool calls expect responses) for the tool call itselfon_call_tool
(because it’s specifically a tool execution) for the tool call itselfon_message
for broad concerns like logging, on_request
for authentication, and on_call_tool
for tool-specific logic like performance monitoring.
on_message
: Called for all MCP messages (requests and notifications)on_request
: Called specifically for MCP requests (that expect responses)on_notification
: Called specifically for MCP notifications (fire-and-forget)on_call_tool
: Called when tools are being executedon_read_resource
: Called when resources are being readon_get_prompt
: Called when prompts are being retrievedon_list_tools
: Called when listing available toolson_list_resources
: Called when listing available resourceson_list_resource_templates
: Called when listing resource templateson_list_prompts
: Called when listing available promptson_list_tools
, on_list_resources
, on_list_prompts
, etc.):
tags
that can be accessed directly from the componentmeta
field in the listing response returned to MCP clientson_call_tool
, on_read_resource
, on_get_prompt
):
call_next
function returns a list of FastMCP components prior to being converted to MCP format. You can filter or modify this list and return it to the client. For example:
meta
field in the final listing response.
on_call_tool
, on_read_resource
, on_get_prompt
) to maintain consistency.ToolError
in your middleware. This is the correct way to block tool execution, as it integrates properly with the FastMCP error handling system.
ToolError
rather than returning ToolResult
objects or other values. ToolError
ensures proper error propagation through the middleware chain and converts to the correct MCP error response format.on_message
hook to understand the structure:
context: MiddlewareContext
- Contains information about the current request:
context.method
- The MCP method name (e.g., “tools/call”)context.source
- Where the request came from (“client” or “server”)context.type
- Message type (“request” or “notification”)context.message
- The MCP message datacontext.timestamp
- When the request was receivedcontext.fastmcp_context
- FastMCP Context object (if available)call_next
- A function that continues the middleware chain. You must call this to proceed, unless you want to stop processing entirely.
await call_next(context)
to proceedcall_next
call_next
call_next
(rarely needed)call_next
in try/catch blocksNew in version: 2.11.0
In addition to modifying the request and response, you can also store state data that your tools can (optionally) access later. To do so, use the FastMCP Context to either set_state
or get_state
as appropriate. For more information, see the Context State Management docs.
Middleware
base class and overriding the hooks you need. You only need to implement the hooks that are relevant to your use case.
mount
or import_server
, middleware behavior follows these rules:
fastmcp.server.middleware.timing
.
Here’s an example of how it works:
on_call_tool
and on_read_resource
for granular timing.
fastmcp.server.middleware.logging
.
Here’s an example of how it works:
fastmcp.server.middleware.rate_limiting
.
Here’s an example of how it works:
fastmcp.server.middleware.error_handling
.
Here’s an example of how it works: