[FastMCP设计、原理与应用-14]FastMCP——架构之魂,构建MCP应用的统一入口与调度中枢

作为一个MCP服务器,FastMCP在底层需要建立一个面向传输(STDIO、SSE和Streamable-HTTP)的服务器用于建立和维护于客户端的连接,并在此基础上完成与客户端的消息交互。具体的消息交互具有如下几种模式:

  • 从客户端到服务器的请求-回复模式:这是主要的消息交换模式,客户端请求服务端获取组件列表、读取资源、渲染提示词和工具调用都采用此种模式;
  • 从服务端到客户端的请求-回复模式:服务端在执行某些操作的时候需要反向请求客户,并要求对方提供某些信息,比如Elicitation就是这类模式的代表;
  • 从服务端到客户端的单向通知模式:当某些状态发生改变时,服务端单向发送通知给客户端,比如当组件列表改变的通知发送便采用这种模式;

由于采用JSON-RPC协议,服务端接收到的每个请求均携带一个具体的方法名称,方法名称关联的操作对请求和响应数据结构均有确定性的描述,所以请求可以精准地被反序列化成操作对应的输入类型,也就是mcp库中定义的各种请求类型。FastMCP会针对具体的请求类型注册对应的处理器,反序列化生成的请求会交给对应的处理器进行处理,返回的结果被序列化成标准的JSON-RPC内容响应给客户端。前面介绍的ProviderTransformMiddleware的应用最终体现在这个处理器的实现上。

python 复制代码
class FastMCP(
    AggregateProvider,
    LifespanMixin,
    MCPOperationsMixin,
    TransportMixin,
    Generic[LifespanResultT],
):
    def __init__(
        self,
        name: str | None = None,
        instructions: str | None = None,
        *,
        version: str | None = None,
        website_url: str | None = None,
        icons: list[mcp.types.Icon] | None = None,
        auth: AuthProvider | None = None,
        middleware: Sequence[Middleware] | None = None,
        providers: Sequence[Provider] | None = None,
        transforms: Sequence[Transform] | None = None,
        lifespan: LifespanCallable | Lifespan | None = None,
        tools: Sequence[Tool | Callable[..., Any]] | None = None,
        on_duplicate: DuplicateBehavior | None = None,
        mask_error_details: bool | None = None,
        dereference_schemas: bool = True,
        strict_input_validation: bool | None = None,
        list_page_size: int | None = None,
        tasks: bool | None = None,
        session_state_store: AsyncKeyValue | None = None,
        sampling_handler: SamplingHandler | None = None,
        sampling_handler_behavior: Literal["always", "fallback"] | None = None,
        **kwargs: Any,
    )
LifespanCallable = Callable[["FastMCP[LifespanResultT]"], AbstractAsyncContextManager[LifespanResultT]]
DuplicateBehavior = Literal["warn", "error", "replace", "ignore"]

上面给出了FastMCP构造函数的定义,我们来看看构造一个FastMCP可以提供哪些参数:

  • name: 服务器名称。如果不传,会自动生成一个随机 ID;
  • instructions:给LLM 的"系统提示词"。告诉模型这个服务器是做什么的、应该如何使用它;
  • version:版本号(支持字符串、整数、浮点数);
  • website_url: 服务器相关的官方链接;
  • icons: 在客户端 UI 中显示的图标列表;
  • auth:处理客户端的身份验证;
  • middleware: 注册的Middleware序列;
  • providers: 注册的Provider序列;
  • transforms: 注册的Transform序列;
  • lifespan:生命周期管理函数。用于在服务器启动/关闭时执行初始化(如连数据库)和清理工作;
  • tools: 初始化时直接注册的工具列表(支持原始函数或 Tool 对象);
  • on_duplicate: 冲突处理策略(如 warn 或 error)。当注册了同名的工具或资源时,决定是警告还是报错;
  • mask_error_details:错误脱敏。开启后,详细的 Python 报错不会发给客户端,防止泄露后端代码细节。
  • dereference_schemas: 是否Schema进行解引用(引用变成内联)。默认开启,将复杂的JSON引用展开,方便LLM理解;
  • strict_input_validation: 严格输入校验。是否强制要求客户端传参完全符合 JSON Schema。
  • list_page_size: 分页大小。当工具或资源非常多时,控制单次列表返回的数量;
  • tasks: 是否启用后台任务支持;
  • session_state_store: 状态存储引擎(默认是内存存储)。用于在不同请求间共享数据;
  • sampling_handler: 采样处理器。当模型需要调用其他模型的能力(Sampling)时,由它处理;
  • sampling_handler_behavior: 采样行为。always(总是使用处理器)或fallback(仅在必要时回退);

