
MCP 全称Model Context Protocol模型上下文协议是由 Anthropic 发起、现由 Linux 基金会托管的开放行业标准专门解决AI Agent 与外部工具、数据源之间的标准化接入问题。它定义了一套统一的通信规则、能力发现机制和交互格式让任意符合规范的 AI 应用都能无缝调用任意符合规范的外部能力被称为「AI 时代的通用工具接口标准」。Host-Client-Server 的三级架构角色定位核心职责典型实例Host宿主AI 应用本体管理大模型、执行业务逻辑、统筹所有工具会话Claude Desktop、VS Code、Cursor、自研 Agent 平台Client客户端连接器 / 协议适配器每个服务端对应一个独立 Client负责协议握手、消息路由、会话管理、安全隔离Host 内置的 MCP 客户端模块Server服务端能力提供方把底层的 API、数据库、文件系统等包装成标准 MCP 能力对外暴露文件系统服务、数据库服务、第三方业务工具一个Host可以同时管理多个 Client每个 Client 对应一个独立的 Server 连接不同的工具之间天然隔离互不影响两层协议分层MCP 把协议拆分为独立的两层底层通信变化不影响上层业务逻辑数据层内层基于 JSON-RPC 2.0 标准定义所有业务消息的格式语义和交互流程包括生命周期管理核心原语通知机制。这一层和传输方式无关是协议的核心传输层外层定义客户端和服务端之间的通信通道主流支持两种传输方式1.stdio标准输入输出用于本地进程间通信延迟极低适合本地工具服务2.HTTP用于远程服务通信支持跨网络跨部署适合第三方云服务核心原语原语Primitives是 MCP 协议的核心规定了服务端可以对外暴露的能力类型以及客户端可以提供的回调能力所有交互都基于这些标准原语展开。服务端原语服务端通过这三类原语对外暴露能力也是 Agent 开发最常用的部分1.Tools工具可执行的函数是最核心的原语。Agent 可以调用工具执行操作比如查询数据库、调用业务 API、操作文件、执行命令。对应标准方法tools/list发现工具、tools/call调用工具。2.Resource资源给模型提供上下文的数据比如文件内容、表结构、文档片段。模型只能读取不能修改适合给模型注入静态背景信息。3.Prompts提示模板可复用的提示词模板比如少样本示例、工具使用引导、系统提示用来统一模型和工具的交互方式。客户端原语服务端也可以反向向客户端请求能力这是 MCP 和普通 API 最大的区别之一1.Sampling采样服务端可以请求客户端的大模型生成文本比如工具执行到一半需要模型做决策不用自己集成大模型 SDK。2.ELicitation引导服务端可以请求用户补充信息或确认操作比如高危操作前向用户二次确认。3.Logging日志服务端可以向客户端发送日志用于统一调试和监控标准扩展位 _meta字段协议专门在消息结构中预留了_meta字段用于传输带外元数据比如用户身份、会话 ID、链路追踪信息等。这类数据不属于业务参数不应该塞进工具的 arguments 里_meta就是标准的存放位置 —— 这也是你之前笔记里「身份走 _meta」的规范依据。完整的工具链与工具调用生命周期一次标准的 MCP 工具调用从连接建立到结果返回遵循严格的标准化流程1.初始化与能力协商Host 创建 Client向目标 Server 发起 initialize 请求携带客户端支持的能力、协议版本Server 返回自身支持的能力协议版本可用的原语范围Client 发送 notifications/initialized 通知确认握手完成会话进入就绪状态2.工具发现Client 调用 tools/list 方法向 Server 查询当前可用的所有工具Server 返回工具列表包含每个工具的名称、描述、参数 SchemaJSON Schema 格式Client 把工具列表同步给 HostHost 将其注入大模型的上下文供模型决策调用3.工具调用与结果返回模型决定调用某个工具输出工具调用意图Client 封装成标准的 tools/call 请求发送给 ServerServer 执行工具返回结构化结果成功/错误都遵循统一格式Client 把结果回传给 Host注入对话历史模型基于结果继续生成回答MCP vs Function Calling维度Function CallingMCP层级模型能力层通信协议层核心作用让模型输出结构化的工具调用意图让工具以标准方式接入、被发现、被调用工具发现静态工具 Schema 写死在 prompt 或代码里动态运行时通过tools/list实时获取跨厂商兼容不兼容每个厂商格式有差异统一标准任意模型、任意工具都能对接部署形态和应用同进程工具服务独立部署天然隔离Function Calling 是「模型怎么说要调工具」MCP 是「工具怎么接进来、怎么执行」。生产环境中通常两者配合使用模型用 Function Calling 生成调用意图通过 MCP 协议真正执行调用。MCP vs 自定义 REST API维度自定义 REST APIMCP面向对象面向人类开发者、服务间调用面向 AI 模型、Agent 自动调用发现方式静态文档Swagger/OpenAPI设计时确定运行时动态发现工具可实时增减集成成本M×N 复杂度每接一个新工具每个 Agent 都要写适配MN 复杂度工具和 Agent 各接一次标准协议即可互通状态管理默认无状态有状态会话上下文跨调用保留安全边界接口级鉴权逻辑分散在每个接口协议层统一鉴权、隔离、审计REST 是通用的服务间通信协议MCP 是专门为 AI Agent 优化的工具接入协议用官方 Python SDK 写的最小化服务端客户端完整走通「初始化→列工具→调工具」全流程1.服务端import asyncio from mcp.server.fastmcp import FastMCP #创建 MCP 服务实例 mcpFastMCP(DemoCalculator) #注册一个工具 - 自动生成 inputSchema自动暴露给 tools/list mcp.tool() def add(a: int, b: int) - int: Add two integers together return a b if __name____main__: #stdio 传输模式本地进程通信 mcp.run(transportstdio)2.客户端通过 stdio 连接服务端完成完整调用流程import asyncio from mcp.client.stdio import stdio_client from mcp.client.session import ClientSession async def main(): #建立 stdio 传输通道启动子进程运行服务端 async with stdio_client([python, server.py]) as (read, write): #创建会话执行 initialize 握手 async with ClientSession(read, write) as session: await session.initialize() # 调用 tools/list 获取工具列表 toolsawait session.list_tools() print(可用工具: ) for tool in tools.tools: print(f - {tool.name}: {tool.description}) #调用 tools/call 执行 add 工具 resultawait session.call_tool(add, {a:5, b:3}) print(f\n调用结果{result.content[0].text}) if __name____main__: asyncio.run(main())核心方法的源码级实现tool/list 的底层实现tools/list 请求的处理逻辑本质就是遍历注册的工具返回标准化结构async def handle_list_tools(self, request:ListToolRequest) - ListToolsResult: tools[] for name, tool in self._tool_registry.items(): tools.append({ name: name, description: tool.description, inputSchema: tool.input_schema # JSON Schema 格式 }) return ListToolsResult(toolstools)客户端收到后会把这个列表转换成模型能理解的 Function Calling 格式注入 prompt这一步又是怎么实现的tools/call 的底层实现async def handle_call_tool(self, request:CallToolRequest) - CallToolresult: tool_namerequest.params.name argumentsrequest.params.arguments #从注册表查找工具 if tool_name not in self._tool_registry: return CallToolResult( content[{type: text, text: fUnknown tool: {tool_name}}], isErrorTrue ) try: #执行工具函数 resultawait self._tool_registry[tool_name].handler(**arguments) #包装成标准返回格式 return CallToolResult( content[{type:text, text:str(result)}] ) except Exception as e: #结构化错误返回 return CallToolResult( content[{type: text, text: str(e)}], isErrorTrue )