当前位置: 首页 > news >正文

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

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

Model Context Protocol(MCP)是 Anthropic 在 2024 年底开源的一套标准协议,目标是解决"每个 AI 应用都要自己接一遍工具"的碎片化问题。你可以把它理解成"AI 工具调用的 USB-C 接口"——定义了一套统一的客户端-服务端协议,任何 MCP Server 暴露的工具/资源,都能被任何 MCP Client(Claude Desktop、Cursor、自研 Agent)直接使用。面试官考 Agent 岗,MCP 已经成了 2026 年的高频题,这篇文章把它的架构、协议、实现拆透,配可运行代码。

一、为什么需要 MCP:M × 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 暴露若干工具和资源。Host(LLM)看到的是所有已连接 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 声明工具的 Schema,Client(Host)把它发给 LLM,LLM 决定调用时,Client 通过协议把调用请求转发给 Server 执行,结果返回给 LLM。

Resources让 Server 暴露可读数据,比如文件系统 Server 暴露file:///path/to/file资源,Client 可以按需读取。与 Tools 的区别:Resources 是"读取"(幂等、无副作用),Tools 是"执行"(可能有副作用)。

Prompts是预定义的提示词模板,用户在 Host 里选一个 Prompt,Server 填充参数后返回完整提示词给 LLM。适用于标准化工作流。

四、JSON-RPC 2.0:MCP 的传输协议

MCP 用 JSON-RPC 2.0 做消息格式。核心消息类型:

| 消息类型 | 方向 | 用途 | |---|---|---| | Request | 双向 | 请求(带 id,期待响应) | | Response | 双向 | 对 Request 的响应 | | Notification | 双向 | 通知(不带 id,不期待响应) |

