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.
What is MCP Middleware?
MCP middleware lets you intercept and modify MCP requests and responses as they flow through your server. Think of it as a pipeline where each piece of middleware can inspect what’s happening, make changes, and then pass control to the next middleware in the chain. Common use cases for MCP middleware include:- Authentication and Authorization: Verify client permissions before executing operations
- Logging and Monitoring: Track usage patterns and performance metrics
- Rate Limiting: Control request frequency per client or operation type
- Request/Response Transformation: Modify data before it reaches tools or after it leaves
- Caching: Store frequently requested data to improve performance
- Error Handling: Provide consistent error responses across your server
How Middleware Works
FastMCP middleware operates on a pipeline model. When a request comes in, it flows through your middleware in the order they were added to the server. Each middleware can:- Inspect the incoming request and its context
- Modify the request before passing it to the next middleware or handler
- Execute the next middleware/handler in the chain by calling
call_next() - Inspect and modify the response before returning it
- Handle errors that occur during processing
__call__ method on the Middleware base class:
Middleware Hooks
To make it easier for users to target specific types of messages, FastMCP middleware provides a variety of specialized hooks. Instead of implementing the raw__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.
Hook Hierarchy and Execution Order
FastMCP provides multiple hooks that are called with varying levels of specificity. Understanding this hierarchy is crucial for effective middleware design. When a request comes in, multiple hooks may be called for the same request, going from general to specific:on_message- Called for ALL MCP messages (both requests and notifications)on_requestoron_notification- Called based on the message type- Operation-specific hooks - Called for specific MCP operations like
on_call_tool
on_messageandon_requestfor 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 itself
on_message for broad concerns like logging, on_request for authentication, and on_call_tool for tool-specific logic like performance monitoring.
Available Hooks
New in version2.9.0
-
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 executed -
on_read_resource: Called when resources are being read -
on_get_prompt: Called when prompts are being retrieved -
on_list_tools: Called when listing available tools -
on_list_resources: Called when listing available resources -
on_list_resource_templates: Called when listing resource templates -
on_list_prompts: Called when listing available prompts
2.13.0
on_initialize: Called when a client connects and initializes the session (returnsNone)
The
on_initialize hook receives the client’s initialization request but returns None rather than a result. The initialization response is handled internally by the MCP protocol and cannot be modified by middleware. This hook is useful for client detection, logging connections, or initializing session state, but not for modifying the initialization handshake itself.MCP Session Availability in Middleware
New in version2.13.1
The MCP session and request context are not available during certain phases like initialization. When middleware runs during these phases, context.fastmcp_context.request_context returns None rather than the full MCP request context.
This typically occurs when:
- The
on_requesthook fires during client initialization - The MCP handshake hasn’t completed yet
get_http_request() or get_http_headers() from fastmcp.server.dependencies, which work regardless of MCP session availability. See HTTP Requests for details.
Component Access in Middleware
Understanding how to access component information (tools, resources, prompts) in middleware is crucial for building powerful middleware functionality. The access patterns differ significantly between listing operations and execution operations.Listing Operations vs Execution Operations
FastMCP middleware handles two types of operations differently: Listing Operations (on_list_tools, on_list_resources, on_list_prompts, etc.):
- Middleware receives FastMCP component objects with full metadata
- These objects include FastMCP-specific properties like
tagsthat can be accessed directly from the component - The result contains complete component information before it’s converted to MCP format
- Tags are included in the component’s
metafield in the listing response returned to MCP clients
on_call_tool, on_read_resource, on_get_prompt):
- Middleware runs before the component is executed
- The middleware result is either the execution result or an error if the component wasn’t found
- Component metadata isn’t directly available in the hook parameters
Accessing Component Metadata During Execution
If you need to check component properties (like tags) during execution operations, use the FastMCP server instance available through the context:Working with Listing Results
For listing operations, the middlewarecall_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.
Tool Call Denial
You can deny access to specific tools by raising aToolError in your middleware. This is the correct way to block tool execution, as it integrates properly with the FastMCP error handling system.
Tool Call Modification
For execution operations like tool calls, you can modify arguments before execution or transform results afterward:Anatomy of a Hook
Every middleware hook follows the same pattern. Let’s examine theon_message hook to understand the structure:
Hook Parameters
Every hook receives two parameters:-
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.
Control Flow
You have complete control over the request flow:- Continue processing: Call
await call_next(context)to proceed - Modify the request: Change the context before calling
call_next - Modify the response: Change the result after calling
call_next - Stop the chain: Don’t call
call_next(rarely needed) - Handle errors: Wrap
call_nextin try/catch blocks
State Management
New in version2.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.
Creating Middleware
FastMCP middleware is implemented by subclassing theMiddleware base class and overriding the hooks you need. You only need to implement the hooks that are relevant to your use case.
Adding Middleware to Your Server
Single Middleware
Adding middleware to your server is straightforward:Multiple Middleware
Middleware executes in the order it’s added to the server. The first middleware added runs first on the way in, and last on the way out:- AuthenticationMiddleware (pre-processing)
- PerformanceMiddleware (pre-processing)
- LoggingMiddleware (pre-processing)
- Actual tool/resource handler
- LoggingMiddleware (post-processing)
- PerformanceMiddleware (post-processing)
- AuthenticationMiddleware (post-processing)
Server Composition and Middleware
When using Server Composition withmount or import_server, middleware behavior follows these rules:
- Parent server middleware runs for all requests, including those routed to mounted servers
- Mounted server middleware only runs for requests handled by that specific server
- Middleware order is preserved within each server
Built-in Middleware Examples
FastMCP includes several middleware implementations that demonstrate best practices and provide immediately useful functionality. Let’s explore how each type works by building simplified versions, then see how to use the full implementations.Timing Middleware
Performance monitoring is essential for understanding your server’s behavior and identifying bottlenecks. FastMCP includes timing middleware atfastmcp.server.middleware.timing.
Here’s an example of how it works:
on_call_tool and on_read_resource for granular timing.
Tool Injection Middleware
Tool injection middleware is a middleware that injects tools into the server during the request lifecycle:Prompt Tool Middleware
Prompt tool middleware is a compatibility middleware for clients that are unable to list or get prompts. It provides two tools:list_prompts and get_prompt which allow clients to list and get prompts respectively using only tool calls.
Resource Tool Middleware
Resource tool middleware is a compatibility middleware for clients that are unable to list or read resources. It provides two tools:list_resources and read_resource which allow clients to list and read resources respectively using only tool calls.
Caching Middleware
Caching middleware is essential for improving performance and reducing server load. FastMCP provides caching middleware atfastmcp.server.middleware.caching.
Here’s how to use the full version:
Storage Backends
By default, caching uses in-memory storage, which is fast but doesn’t persist across restarts. For production or persistent caching across server restarts, configure a different storage backend. See Storage Backends for complete options including disk, Redis, DynamoDB, and custom implementations. Disk-based caching example:Cache Statistics
The caching middleware collects operation statistics (hits, misses, etc.) through the underlying storage layer. Access statistics from the middleware instance:Logging Middleware
Request and response logging is crucial for debugging, monitoring, and understanding usage patterns in your MCP server. FastMCP provides comprehensive logging middleware atfastmcp.server.middleware.logging.
Here’s an example of how it works:
Rate Limiting Middleware
Rate limiting is essential for protecting your server from abuse, ensuring fair resource usage, and maintaining performance under load. FastMCP includes sophisticated rate limiting middleware atfastmcp.server.middleware.rate_limiting.
Here’s an example of how it works:
Error Handling Middleware
Consistent error handling and recovery is critical for robust MCP servers. FastMCP provides comprehensive error handling middleware atfastmcp.server.middleware.error_handling.
Here’s an example of how it works:

