【FastMCP】中间件

什么是 MCP Middleware?

  • MCP Middleware 是 FastMCP 在 2.9.0 版本之后 引入的一种机制,用于在服务器层面插入"跨切面"逻辑(cross-cutting logic),拦截、修改、控制所有的 MCP 请求和响应。(gofastmcp.com)

  • 它并不是 MCP 协议本身的一部分,而是 FastMCP 的扩展机制。也就是说,其他 MCP 实现可能没有或不兼容这个中间件系统。(gofastmcp.com)

  • 典型用例包括:

    • 身份验证 / 权限校验
    • 日志记录与监控
    • 限流 / 频率控制
    • 请求/响应转换
    • 缓存
    • 错误处理

中间件让你可以在 "工具执行 / 资源读取 / 提示获取 / 列表操作" 这些执行路径里插入统一逻辑,而不需要每一个工具、资源、或提示都手动加逻辑。


工作机制与生命周期

中间件的执行模型

  • 当一个 MCP 请求流入服务器时,它会按你添加中间件的顺序,依次通过各个中间件(在进入处理器之前),然后在响应返回时再反向通过中间件(后加进来的最先被响应处理)。(gofastmcp.com)

  • 每个中间件的责任通常包括:

    1. 预处理:在进入下一级之前检查或修改请求
    2. 调用下一个环节call_next(context)
    3. 后处理:检查或修改响应
    4. 出错处理:捕获异常、生成错误响应或抛出错误
  • 如果某个中间件选择不调用 call_next,那么这个请求链就可能在这里被拦截、终止或直接响应。要慎用这种中断行为。(gofastmcp.com)

Hook 层次与调用顺序

FastMCP 将中间件钩子(hooks)按"通用 → 特定"分层,这样你可以选择在不同粒度插入逻辑。(gofastmcp.com)

层级 钩子名称 触发时机 / 语义
最通用 on_message 所有 MCP 消息(请求 + 通知)都会触发
通用请求 / 通知 on_request / on_notification 针对是请求类型还是通知类型的消息
操作级别 on_call_toolon_read_resourceon_get_prompton_list_toolson_list_resourceson_list_prompts 针对具体操作(调用工具/读取资源/列出工具等)

比如,当客户端调用某个工具(tools/call),中间件会依次触发:

  1. on_message
  2. on_request(因为请求型)
  3. on_call_tool

这套层次允许你在通用层做统一处理(如日志、权限检查),在特定层做工具级别的细粒度控制(如某工具禁用、修改入参、审计等)(gofastmcp.com)。