FastMCP继承了如下四个基类:

  • AggregateProvider:这是一个Provider,同时也是一个Provider的组合,它重写了Provider的方法并将其转发给作为组合成员的每个Provider
  • LifespanMixin:这是异步服务的状态控制器。管理服务器"从启动到关闭"的全过程。它提供了钩子是我们能在服务器真正开始处理请求前执行初始化代码,并在关闭时优雅地实施回收;
  • MCPOperationsMixin:针对MCP协议的操作定义了对应的方法,上面提到的FastMCP针对每个请求类型注册的处理器指的就是这些方法;
  • TransportMixin:定义了相应的方法以不同的方式启动面向传输的底层服务器;

1. AggregateProvider

AggregateProvider采用典型的组合 设计模式,它自身维护了一组Provider对象(通过构造函数或者调用add_provider方法提供),而自身也是一个Provider对象,这也是我们为什么说FastMCP自身就是一个Provider的原因。AggregateProvider重写了真正用于提供组件的所有九个方法(带下划线前缀的方法),并将方法调用分发给作为组成成员的Provider。对于_list方法,它不会进行去重和过滤处理,返回的是所有Provider提供列表的合并。对于提供指定组件的_get方法,它会选择具有最高版本的那一个(如果具有多个选项,就随机选一个)。

python 复制代码
class AggregateProvider(Provider):
    def __init__(self, providers: Sequence[Provider] | None = None) -> None
    def add_provider(self, provider: Provider, *, namespace: str = "") -> None

    async def _list_tools(self) -> Sequence[Tool]
    async def _get_tool(self, name: str, version: VersionSpec | None = None) -> Tool | None
    async def _list_resources(self) -> Sequence[Resource]
    async def _get_resource(self, uri: str, version: VersionSpec | None = None) -> Resource | None
    async def _list_resource_templates(self) -> Sequence[ResourceTemplate]
    async def _get_resource_template(self, uri: str, version: VersionSpec | None = None) -> ResourceTemplate | None
    async def _list_prompts(self) -> Sequence[Prompt]
    async def _get_prompt(self, name: str, version: VersionSpec | None = None) -> Prompt | None
    async def get_tasks(self) -> Sequence[FastMCPComponent]
    @asynccontextmanager
    async def lifespan(self) -> AsyncIterator[None]

正是因为FastMCP继承了AggregateProvider,让它对组件具有分而治之 的能力。也就是说,如果提供的组件过多,我们可以将其分类,每个类别的组件由对应的Provider来提供。不仅如此,这还赋予了FastMCP可以挂载(Mount)其他FastMCP的能力,谁叫FastMCP就是一个Provider呢。对于需要跨进程或者跨网络远程调用的MCP服务器,我们还可以采用代理的形式进行挂载(将代理定义成Provider)。

2. TransportMixin

FastMCP在底层需要建立一个面向传输的服务器(对应的类型为fastmcp.server.LowLevelServer)用于建立和维护于客户端的连接,并在此基础上完成与客户端的消息交互。TransportMixin定义了相应的方法以不同的模式启动服务器。

python 复制代码
class TransportMixin:
    async def run_async(
        self: FastMCP,
        transport: Transport | None = None,
        show_banner: bool | None = None,
        **transport_kwargs: Any,
    ) -> None

    def run(
        self: FastMCP,
        transport: Transport | None = None,
        show_banner: bool | None = None,
        **transport_kwargs: Any,
    ) -> None

    async def run_stdio_async(
        self: FastMCP,
        show_banner: bool = True,
        log_level: str | None = None,
        stateless: bool = False,
    ) -> None

    async def run_http_async(
        self: FastMCP,
        show_banner: bool = True,
        transport: Literal["http", "streamable-http", "sse"] = "http",
        host: str | None = None,
        port: int | None = None,
        log_level: str | None = None,
        path: str | None = None,
        uvicorn_config: dict[str, Any] | None = None,
        middleware: list[ASGIMiddleware] | None = None,
        json_response: bool | None = None,
        stateless_http: bool | None = None,
        stateless: bool | None = None,
    ) -> None

    def http_app(
        self: FastMCP,
        path: str | None = None,
        middleware: list[ASGIMiddleware] | None = None,
        json_response: bool | None = None,
        stateless_http: bool | None = None,
        transport: Literal["http", "streamable-http", "sse"] = "http",
        event_store: EventStore | None = None,
        retry_interval: int | None = None,
    ) -> StarletteWithLifespan    

    def custom_route(
        self: FastMCP,
        path: str,
        methods: list[str],
        name: str | None = None,
        include_in_schema: bool = True,
    ) -> Callable[
        [Callable[[Request], Awaitable[Response]]],
        Callable[[Request], Awaitable[Response]],
    ]

