智能体面试准备(四):MCP 协议深入——从架构设计到手写一个 MCP Server

发布时间:2026/7/27 2:50:46

智能体面试准备(四):MCP 协议深入——从架构设计到手写一个 MCP Server 智能体面试准备四MCP 协议深入——从架构设计到手写一个 MCP ServerModel Context ProtocolMCP是 Anthropic 在 2024 年底开源的一套标准协议目标是解决每个 AI 应用都要自己接一遍工具的碎片化问题。你可以把它理解成AI 工具调用的 USB-C 接口——定义了一套统一的客户端-服务端协议任何 MCP Server 暴露的工具/资源都能被任何 MCP ClientClaude Desktop、Cursor、自研 Agent直接使用。面试官考 Agent 岗MCP 已经成了 2026 年的高频题这篇文章把它的架构、协议、实现拆透配可运行代码。一、为什么需要 MCPM × N 问题在 MCP 之前让 AI 应用接入外部工具是 M × N 问题M 个 AI 应用Claude、ChatGPT、Cursor、自研 Agent× N 个工具源数据库、文件系统、GitHub、Slack每个组合都要写一遍集成代码。工具一多集成成本爆炸。MCP 的解法是引入一个中间层工具提供方写一个 MCP Server只写一次AI 应用实现一个 MCP Client只写一次二者通过标准协议通信。M × N 降为 M N。| 对比 | 无 MCP | 有 MCP | |---|---|---| | 集成成本 | M × N | M N | | 工具复用 | 每个应用各接一遍 | 写一次 Server所有 Client 通用 | | 协议 | 各家私有 | JSON-RPC 2.0 标准 | | 工具发现 | 硬编码 | 运行时动态发现 | | 换模型/换工具 | 重写集成 | 换 Client/Server 即可 |这个M × N → M N的论点是面试回答 MCP 价值时的核心框架。二、MCP 的三层架构MCP 架构分三层Host宿主、Client客户端、Server服务端。| 角色 | 职责 | 示例 | |---|---|---| | Host | 运行 LLM、管理对话、决定何时调工具的应用 | Claude Desktop、Cursor、IDE 插件 | | Client | Host 内的协议适配层与 Server 通信 | Host 内嵌的 MCP Client 实例 | | Server | 工具/资源的提供方独立进程 | 文件系统 Server、GitHub Server |一个 Host 可以连多个 Server每个 Server 一个 Client 实例每个 Server 暴露若干工具和资源。HostLLM看到的是所有已连接 Server 的工具的合集统一调度。通信方式有两种stdio子进程本地用Server 作为 Host 的子进程运行通过标准输入输出传 JSON-RPC和SSE/HTTP远程用Server 独立部署通过网络通信。本地开发多用 stdio生产部署多用 SSE。三、MCP 的三大能力原语MCP Server 通过三种原语primitive向 Client 暴露能力| 原语 | 方向 | 用途 | 类比 | |---|---|---|---| | Tools | Server → Model | 可执行的操作函数调用 | Function Calling | | Resources | Server → Model | 可读取的数据文件、数据库记录 | GET 请求 | | Prompts | Server → User | 预定义的提示词模板 | Slash 命令 |Tools是最常用的原语等同于 Function Calling 里的函数。Server 声明工具的 SchemaClientHost把它发给 LLMLLM 决定调用时Client 通过协议把调用请求转发给 Server 执行结果返回给 LLM。Resources让 Server 暴露可读数据比如文件系统 Server 暴露file:///path/to/file资源Client 可以按需读取。与 Tools 的区别Resources 是读取幂等、无副作用Tools 是执行可能有副作用。Prompts是预定义的提示词模板用户在 Host 里选一个 PromptServer 填充参数后返回完整提示词给 LLM。适用于标准化工作流。四、JSON-RPC 2.0MCP 的传输协议MCP 用 JSON-RPC 2.0 做消息格式。核心消息类型| 消息类型 | 方向 | 用途 | |---|---|---| | Request | 双向 | 请求带 id期待响应 | | Response | 双向 | 对 Request 的响应 | | Notification | 双向 | 通知不带 id不期待响应 |一个典型的 MCP 交互流程Client → Serverinitialize请求协商协议版本、能力Server → Clientinitialize响应声明自己支持的原语Client → Servertools/list请求获取工具列表Server → Client返回工具 Schema 列表LLM 决定调用某工具后Client → Servertools/call请求带工具名和参数Server → Client返回执行结果下面是一个tools/list请求的 JSON-RPC 消息示例{ jsonrpc: 2.0, id: 1, method: tools/list, params: {} }对应的响应{ jsonrpc: 2.0, id: 1, result: { tools: [ { name: get_weather, description: 查询指定城市天气, inputSchema: { type: object, properties: { city: {type: string, description: 城市名} }, required: [city] } } ] } }五、手写一个 MCP Server下面用 Python 官方 SDKmcp包实现一个最小 MCP Server暴露两个工具查天气和算数学。这段代码可以直接跑。 最小 MCP Server 示例。 安装: pip install mcp 运行: python mcp_server_demo.py作为子进程被 Client 启动 from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent import mcp.server.stdio import json import asyncio app Server(demo-tools-server) # ---- 定义工具 ---- app.list_tools() async def list_tools() - list[Tool]: 声明 Server 提供的所有工具等价于 tools/list 响应。 return [ Tool( nameget_weather, description查询指定城市当天天气。当用户问天气、气温时调用。, inputSchema{ type: object, properties: { city: { type: string, description: 城市名如北京 } }, required: [city] } ), Tool( namecalculate, description执行数学计算表达式。, inputSchema{ type: object, properties: { expression: { type: string, description: 数学表达式如3*82 } }, required: [expression] } ) ] app.call_tool() async def call_tool(name: str, arguments: dict) - list[TextContent]: 执行被调用的工具等价于 tools/call 响应。 if name get_weather: city arguments.get(city, ) # 模拟天气数据实际接 API mock {北京: 晴 25°C, 上海: 多云 28°C, 深圳: 雷阵雨 30°C} result mock.get(city, f未找到{city}的天气) return [TextContent(typetext, textf{city}今天天气: {result})] elif name calculate: expr arguments.get(expression, ) try: # 注意生产环境不要用 eval这里仅演示 result eval(expr, {__builtins__: {}}, {}) return [TextContent(typetext, textf{expr} {result})] except Exception as e: return [TextContent(typetext, textf计算失败: {e})] else: return [TextContent(typetext, textf未知工具: {name})] async def main(): 通过 stdio 启动 Server。 async with stdio_server() as (read_stream, write_stream): await app.run(read_stream, write_stream, app.create_initialization_options()) if __name__ __main__: asyncio.run(main())代码要点解读app.list_tools()装饰器注册工具声明回调Client 发tools/list时触发返回工具 Schema 列表。app.call_tool()装饰器注册工具执行回调Client 发tools/call时触发按 name 路由到对应逻辑。stdio_server()用标准输入输出做传输Host 以子进程方式启动这个 Server通过管道收发 JSON-RPC 消息。返回值是TextContent列表——MCP 工具结果支持多种内容类型text、image、resource最常用的是 text。六、MCP Client 侧Host 怎么用Host 侧Client的工作是启动/连接 Server → 获取工具列表 → 把工具发给 LLM → LLM 决定调用时转发给 Server → 回填结果。下面是 Client 侧的核心逻辑伪代码示意流程 MCP Client 侧流程示意伪代码展示协议交互。 import asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def run_client(): # 1. 定义如何启动 Serverstdio 模式 server_params StdioServerParameters( commandpython, args[mcp_server_demo.py], ) # 2. 启动 Server 子进程并建立会话 async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: # 3. 初始化握手 await session.initialize() # 4. 获取工具列表 tools_result await session.list_tools() print(可用工具:, [t.name for t in tools_result.tools]) # 5. 把工具 Schema 转成 LLM 的 tools 格式 llm_tools [] for tool in tools_result.tools: llm_tools.append({ type: function, function: { name: tool.name, description: tool.description, parameters: tool.inputSchema, } }) # 6. 调用 LLM此处用伪代码 # user_msg 北京天气怎么样 # llm_response llm.chat(messages[...], toolsllm_tools) # if llm_response.tool_calls: # for tc in llm_response.tool_calls: # 7. 转发工具调用给 MCP Server result await session.call_tool(get_weather, {city: 北京}) print(工具结果:, result.content[0].text) # 8. 把 result 回填给 LLMLLM 生成最终回答 if __name__ __main__: asyncio.run(run_client())这段伪代码展示了 MCP 的完整数据流Client 拿到 Server 的工具列表后转成 LLM 能理解的格式发给模型模型决定调用工具时Client 通过session.call_tool转发给 ServerServer 执行后结果回到 Client再回填给 LLM。MCP 在这里扮演的就是标准化中间层。七、MCP vs Function Calling vs LangChain Tools面试常考三者的定位差异| 维度 | Function Calling | LangChain Tools | MCP | |---|---|---|---| | 本质 | 模型 API 能力 | 框架封装 | 开放协议标准 | | 工具定义 | 各家 API 私有格式 | Python 类装饰器 | JSON-RPC JSON Schema | | 运行位置 | 与 LLM 同进程 | 与 Agent 同进程 | 独立进程/远程 | | 跨语言 | 否绑定特定 API | 否绑定 Python | 是协议级跨语言 | | 工具复用 | 同 API 内复用 | 同项目内复用 | 全生态复用一次编写处处可用 | | 动态发现 | 不支持 | 不支持 | 支持运行时 list_tools | | 适用阶段 | 单模型快速接入 | LangChain 生态内 | 多工具、多客户端、跨平台 |一句话总结Function Calling 是模型层的能力LangChain Tools 是框架层的封装MCP 是协议层的标准。三者不互斥——MCP Server 暴露的工具最终在 Host 里还是通过 Function Calling 让 LLM 调用的MCP 只是标准化了工具怎么被发现和传输。八、面试高频追问与答题模板追问1MCP 解决了什么问题答M × N 集成碎片化问题。M 个 AI 应用 × N 个工具源每个组合都要写集成代码。MCP 引入标准协议中间层工具方写一次 Server、应用方写一次 Client通过 JSON-RPC 通信成本降为 M N。类比 USB-C 统一接口。追问2MCP 的 Tools 和 Resources 有什么区别答Tools 是可执行操作有副作用写文件、发消息、调 API等价于 POST 请求Resources 是可读数据幂等无副作用读文件、查数据库等价于 GET 请求。LLM 通过 Tools 做事通过 Resources 获取上下文。追问3MCP Server 怎么被发现的答两种模式。一是静态配置Host 配置文件里写明 Server 启动命令或 URL二是动态发现SSE 模式下 Server 注册到注册中心Client 查询发现。目前主流是静态配置动态发现仍在发展中。追问4MCP 的安全性怎么保证答三层。传输层stdio 本地隔离或 SSE 加 TLS权限层Server 可声明工具需要的权限Client 授权后才调用执行层Server 在自己进程内执行可加沙箱。敏感操作删文件、转账应加用户确认环节。MCP 规范本身没有定义完整的权限模型目前靠实现方自律。追问5为什么不用 OpenAPI/Swagger 而要搞 MCP答OpenAPI 是给人调 API设计的描述 HTTP 端点MCP 是给LLM 调工具设计的描述工具语义、支持动态发现和双向通信Server 可以主动推送资源更新。OpenAPI 缺少 LLM 需要的工具语义描述什么时候该用这个工具MCP 的 description 字段正是为此设计。九、MCP 生态现状与工程建议截至 2026 年MCP 生态快速扩张。Anthropic 官方维护了一批参考 Serverfilesystem、github、slack、postgres 等社区贡献了数百个第三方 Server。Claude Desktop、Cursor、Zed 等已原生支持 MCP Client。工程落地建议工具少5个、单应用直接 Function Calling 够用上 MCP 是过度设计。工具多、要多应用复用上 MCP写一次 Server 多个 Host 通用。跨语言团队MCP 协议级跨语言Python Server 配 TS Client 没问题。远程部署用 SSE 模式Server 独立部署多 Client 共享。安全生产环境务必加权限校验和操作确认MCP 规范不强制安全模型。MCP 的价值在于标准化——它不引入新的模型能力而是让工具生态从私有花园走向开放市场。对 Agent 工程师来说理解 MCP 的协议设计和实现方式是 2026 年面试的必备项。下一篇我们进入 Agent 的规划与任务分解讲 Plan-Execute 范式。

相关新闻