列表操作 vs 执行操作的差异

  • 列表操作 (如列出工具、资源、提示)
    中间件会收到的是具体的 FastMCP 组件对象(带有 metadata、tags 等属性)→ 你可以读取、过滤、修饰这些对象。(gofastmcp.com)
  • 执行操作 (如 on_call_toolon_read_resourceon_get_prompt
    中间件拿到的并不是完整组件对象,而是 context + message。组件的 metadata 需要你再通过 fastmcp_context 去查。(gofastmcp.com)

这意味着:如果你希望中间件在执行时根据某个工具的标签做判断,需要额外通过 context.fastmcp_context.fastmcp.get_tool(...) 来查这个工具对象。(gofastmcp.com)


中间件开发细节

Hook 方法签名与参数

任何钩子方法(如 on_messageon_call_tool)通常接收两个参数:

  • context: MiddlewareContext --- 包含当前请求的元信息(方法名、来源、消息体、时间戳等)
  • call_next --- 一个可调用(async 函数),用于继续执行下一个中间件或最终处理器

中间件的标准结构通常是:

python 复制代码
async def on_message(self, context: MiddlewareContext, call_next):
    # 前置逻辑:检查 / 修改 context.message 等
    result = await call_next(context)
    # 后置逻辑:检查 / 修改 result
    return result

你也可以在这个过程中捕获异常、拒绝处理、短路(不调用 call_next)等。(gofastmcp.com)

控制流策略

中间件可以对请求做出如下操作:

  • 继续流程await call_next(context)
  • 修改请求 :在调用 call_next 之前,修改 context.message 或相关字段
  • 修改响应 :在拿到 result 后改写结果(如在返回结果里添加字段)
  • 中断流程 / 拒绝请求 :直接抛出错误(如 ToolErrorResourceErrorPromptError 等)或返回错误响应
  • 捕获异常 / 统一错误处理 :在 try / except 块里包裹 call_next,做错误转换、日志记录、重试等

状态管理(state)

2.11.0 版本之后 ,FastMCP 支持从上下文中存取状态(state),中间件可以 set_state / get_state,让工具、后续中间件或处理器能够共享上下文状态。(gofastmcp.com)

这个特性对于跨中间件共享数据、在一个请求周期内保留中间状态非常有用。


如何在服务器上使用中间件

单个中间件

使用非常简单:

python 复制代码
from fastmcp import FastMCP
from fastmcp.server.middleware import Middleware, MiddlewareContext

class LoggingMiddleware(Middleware):
    async def on_message(self, context: MiddlewareContext, call_next):
        print(f"Processing {context.method} from {context.source}")
        result = await call_next(context)
        print(f"Completed {context.method}")
        return result

mcp = FastMCP("MyServer")
mcp.add_middleware(LoggingMiddleware())

这样,每条 MCP 消息经过服务器时,都会被这个中间件拦截、打印前后日志。(gofastmcp.com)

多个中间件与执行顺序

多个中间件会依次添加,执行顺序如下:

  1. 最先添加的中间件的"前置"逻辑先执行
  2. 最后添加的中间件的"前置逻辑"最后执行
  3. 然后进入实际处理
  4. 响应返回时,最后添加的中间件的后置逻辑最先执行
  5. 最先添加的中间件的后置逻辑最后执行

示例:

python 复制代码
mcp = FastMCP("MyServer")
mcp.add_middleware(AuthenticationMiddleware("token"))
mcp.add_middleware(PerformanceMiddleware())
mcp.add_middleware(LoggingMiddleware())

执行序列:

  • 入站阶段:Auth → Perf → Logging → 处理器
  • 出站阶段:Logging → Perf → Auth (gofastmcp.com)

在组合服务器中的中间件行为(Server Composition)

FastMCP 支持把子服务器 mount 到父服务器。中间件在组合服务器环境下的行为规则如下:

  1. 父服务器中间件会对所有请求生效(包括那些被路由到子服务器的请求)
  2. 子服务器中间件只对被路由到子服务器的请求生效
  3. 每个服务器内部的中间件顺序保持不变 (gofastmcp.com)

举例:

python 复制代码
parent = FastMCP("Parent")
parent.add_middleware(AuthenticationMiddleware("token"))

child = FastMCP("Child")
child.add_middleware(LoggingMiddleware())

@child.tool
def child_tool():
    return "from child"

parent.mount(child, prefix="child")

当 client 调用 child_tool 时,请求先经过 parent 的 AuthenticationMiddleware,再进入子服务器,然后经过 child 的 LoggingMiddleware。(gofastmcp.com)


内置中间件示例与使用

FastMCP 自带一些插件级别的中间件,是实用且推荐的组合。下面是几个经典示例,以及它们的实现思路/作用。

Timing / 性能测量中间件

用于测量每次请求或每个操作的耗时:

  • 示例代码(简化版):

    python 复制代码
    class SimpleTimingMiddleware(Middleware):
        async def on_request(self, context: MiddlewareContext, call_next):
            start = time.perf_counter()
            result = await call_next(context)
            duration_ms = (time.perf_counter() - start) * 1000
            print(f"Request {context.method} took {duration_ms:.2f} ms")
            return result
  • FastMCP 内置版本(如 TimingMiddlewareDetailedTimingMiddleware)提供更完整的日志、配置选项、粒度更细的钩子(如 on_call_toolon_read_resource)等。(gofastmcp.com)

Logging / 日志中间件

用于记录请求、响应、异常等:

  • 简单版本:

    python 复制代码
    class SimpleLoggingMiddleware(Middleware):
        async def on_message(self, context: MiddlewareContext, call_next):
            print(f"Processing {context.method}")
            try:
                result = await call_next(context)
                print(f"Completed {context.method}")
                return result
            except Exception as e:
                print(f"Failed {context.method}: {e}")
                raise
  • 内置版本(LoggingMiddlewareStructuredLoggingMiddleware)支持更多功能,比如:

    * 是否包含 payload(消息体)

    * 最大 payload 长度

    * 结构化 JSON 日志输出(适合日志聚合与追踪系统)

    * 针对不同操作(工具调用、资源读取等)的分层日志

    (gofastmcp.com)

Rate Limiting / 限流中间件

用于控制客户端请求速率,防止滥用:

  • 简单版本(示例):

    python 复制代码
    class SimpleRateLimitMiddleware(Middleware):
        def __init__(self, requests_per_minute=60):
            self.requests_per_minute = requests_per_minute
            self.client_requests = defaultdict(list)
    
        async def on_request(self, context: MiddlewareContext, call_next):
            now = time.time()
            client_id = "default"  # 实际场景应从 context 中提取 client 标识
            # 删除过旧请求记录
            self.client_requests[client_id] = [
                t for t in self.client_requests[client_id] if t > now - 60
            ]
            if len(self.client_requests[client_id]) >= self.requests_per_minute:
                raise McpError(ErrorData(code=-32000, message="Rate limit exceeded"))
            self.client_requests[client_id].append(now)
            return await call_next(context)
  • FastMCP 自带的 RateLimitingMiddlewareSlidingWindowRateLimitingMiddleware 支持更优秀的算法(如 token bucket、滑动窗口)、并支持客户端识别、自定义行为等。(gofastmcp.com)

错误处理中间件

用于统一拦截、记录、转换错误,保持错误响应一致性:

  • 简单示例:

    python 复制代码
    class SimpleErrorHandlingMiddleware(Middleware):
        async def on_message(self, context: MiddlewareContext, call_next):
            try:
                return await call_next(context)
            except Exception as error:
                # 记录错误、统计、转换错误响应等
                logger.error(f"Error in {context.method}: {error}")
                raise
  • 内置版本(ErrorHandlingMiddlewareRetryMiddleware)支持:

    * 是否包含 traceback

    * 错误类型转换

    * 重试机制(对特定异常自动重试)

    * 自定义错误回调逻辑

    (gofastmcp.com)

组合使用中间件

这些中间件之间可以组合使用,形成一个健全的中间件链。通常建议的顺序是:

  1. 错误处理(确保下游异常被捕获)
  2. 限流 / 防护
  3. 性能测量 / 计时
  4. 日志记录 / 可观察性
  5. 其他业务中间件

示例:

python 复制代码
mcp = FastMCP("ProdServer")
mcp.add_middleware(ErrorHandlingMiddleware())
mcp.add_middleware(RateLimitingMiddleware(max_requests_per_second=50))
mcp.add_middleware(TimingMiddleware())
mcp.add_middleware(LoggingMiddleware())

自定义中间件示例及进阶用法

自定义中间件(基础)

假设你想做一个中间件,用于拦截某些工具调用,并在调用前后记录一些自定义信息:

python 复制代码
from fastmcp.server.middleware import Middleware, MiddlewareContext
from fastmcp.exceptions import ToolError

class CustomAuthMiddleware(Middleware):
    async def on_call_tool(self, context: MiddlewareContext, call_next):
        tool_name = context.message.name
        # 拒绝某些工具调用
        if tool_name in ["admin_delete", "config_modify"]:
            raise ToolError("Access denied: insufficient privileges")

        # 修改调用参数(例如限制某个字段为非负数)
        if tool_name == "compute":
            args = context.message.arguments
            if args.get("value", 0) < 0:
                args["value"] = abs(args["value"])

        # 调用下一阶段
        result = await call_next(context)

        # 对返回结果进行增强
        if tool_name == "get_data" and result.structured_content is not None:
            result.structured_content["processed_by"] = "CustomAuthMiddleware"
        return result

你可以将这个中间件加到链中:

python 复制代码
mcp.add_middleware(CustomAuthMiddleware())

中间件共享状态(state)

如果你有多个中间件之间或中间件与工具之间需要共享某些中间状态(比如某次请求的上下文标志、验证 token、追踪 ID 等),可以使用 context 的 state 接口(在 2.11.0+ 版本支持):

python 复制代码
class StateMiddleware(Middleware):
    async def on_request(self, context: MiddlewareContext, call_next):
        # 存储一个随机请求 ID 到状态
        request_id = uuid.uuid4().hex
        context.set_state("request_id", request_id)
        return await call_next(context)

class UseStateMiddleware(Middleware):
    async def on_message(self, context: MiddlewareContext, call_next):
        request_id = context.get_state("request_id")
        print("Request ID is", request_id)
        return await call_next(context)

这样你就可以在同一个请求流中跨多个中间件或工具访问共享的 request_id

高级用例:动态工具替换 / 中间件注入

对于复杂场景,你可能希望:

  • 根据条件动态禁用、替换或代理工具
  • 变更工具行为(例如 wrap 一个工具,使其先跑预处理逻辑再调用真正工具)
  • 在某些请求中跳过某些中间件

这些高级用法可以通过组合 on_list_toolson_call_tool 等钩子实现。关键要点是:

  • 列表阶段 拦截工具、修改工具列表或屏蔽不应公开的工具
  • 执行阶段 再次校验(以防有人直接调用未公开工具)
  • 保持一致性:如果在列表阶段屏蔽掉某工具,在执行阶段也应拒绝其调用

总结与实践建议

  • MCP Middleware 是 FastMCP 提供的强大机制,用于在 MCP 请求/响应流程中插入跨切面逻辑。(gofastmcp.com)
  • 它有一个清晰的钩子层次结构(从 on_messageon_request → 操作级别钩子),能让你在合适的粒度插入逻辑。(gofastmcp.com)
  • 列表操作与执行操作在中间件中访问组件 metadata 的方式不同,需要特别注意。(gofastmcp.com)
  • 通过 state 机制(2.11.0+)可以让中间件和工具之间共享上下文状态。(gofastmcp.com)
  • 利用 FastMCP 自带的中间件(如计时、日志、限流、错误处理),通常能满足大多数需求;你也可以在其基础上扩展或组合出更复杂的行为。(gofastmcp.com)
相关推荐
说私域2 小时前
IP新定义下的商业新范式:基于定制开发开源AI智能名片S2B2C商城小程序的IP价值变现研究
人工智能·tcp/ip·开源
小关会打代码2 小时前
计算机视觉进阶教学之dlib库(二)
人工智能·计算机视觉
黄焖鸡能干四碗2 小时前
企业信息化建设总体规划设计方案
大数据·运维·数据库·人工智能·web安全
GIS 数据栈2 小时前
重构地理信息软件老代码:实践记载之1
人工智能·重构
程序猿阿伟2 小时前
《用AI重构工业设备故障预警系统:从“被动维修”到“主动预判”的协作实践》
人工智能·重构
stjiejieto3 小时前
AI 重构实体经济:2025 传统产业转型的实践与启示
人工智能·重构
Coovally AI模型快速验证3 小时前
华为发布开源超节点架构,以开放战略叩响AI算力生态变局
人工智能·深度学习·神经网络·计算机视觉·华为·架构·开源
CV-杨帆3 小时前
论文阅读:硕士学位论文 2025 面向大语言模型的黑盒对抗性攻击与防御关键技术研究
论文阅读·人工智能·语言模型
berling003 小时前
【论文阅读 | WACV 2025 | MCOR:通过跨模态信息互补和余弦相似性通道重采样模块增强的多光谱目标检测】
论文阅读·人工智能·目标检测