TransportMixin定义了如下的方法:

  • run_async: 异步启动。在已有asyncio事件循环的环境(如脚本内部)使用。它会根据transport参数决定调用run_stdio_async还是run_http_async;
  • run: 同步封装。这是最常用的入门方法,它内部会自动调用 asyncio.run来启动服务,适合简单的独立脚本;
  • run_http_async:一键启动一个HTTP服务器。它内部集成了Uvicorn,可以直接指定hostport
  • http_app:它不直接启动服务器,而是返回一个Starlette (ASGI) 应用对象。这让你可以把FastMCP集成到现有的FastAPI或自定义Web后端中;
  • custom_route:这是一个用于注册额外的路由的装饰器,它让FastMCP不仅仅是一个MCP服务器,还能当成一个微型Web框架;

在下面演示实例中,我们利用@custom_route装饰器注册了一个用于健康检查的终结点。原则上我们可以采用这种方式利用FastMCP作为一个Web框架来构建一个Web应用。

python 复制代码
from fastmcp import FastMCP
from httpx import AsyncClient
from starlette.requests import Request
from starlette.responses import Response,PlainTextResponse
import asyncio
mcp = FastMCP("Server")

@mcp.custom_route("/health", methods=["GET"])
async def health_check(_: Request) -> Response:
    return PlainTextResponse("healthy", status_code=200)

async def main():
    async with AsyncClient() as client:
      asyncio.create_task(mcp.run_async(transport="streamable-http", host="0.0.0.0", port=3721))
      await asyncio.sleep(2)  # Wait for the server to start
      response = await client.get("http://localhost:3721/health")
      assert response.status_code == 200
      assert response.text == "healthy"

if __name__ == "__main__":
    asyncio.run(main())

3. MCPOperationsMixin

当底层服务器从传输层读取请求,并根据JSON-RPC的方法名反序列化成对应的请求类型后,会根据请求类型提取对应的处理器进行处理,处理器与请求类型的映射关系就是在MCPOperationsMixin中建立的。如下面的代码片段所示,这个类型针对四种组件(工具、静态资源、动态资源模板和提示词,没有后台任务)的七种操作(四种List加上工具执行、资源读取和提示词渲染)定义了对应的处理器函数,它们会在_setup_handlers方法中映射给对应的请求类型。

python 复制代码
class MCPOperationsMixin:

    def _setup_handlers(self: FastMCP) -> None

    async def _list_tools_mcp(self, request: mcp.types.ListToolsRequest) -> mcp.types.ListToolsResult
    async def _list_resources_mcp(self, request: mcp.types.ListResourcesRequest) -> mcp.types.ListResourcesResult
    async def _list_resource_templates_mcp(self, request: mcp.types.ListResourceTemplatesRequest) -> mcp.types.ListResourceTemplatesResult
    async def _list_prompts_mcp(self, request: mcp.types.ListPromptsRequest) -> mcp.types.ListPromptsResult

    async def _call_tool_mcp(self, key: str, arguments: dict[str, Any]) -> (
        list[ContentBlock]
        | tuple[list[ContentBlock], dict[str, Any]]
        | mcp.types.CallToolResult
        | mcp.types.CreateTaskResult
    )
    async def _read_resource_mcp(self, uri: AnyUrl | str) -> mcp.types.ReadResourceResult | mcp.types.CreateTaskResult
    async def _get_prompt_mcp(
        self, name: str, arguments: dict[str, Any] | None
    ) -> mcp.types.GetPromptResult | mcp.types.CreateTaskResult

4. LifespanMixin

LifespanMixin的核心任务是管理 "环境准备" 与 "后台任务"。它确保在服务器处理第一个请求前,所有依赖(如数据库、任务队列)都已就绪,并在关闭时安全退出。

python 复制代码
class LifespanMixin:
    @property
    def docket(self: FastMCP) -> Docket | None
    @asynccontextmanager
    async def _docket_lifespan(self: FastMCP) -> AsyncIterator[None]
    @asynccontextmanager
    async def _lifespan_manager(self: FastMCP) -> AsyncIterator[None]
    def _setup_task_protocol_handlers(self: FastMCP) -> None

LifespanMixin具有如下的类型成员:

  • docket: 返回作为后台任务调度器的Docket对象;
  • _docket_lifespan:是专门为后台任务准备的,负责管理对象DocketWorker相关资源的生命周期;
  • _lifespan_manager:它是整个服务器启动的唯一入口,管理服务器整体状态、引用计数、所有子组件的生命周期;
  • _setup_task_protocol_handlers:在后台任务开关被开启后(Docket对象可用),用于注册基于后台任务执行方法的处理器;

5. LocalProvider

FastMCP利用字段_local_provider返回的LocalProvider作为本地资源提供者,我们利用@tool@resource@propmt装饰器注册的组件实际上全部存储在这个LocalProvider对象中。LocalProvider类型定义如下,它继承自Provider类型,我们可以调用四个remove方法删除注册的组件,还可以调用get_tasks方法返回后台任务列表。

