用Python构建你的第一个MCP服务器(无状态规范版)
内容提要
2026年7月MCP规范转向无状态核心,服务器更易扩展。官方Python SDK v2提供MCPServer高级API,可用普通函数定义工具、资源和提示。教程演示构建开发者知识库服务器,包含search_kb工具、kb://articles资源和draft_support_reply提示,通过Streamable HTTP运行并用Python客户端连接。应用状态应显式传递标识符,而非依赖协议会话。
延伸解读
无状态协议对部署架构的实际影响
2026-07-28版MCP规范将协议核心改为无状态,普通请求不再依赖Mcp-Session-Id。这意味着服务器可以部署在普通HTTP基础设施后,由负载均衡器将请求分发到任意工作进程,无需粘性路由或共享会话存储。对于需要横向扩展的MCP服务,这一变化显著降低了运维复杂度,但多轮交互、共享订阅等高级功能仍需应用层自行处理。
MCPServer高级API与底层Server类的选择
官方Python SDK v2提供MCPServer高级API,允许用普通Python函数和装饰器定义工具、资源和提示,SDK自动从类型提示生成输入模式。对于大多数服务器,这是推荐方式。若需要精确控制模式、协议元数据或自定义方法,则可使用底层Server类。教程中的知识库服务器展示了高级API的典型用法,代码简洁且无需手写JSON Schema。
应用状态应显式传递标识符
无状态协议并不意味着应用不能有状态,而是状态不再隐藏在协议会话中。教程建议采用显式句柄模式:例如创建购物篮时返回basket_id,后续操作要求模型显式传递该标识符。这样应用完全拥有状态管理,请求自包含,便于扩展和调试。开发者需注意,任何需要跨请求保持的数据都应通过参数或返回值显式传递,而非依赖协议会话。
开发与生产运行方式的差异
开发阶段可使用uv run mcp dev server.py启动带MCP Inspector的调试环境,方便列出和调用工具。生产环境则通过mcp.run("streamable-http")运行,默认端点为http://127.0.0.1:8000/mcp。若需集成到FastAPI或Starlette应用,可改用mcp.streamable_http_app()获取ASGI应用,再用Uvicorn启动。这种灵活性允许MCP作为更大应用的一个组件。
Q&A
2026年7月MCP规范的无状态核心是什么意思?
2026-07-28版MCP规范将协议核心改为无状态:现代客户端无需先建立协议会话即可发起请求,服务器也不再依赖Mcp-Session-Id处理普通请求。每个请求自包含,可被任意服务器实例处理,因此更容易在普通HTTP基础设施后扩展。
用Python SDK v2的MCPServer API怎么定义一个MCP工具?
使用@mcp.tool()装饰器修饰普通Python函数即可。SDK会根据函数的类型提示自动生成MCP输入schema,默认值会让参数变为可选,无需手写JSON Schema或工具清单。例如search_kb(query: str, limit: int = 3)会自动生成包含query和limit的schema。
MCP中的资源和工具有什么区别?
工具是模型可以调用的动作,类似POST;资源是暴露给宿主应用加载到上下文的信息,类似GET,客户端无需调用工具即可读取。例如kb://articles资源返回知识库文章列表,而search_kb工具执行搜索操作。
如何用Python客户端连接并调用MCP服务器?
使用mcp.Client,传入HTTP URL(如http://127.0.0.1:8000/mcp)即可自动使用Streamable HTTP。客户端可查看协商的协议版本、列出工具(client.list_tools())并调用工具(client.call_tool())。示例中调用search_kb并打印结构化结果。
无状态MCP下应用需要状态时该怎么处理?
应用状态应由应用自身管理,而不是隐藏在协议会话中。推荐显式传递标识符,例如create_basket()返回basket_id,后续add_item(basket_id, product_id)显式传入该ID。这样模型能看到并传递标识符,符合MCP维护者推荐的显式句柄模式。
无状态MCP服务器如何部署多个worker进行扩展?
由于协议不再要求请求返回之前处理过的worker,可以用uvicorn server:app --workers 4启动多个worker,请求可被任意worker处理,无需粘性路由或共享会话基础设施。负载均衡器可将请求分发到不同worker。