一个典型的 MCP 交互流程:

  1. Client → Server:initialize请求(协商协议版本、能力)
  2. Server → Client:initialize响应(声明自己支持的原语)
  3. Client → Server:tools/list请求(获取工具列表)
  4. Server → Client:返回工具 Schema 列表
  5. (LLM 决定调用某工具后)
  6. Client → Server:tools/call请求(带工具名和参数)
  7. 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 官方 SDK(mcp包)实现一个最小 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( name="get_weather", description="查询指定城市当天天气。当用户问天气、气温时调用。", inputSchema={ "type": "object", "properties": { "city": { "type": "string", "description": "城市名,如'北京'" } }, "required": ["city"] } ), Tool( name="calculate", description="执行数学计算表达式。", inputSchema={ "type": "object", "properties": { "expression": { "type": "string", "description": "数学表达式,如'3*8+2'" } }, "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(type="text", text=f"{city}今天天气: {result}")] elif name == "calculate": expr = arguments.get("expression", "") try: # 注意:生产环境不要用 eval,这里仅演示 result = eval(expr, {"__builtins__": {}}, {}) return [TextContent(type="text", text=f"{expr} = {result}")] except Exception as e: return [TextContent(type="text", text=f"计算失败: {e}")] else: return [TextContent(type="text", text=f"未知工具: {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())

代码要点解读:

  1. @app.list_tools()装饰器注册工具声明回调,Client 发tools/list时触发,返回工具 Schema 列表。
  2. @app.call_tool()装饰器注册工具执行回调,Client 发tools/call时触发,按 name 路由到对应逻辑。
  3. stdio_server()用标准输入输出做传输,Host 以子进程方式启动这个 Server,通过管道收发 JSON-RPC 消息。
  4. 返回值是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. 定义如何启动 Server(stdio 模式) server_params = StdioServerParameters( command="python", 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=[...], tools=llm_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 回填给 LLM,LLM 生成最终回答 if __name__ == "__main__": asyncio.run(run_client())

这段伪代码展示了 MCP 的完整数据流:Client 拿到 Server 的工具列表后,转成 LLM 能理解的格式发给模型;模型决定调用工具时,Client 通过session.call_tool转发给 Server;Server 执行后结果回到 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 只是标准化了"工具怎么被发现和传输"。

八、面试高频追问与答题模板

追问1:MCP 解决了什么问题?答:M × N 集成碎片化问题。M 个 AI 应用 × N 个工具源,每个组合都要写集成代码。MCP 引入标准协议中间层,工具方写一次 Server、应用方写一次 Client,通过 JSON-RPC 通信,成本降为 M + N。类比 USB-C 统一接口。

追问2:MCP 的 Tools 和 Resources 有什么区别?答:Tools 是"可执行操作",有副作用(写文件、发消息、调 API),等价于 POST 请求;Resources 是"可读数据",幂等无副作用(读文件、查数据库),等价于 GET 请求。LLM 通过 Tools 做事,通过 Resources 获取上下文。

追问3:MCP Server 怎么被发现的?答:两种模式。一是静态配置(Host 配置文件里写明 Server 启动命令或 URL);二是动态发现(SSE 模式下 Server 注册到注册中心,Client 查询发现)。目前主流是静态配置,动态发现仍在发展中。

追问4:MCP 的安全性怎么保证?答:三层。传输层: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 官方维护了一批参考 Server(filesystem、github、slack、postgres 等),社区贡献了数百个第三方 Server。Claude Desktop、Cursor、Zed 等已原生支持 MCP Client。

工程落地建议:

  1. 工具少(<5个)、单应用:直接 Function Calling 够用,上 MCP 是过度设计。
  2. 工具多、要多应用复用:上 MCP,写一次 Server 多个 Host 通用。
  3. 跨语言团队:MCP 协议级跨语言,Python Server 配 TS Client 没问题。
  4. 远程部署:用 SSE 模式,Server 独立部署,多 Client 共享。
  5. 安全:生产环境务必加权限校验和操作确认,MCP 规范不强制安全模型。

MCP 的价值在于"标准化"——它不引入新的模型能力,而是让工具生态从"私有花园"走向"开放市场"。对 Agent 工程师来说,理解 MCP 的协议设计和实现方式,是 2026 年面试的必备项。下一篇我们进入 Agent 的规划与任务分解,讲 Plan-Execute 范式。

http://www.jsqmd.com/news/1271376/

相关文章:

  • AI开发中的跨学科思维:从哲学到工程实践
  • 模型融合技术:原理、方法与实践指南
  • Java+AI构建智能日志分析系统实战
  • AI公司技术团队建设:从初创到成熟期的架构演进与人员管理
  • LangChain框架实战:构建RAG知识库与智能体开发
  • C++11核心特性解析:从自动类型推导到移动语义的现代编程实践
  • 美国教育机构AI使用分级制度:从禁止到引导的学术诚信新框架
  • 嵌入式以太网Mini-Driver开发:从API到DMA的实战解析
  • Wand-Enhancer:本地化WeMod客户端增强方案的技术实现与应用
  • Ollama大模型部署与管理实战指南
  • 智能仓储翻箱优化:基于强化学习的预翻箱策略
  • TI DSP仿真器JTAG连接故障排查:从原理到示波器诊断全解析
  • C++访问说明符:从语法到工程实践,构建安全可维护的代码
  • C++学习路径全解析:从基础语法到项目实战的进阶指南
  • Seedance2.0:多模态AI如何革新视频创作
  • Java实现RSA文件加密工具:从非对称加密原理到桌面应用开发
  • HLQFP封装PCB设计实战:从焊盘布局、钢网优化到散热管理的全流程解析
  • GSE宏编译器:魔兽世界智能技能编排完全指南
  • 微软C++算法面试核心:从解题到工程级代码的实战指南
  • TMS320DM6467T DSP内存映射与缓存架构深度解析与实战配置
  • AI编程助手如何重塑开发者打字能力与工作流效率
  • 7 月 AI CLI 工具开发总结:从 idea 到可用的 31 天全记录与关键决策
  • Linux中断机制:原理、优化与实战调试技巧
  • Claude-5代码生成模型:业务逻辑理解与工程化实践指南
  • Turnitin AI检测技术原理与学术查重实战指南
  • 深入解析MMC/SD/SDIO的DMA与命令流协同工作原理
  • 2026年上海虾塘防渗膜行业知名销售联络方式解析与推荐 - 装修教育财税推荐2026
  • 家居设备配网流程的交互优化:从扫描到连接的每一步微交互
  • TMS320C665x DSP引导配置详解:从硬件引脚到参数表实战
  • KYC完全解读:从合规门槛到信任基石