python 复制代码
class LocalProvider(
    Provider,
    ToolDecoratorMixin,
    ResourceDecoratorMixin,
    PromptDecoratorMixin,
):
    def remove_tool(self, name: str, version: str | None = None) -> None
    def remove_resource(self, uri: str, version: str | None = None) -> None
    def remove_template(self, uri_template: str, version: str | None = None) -> None
    def remove_prompt(self, name: str, version: str | None = None) -> None
    async def get_tasks(self) -> Sequence[FastMCPComponent]

用于注册相应资源的装饰器就定义在它继承的三个混入类中。以如下所示的ToolDecoratorMixin为例,标注在工具函数上用于注册工具的@tool装饰器函数就定义在这里。除此之外,它还定义了add_tool方法手工添加工具。其他的混入类(ResourceDecoratorMixinPromptDecoratorMixin)的定义与之类似。

python 复制代码
class ToolDecoratorMixin:
    def add_tool(self: LocalProvider, tool: Tool | Callable[..., Any]) -> Tool
    @overload
    def tool(
        self: LocalProvider,
        name_or_fn: F,
        *,
        name: str | None = None,
        version: str | int | None = None,
        title: str | None = None,
        description: str | None = None,
        icons: list[mcp.types.Icon] | None = None,
        tags: set[str] | None = None,
        output_schema: dict[str, Any] | NotSetT | None = NotSet,
        annotations: ToolAnnotations | dict[str, Any] | None = None,
        exclude_args: list[str] | None = None,
        meta: dict[str, Any] | None = None,
        enabled: bool = True,
        task: bool | TaskConfig | None = None,
        serializer: ToolResultSerializerType | None = None,  # Deprecated
        timeout: float | None = None,
        auth: AuthCheck | list[AuthCheck] | None = None,
    ) -> F: ...
    @overload
    def tool(
        self: LocalProvider,
        name_or_fn: str | None = None,
        *,
        name: str | None = None,
        version: str | int | None = None,
        title: str | None = None,
        description: str | None = None,
        icons: list[mcp.types.Icon] | None = None,
        tags: set[str] | None = None,
        output_schema: dict[str, Any] | NotSetT | None = NotSet,
        annotations: ToolAnnotations | dict[str, Any] | None = None,
        exclude_args: list[str] | None = None,
        meta: dict[str, Any] | None = None,
        enabled: bool = True,
        task: bool | TaskConfig | None = None,
        serializer: ToolResultSerializerType | None = None,  # Deprecated
        timeout: float | None = None,
        auth: AuthCheck | list[AuthCheck] | None = None,
    ) -> Callable[[F], F]: ...
    def tool(
        self: LocalProvider,
        name_or_fn: str | AnyFunction | None = None,
        *,
        name: str | None = None,
        version: str | int | None = None,
        title: str | None = None,
        description: str | None = None,
        icons: list[mcp.types.Icon] | None = None,
        tags: set[str] | None = None,
        output_schema: dict[str, Any] | NotSetT | None = NotSet,
        annotations: ToolAnnotations | dict[str, Any] | None = None,
        exclude_args: list[str] | None = None,
        meta: dict[str, Any] | None = None,
        enabled: bool = True,
        task: bool | TaskConfig | None = None,
        serializer: ToolResultSerializerType | None = None,  # Deprecated
        timeout: float | None = None,
        auth: AuthCheck | list[AuthCheck] | None = None,
    ) -> (
        Callable[[AnyFunction], FunctionTool]
        | FunctionTool
        | partial[Callable[[AnyFunction], FunctionTool] | FunctionTool]
    )
相关推荐
阿杰学AI2 小时前
AI核心知识133—大语言模型之 AI Coding(简洁且通俗易懂版)
人工智能·ai·语言模型·自然语言处理·ai编程·ai coding
2401_882273722 小时前
如何通过MongoDB GridFS实现文件的分块下载
jvm·数据库·python
weixin_580614002 小时前
CSS如何实现动态背景色线性渐变_利用CSS变量控制渐变方向
jvm·数据库·python
weixin_408717772 小时前
mysql如何查询所有列_mysql select星号性能分析
jvm·数据库·python
a9511416422 小时前
mysql权限表查询性能如何优化_MySQL系统权限缓存原理
jvm·数据库·python
23471021272 小时前
4.21 学习笔记
软件测试·笔记·python·学习
踩着两条虫2 小时前
AI + 低代码实战 | 一文吃透 API 管理、Swagger 导入与全局配置
前端·低代码·ai编程
weixin_408099672 小时前
OCR + 自动翻译:跨境电商批量铺货方案(支持多语言自动识别)
python·ocr·机器翻译·api接口·跨境电商·ocr识别·电商自动化
AI自动化工坊2 小时前
T3 Code:专为AI编程代理设计的Web IDE技术实践指南
前端·ide·人工智能·ai编程·t3