十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MCP协议实战:从零搭建AI Agent统一工具链

MCP协议实战:从零搭建AI Agent统一工具链 1. 项目概述与核心思路聊 MCP 之前先说个我最近的真实感受。以前给 AI Agent 接工具每个工具都得单独写适配调一个 API 写一段函数换一个 Agent 框架又得重写一遍。攒了十几个工具之后维护成本直接爆炸。后来我把整套工具链统一到 MCPModel Context Protocol上所有工具都以 MCP Server 的形式暴露AI Agent 这边只需要一套协议就能发现工具、调用工具、拿结果。这篇文章就是我从零搭建这套 AI Agent 工具链的完整记录包括协议原理、核心代码、接入方式和踩坑实录。MCP 本质上是 Anthropic 在 2024 年底开源的一个开放协议核心目标是把“AI 模型和外部工具之间的交互方式”标准化。你可以把它理解成 AI 世界的 USB-C 接口以前每个设备都要专属充电线现在统一成一个接口只要工具实现了 MCP Server任何支持 MCP 的 Agent 客户端都能直接使用。我这次搭建的“笔记工具链”就是一个最小可复现的例子读完你就能自己写一个 MCP Server并接入 Claude Desktop、Cursor 这类客户端。这篇文章适合几类人想入门 MCP 开发但不知道从哪下手的后端工程师正在做 AI Agent 落地但被工具适配折磨的技术负责人以及想把本地已有服务REST API、数据库、脚本快速暴露给 AI 使用的开发者。如果你只是听说过 MCP 想弄懂它是什么我的建议是从第 2 节开始读如果你已经知道基础概念可以直接跳到第 4 节看代码。2. MCP 协议基础与核心概念2.1 MCP 不是 API是协议很多人第一次接触 MCP 会把它当成“封装好的 API 接口”这个理解不够准确。API 描述的是一个服务能提供哪些具体功能而 MCP 描述的是“客户端和服务端之间如何对话”的标准。MCP 定义了你如何发现工具、如何描述工具参数、如何传递调用结果但完全不限制工具内部实现。同一个 MCP Server后端可以是一个 Python 脚本可以是一套 Spring Boot 服务也可以是一个调用外部 HTTP API 的转发层。在 MCP 的术语里有三个角色MCP Host运行 AI Agent 的主进程比如 Claude Desktop、Cursor、或者你自己写的 Agent 程序。Host 负责理解用户意图决定什么时候调用工具。MCP ClientHost 内部负责与 Server 建立连接、收发消息的组件。一个 Host 可以同时连接多个 Server。MCP Server暴露工具、资源或提示词的服务端。它只负责被调用不需要关心上层 Agent 是怎么做决策的。一个核心的感知是MCP Server 不主动发起调用它就像一个坐在工位上等需求的人Agent 来问“你有什么能力”它回答“我有这几个工具”Agent 又说“帮我执行第 2 个”它就去干活然后把结果交回去。这个一问一答的过程底层跑的是 JSON-RPC 2.0 协议。2.2 三种核心原语Tools、Resources、PromptsMCP 设计了三个能力维度简单理解就是让 AI 能干活的、能看东西的、能套模板的。原语作用类比典型用途Tools让 Agent 执行一个动作有输入和输出手和工具查天气、写文件、调 API、执行命令Resources给 Agent 提供可读取的数据内容资料库读取项目文档、加载配置文件、查询数据库记录Prompts预置的提示词模板引导 Agent 完成任务工作手册让 Agent 按固定格式生成周报、代码审查结论我这次实现的核心是 Tools。它在协议层的调用过程是客户端先发tools/list请求服务端返回工具名和参数定义JSON Schema模型根据这些定义决定要不要调用工具如果要调用客户端发tools/call请求服务端执行并返回结构化结果。这里有个特别容易忽略的点工具的 description 不只是给人看的它是给模型的。模型不会读你的代码它只能通过你写的描述来判断这个工具该不该用。描述写得模糊模型就会经常用错或者干脆不用。2.3 传输方式stdio 与 HTTPMCP 支持两种主流传输方式stdio 和 HTTP。stdio标准输入输出是最常见的本地传输方式。客户端启动一个子进程通过标准输入输出和 MCP Server 通信。优点是不用管端口、不用管鉴权适合本地开发工具比如文件操作、代码生成、笔记检索。缺点也很明显进程生命周期绑定在客户端上不太适合远程调用。HTTP通过 HTTP SSE现在更推荐 Streamable HTTP适合部署在服务器上的 MCP Server。远程工具、共享工具、多用户场景都走这条路。HTTP 模式下要考虑身份认证、限流、超时等问题复杂度明显比 stdio 高。我的建议是第一版先用 stdio 做通把协议逻辑跑顺了再考虑 HTTP。因为 stdio 模式能帮你排除很多网络层面的干扰变量让你专注于工具本身的逻辑。3. 工具链整体架构与组件选型3.1 整体架构我搭建的这套工具链目标是把“本地笔记检索”“待办事项管理”“外部 REST API 查询”“文件摘要生成”这四类能力统一暴露给 AI Agent。架构上分三层应用层Claude Desktop 和 Cursor 作为 MCP Host负责理解用户问题、编排调用顺序。协议层各 MCP Server 统一通过 stdio 与 Host 通信使用官方 SDK 或 FastMCP 封装层。能力层底层是本地 SQLite 数据库、文件系统、第三方 HTTP API。这种分层有个明显的好处如果你换一个 Host比如从 Claude Desktop 换到基于 LangGraph 自己搭的 Agent只需要配置相应的 MCP Client 地址工具代码一行都不用改。我自己实际迁移过一次成本几乎为零这就是协议标准化的价值。3.2 组件选型MCP 官方提供了 TypeScript、Python、Java、Go 等多语言 SDK。我的选型原则很简单本地工具和快速原型用 Python FastMCP代码量最少可读性最好。企业内部服务用 Java Spring AI MCP Server方便和现有 Spring Boot 技术栈整合。需要跨语言、跨平台复用用 TypeScript SDK在 Node 生态下内存占用和启动速度更均衡。另外补充一个热词对比“Agent Skill 和 MCP 有什么区别”。我自己的理解是Skill 更接近“行为封装”它定义的是 Agent 在面对某类任务时的动作流程和提示词策略MCP 更接近“能力暴露”它定义的是外部工具怎么被 Agent 发现和调用。两者不是非此即彼的关系而是互补。实际项目中我会用 Skill 组织复杂的多步策略用 MCP 统一底层工具调用分工很清晰。4. 从零实现一个 MCP Server4.1 环境准备与项目结构写一个 MCP Server 的难度远比你想象的低。只要你有 Python 基础半小时内就能跑通。我的开发环境是Python 3.11MCP Python SDK 1.2Claude Desktop 或 Cursor用于配置接入一个文本编辑器项目目录结构如下mcp-demo/ ├── server.py ├── requirements.txt ├── data/ │ └── notes.db └── README.md安装依赖只需要一个命令pip install mcp[cli] httpxmcp[cli]会安装完整 SDK 和命令行调试工具httpx是为了后面演示 HTTP 调用用的。4.2 用 FastMCP 实现笔记检索工具FastMCP 是官方 SDK 里提供的高阶封装它把底层的 JSON-RPC 通信、初始化握手、工具注册全包掉了你只需要写业务函数加装饰器。这是我第一版server.py的核心代码from mcp.server.fastmcp import FastMCP from typing import Optional mcp FastMCP(note-tool) # 模拟本地笔记库实际项目中可替换为 SQLite/ES NOTES_DB [ { id: 1, title: MCP 协议笔记, content: Model Context Protocol用于标准化 AI 与外部工具的交互。, tags: [ai, protocol], created_at: 2025-05-01, }, { id: 2, title: AI Agent 工具链设计, content: 工具链包含 Host、Client、Server 三层各层职责解耦。, tags: [agent, toolchain], created_at: 2025-05-03, }, ] mcp.tool() def search_notes(keyword: str, limit: int 5) - list[dict]: 根据关键字搜索本地笔记标题和内容返回匹配的笔记列表。 Args: keyword: 要搜索的关键字。 limit: 最多返回的笔记数量默认 5 条。 keyword_lower keyword.lower() result [ note for note in NOTES_DB if keyword_lower in note[title].lower() or keyword_lower in note[content].lower() ] return result[:limit] mcp.tool() def get_note_by_id(note_id: int) - Optional[dict]: 根据笔记 ID 获取详情。 Args: note_id: 笔记的唯一 ID。 for note in NOTES_DB: if note[id] note_id: return note return None if __name__ __main__: mcp.run(transportstdio)这段代码里的mcp.tool()是核心FastMCP 会根据函数签名自动生成 JSON Schema并且把函数的 docstring 作为工具描述传给大模型。所以 docstring 写得好不好直接决定模型会不会正确使用这个工具。启动服务python server.py启动后进程会等待 stdin 输入看起来像卡住了这是正常的。想快速验证是否正确可以用 MCP Inspector这是官方提供的可视化调试工具npx modelcontextprotocol/inspector python server.py打开 Inspector 后先点击 Connect然后切到 Tools 标签页能看到search_notes和get_note_by_id两个工具下方会显示自动解析出来的参数 JSON Schema。你可以直接在这里测试调用返回结果会以 JSON 形式展示。这一步强烈建议第一次写 MCP Server 的人做一遍能帮你直观理解“客户端通过 tools/list 发现工具通过 tools/call 调用工具”这个流程。4.3 接入 Agent 客户端服务端写好后把它接入 Claude Desktop。这里需要找到客户端的配置文件。macOS 上 Claude Desktop 的配置文件路径是~/Library/Application Support/Claude/claude_desktop_config.jsonWindows 上通常在%APPDATA%\Claude\claude_desktop_config.json在这个文件里添加{ mcpServers: { note-tool: { command: python, args: [/你的绝对路径/mcp-demo/server.py] } } }配置完成后重启 Claude Desktop。在对话输入框下方如果能看到一个工具图标或者直接问一句“帮我搜索一下笔记里包含 protocol 的内容”它如果正确调用了工具就说明接入成功了。接入 Cursor 的方式类似。在项目根目录创建或编辑.cursor/mcp.json{ mcpServers: { note-tool: { command: python, args: [/你的绝对路径/mcp-demo/server.py] } } }然后在 Cursor 设置里的 MCP 面板点刷新状态变成绿色就说明连接正常。这里有一个我踩过的坑配置里的 command 如果写成python在某些虚拟环境下可能指向错误的解释器。更稳妥的做法是先运行which python拿到绝对路径再填进去。如果你用uv管理 Python 环境也可以把 command 改成uvargs 改成run server.py这样能自动锁定项目依赖。5. 已有服务接入 MCP 的工程化改造5.1 REST API 转 MCP Server实际项目里你手头大概率已经有一堆 REST API 了不可能为了接 MCP 全部重写。正确的思路是写一个薄的 MCP 转发层把已有的 HTTP 接口包成工具。下面这个例子演示了如何把一个“查询待办事项”的 REST API 包装成 MCP 工具import httpx from mcp.server.fastmcp import FastMCP mcp FastMCP(todo-bridge) API_BASE https://api.example.com mcp.tool() def fetch_todo(todo_id: int) - dict | None: 根据 ID 获取待办事项详情。 Args: todo_id: 待办事项的 ID。 resp httpx.get( f{API_BASE}/todos/{todo_id}, timeout10, headers{Authorization: Bearer ${TODO_API_TOKEN}}, ) if resp.status_code 404: return None resp.raise_for_status() return resp.json() mcp.tool() def list_todos(status: str all, limit: int 20) - list[dict]: 获取待办事项列表可按状态过滤。 Args: status: 过滤状态可选 pending / completed / all。 limit: 返回条数默认 20。 params {limit: limit} if status ! all: params[status] status resp httpx.get(f{API_BASE}/todos, paramsparams, timeout10) resp.raise_for_status() return resp.json() if __name__ __main__: mcp.run(transportstdio)这个“薄转发层”的价值在于下游 API 怎么变、鉴权怎么做、数据怎么格式化Agent 完全不需要关心。它只需要知道“我调用 fetch_todo传一个 id就能拿到结构化的待办数据”。但转发层不是无脑转发。我做了三层额外处理超时控制每个外部 API 请求都设置 timeout避免工具调用把 Agent 的整个推理流程卡死。错误降级404 返回 None网络异常抛出明确错误信息让 Agent 能理解“这个工具暂时不可用”而不是拿到一团堆栈。返回结构裁剪API 原始返回可能很大我在转发层只保留 Agent 真正需要的字段防止上下文窗口被无关数据塞爆。5.2 Java 技术栈怎么接如果你的团队主力是 Java同样有正规方案。官方提供了spring-ai-starter-mcp-serverSpring AI 项目里可以直接暴露基于注解的 MCP 工具。假设你有一个用户服务想暴露一个“查询用户积分”的工具Component public class UserMcpTools { private final UserService userService; public UserMcpTools(UserService userService) { this.userService userService; } Tool(description 根据用户ID查询当前积分余额) public String getUserPoints( ToolParam(description 用户ID) Long userId) { return String.valueOf(userService.getPoints(userId)); } }然后在application.properties里配置spring.ai.mcp.server.nameuser-server spring.ai.mcp.server.version1.0.0引入依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server/artifactId /dependency启动项目后Spring AI 会自动把这些带Tool注解的方法注册成 MCP Tools默认走 stdio。如果你需要暴露成 HTTP 形式Spring AI 也支持 Streamable HTTP 传输让远程 Agent 客户端通过 URL 直接调用。我用 Java 这套方案接过一次企业内部的工单系统最大的体会是Spring AI MCP 的注解写法和 Spring MVC 的 Controller 很像后端同学学习成本极低基本上看一下示例代码就能上手。如果你的部门已经熟悉 Spring Boot走这条路比引入一套新语言运行时更顺畅。6. 常用生态工具链盘点6.1 设计、三维和本地数据MCP 的价值离不开生态。最近半年各领域的工具都在往 MCP 上靠我整理了几类比较有代表性的设计协作Figma 官方推出了 MCP ServerAI Agent 可以直接读取设计稿的文件名、页面结构、图层信息前端工程师可以让 Agent 基于设计稿生成代码。获取凭证的地方在 Figma 的 Personal Access Token 设置里配置好之后 Cursor 里就能直接引用设计稿资源。蓝湖 MCP国内设计协作平台蓝湖也做了 MCP 适配主要用于设计稿标注信息的读取和交付对国内做前端开发的人比较友好。三维建模Blender MCP 支持通过自然语言控制 Blender 执行建模、材质修改、场景操作。我自己试过让 Agent 在 Blender 里批量生成简单几何体很直观地感受到“自然语言操作专业软件”这个方向是真的能落地。本地数据像通达信这类股票软件也有开发者把本地数据封装成 MCP Server让 Agent 查询行情或交易数据。注意这类工具的最终输出只能作为辅助参考不能替代专业分析项目里接入时要做好提示词约束。这些生态工具的核心逻辑都是一样的把原来只能“人手动操作”的软件能力变成“AI 可发现、可调用”的结构化接口。换句话说MCP 正在成为连接大模型和存量软件之间的高速路。6.2 工作流与安全测试工具除了设计类还有两类 MCP 工具我觉得特别值得关注。一类是工作流自动化平台比如 n8n 已经支持在 workflow 里调用 AI Agent并且可以连接外部 MCP Server。这意味着你可以在低代码平台上拖出一个展示 Agent 能力的节点再把 MCP 工具当作节点能力接入。对没有专职 AI 工程师的团队来说这是把 AI Agent 落地到业务流程的一条捷径。另一类是安全测试工具。像 Burpsuite、Yakit 这类工具都有开发者提供了 MCP 适配让 AI Agent 能辅助分析 HTTP 请求、提取接口信息、生成安全测试用例。这类 MCP Server 本质上是把安全工具的专业能力图形化和协议化让 Agent 可以理解工具返回的数据并辅助决策。不过提醒一句这类工具生产能力很强使用范围一定要限定在自己的授权测试环境里不要在未授权目标上使用。7. 常见问题与排查技巧实录7.1 STDIO 启动失败这是新手遇到最多的问题。配置好 MCP Server 后客户端显示连接失败。排查步骤我总结成一套顺序先直接在终端手动执行命令比如python /你的路径/server.py看有没有报错。MCP Server 正常启动时不会有标准输出只会等待 stdin如果你一执行就立刻输出了一大段异常那就先把依赖装好、语法改对。检查command是否指向了正确的解释器。特别是在 Windows 环境建议用where python拿到完整路径后再填。确认配置文件是合法 JSON。很多时候失败原因是配置里多了个逗号或者路径反斜杠没转义。看客户端日志。Claude Desktop 的日志一般在~/Library/Logs/Claude/下Cursor 的 MCP 面板会直接显示错误信息。7.2 工具“该用不用”或者“用错参数”工具暴露成功了但 Agent 就是不调用或者调用时传错参数。这个问题的根源通常是工具描述和参数名对模型不够友好。比如你把工具命名为fn1参数叫p1没有 docstring模型大概率不知道什么时候该用它。正确的做法是工具名用动词开头的清晰命名比如search_notes、get_user_points。参数名要语义化不要用param1。docstring 里写清楚适用场景、返回值格式、特殊边界条件。参数限制写在描述里比如“最多返回 5 条”。7.3 安全边界这是我在生产环境接入 MCP 时最重视的一点。MCP 把工具暴露给 AI本质上是把一部分控制权交给了模型。模型有幻觉、有误判所以必须在工具层面设好安全护栏。我的几条经验所有工具输入都必须做参数校验尤其要校验路径、ID、命令这类能影响系统状态的参数。敏感操作删除、写入、转账、执行命令要加二次确认机制不要让 Agent 一键完成不可逆操作。远程 MCP Server 必须做鉴权建议用短期令牌而不是长期密钥。给工具返回结果加长度上限防止单个工具返回几百 MB 数据把 Agent 上下文打爆。7.4 工具返回内容导致上下文爆掉我踩过最实际的坑是一个查数据库的工具把整张表全量返回给 Agent导致上下文窗口直接被撑爆。解决方案是在工具内部做字段裁剪 分页工具返回的字段要按需裁剪别把所有数据库列都返回。增加limit、offset参数让 Agent 分批拿数据。对于大文本可以返回摘要而非全文Agent 需要时再通过另一个工具拿详情。这个思路和设计 REST API 时的“列表接口不返回全文”是完全一致的。工具设计得越接近良好的工程实践AI Agent 的表现就越稳定。8. 最后再分享一点个人体会整套工具链跑通之后我最大的感受是MCP 真正解决了 AI Agent 落地过程中的“集成碎片化”问题。以前给 Agent 加一个新工具要写适配代码、要处理协议差异、要照顾不同框架的兼容性现在只需要写一个 MCP Server所有支持 MCP 的客户端都能用。这种“一次开发、到处复用”的体验对做基础设施的人来说非常舒适。如果让我给刚开始做的人一个建议不要一上来就追求复杂的架构先用 FastMCP 写一个只有一个工具的小服务在 Inspector 里跑通再接入 Cursor 让它帮你完成一个真实任务。跑通这个闭环之后你对 MCP 的理解会比看十篇文档都深。后续想扩展再把 HTTP 传输、鉴权、OAuth、多 Server 编排这些能力一层层加进去。工具链这件事最难的不是技术而是把每一步都走扎实。
返回列表