news 2026/8/6 12:15:37

MCP 协议实战:让 AI Agent 真正连上你的业务系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MCP 协议实战:让 AI Agent 真正连上你的业务系统

MCP 协议实战:让 AI Agent 真正连上你的业务系统

MCP 正在成为 AI Agent 接入外部工具的"HTTP 时刻"。但读文档和实际落地之间,隔着一个真实的业务系统。

背景

上个月给出海电商团队搭一个运营数据 Agent,需求很朴素:自然语言查订单、分析 SKU 周转、对比各站点 GMV。

传统做法是写个 RAG + SQL Generator,Prompt 里拼一堆 Schema 让 LLM 猜怎么查。但有两个根本问题:

  1. Schema 膨胀:出海业务跨多国多站点,表结构随站点定制,Prompt 塞不下
  2. 安全风险:让 LLM 直接拼 SQL,白名单纯靠 Prompt 约束 = 防君子不防小人

我需要一种方式,让 Agent 像调用 HTTP API 一样调内部服务 ——MCP (Model Context Protocol)恰好是这个抽象。

插一句:这让我想起早期门户时代的「频道模板系统」。CMS 后台给编辑一个结构化表单,编辑填参数不用碰 HTML。MCP 对 Agent 做的事本质上一样 —— 给 LLM 一个结构化的工具契约,让它不用碰底层实现。

技术方案

MCP 是什么(两句话说清楚)

MCP 是 Anthropic 提出的开放协议,定义了两个角色:

  • MCP Server:暴露 Tools / Resources / Prompts 的服务端
  • MCP Client:调用这些能力的一方(通常是 AI Agent Host,如 Claude Desktop、Cursor、自建 Agent)

通信走 JSON-RPC 2.0,支持stdioServer-Sent Events (SSE)两种传输。对业务系统集成来说,SSE 是最实用的方案 —— 不需要 Agent 和 Server 在同一台机器上。

架构设计

┌──────────────┐ SSE(HTTP) ┌──────────────┐ gRPC ┌──────────────┐ │ AI Agent │ ◄──────────────► │ MCP Server │ ◄──────────► │ 业务服务 │ │ (Claude/自建) │ │ (Node.js) │ │ (订单/BI等) │ └──────────────┘ └──────────────┘ └──────────────┘

MCP Server 充当"翻译层":把 Agent 的工具调用请求翻译成内部 RPC,把返回结果格式化成 Tool Result。

选型理由:

  • 不用改现有服务:MCP Server 作为独立 Sidecar 部署,业务服务零侵入
  • SSE 模式天然支持跨机器:Agent 在云端,MCP Server 在内网,过一层 API Gateway 就行
  • TypeScript 生态@modelcontextprotocol/sdk官方 SDK,和现有 Node 技术栈匹配

实施步骤

Step 1:创建 MCP Server 项目

mkdir order-mcp-server && cd order-mcp-server npm init -y npm install @modelcontextprotocol/sdk express cors npm install -D typescript @types/node tsx

Step 2:定义 Tool 清单

按业务需求定义了 3 个 Tool:

// tools/schema.ts export const TOOLS: ToolDefinition[] = [ { name: "query_orders", description: "按站点、日期范围、订单状态查询订单列表", parameters: { type: "object", properties: { site: { type: "string", enum: ["US", "SEA", "ME", "LATAM"], description: "站点代码" }, startDate: { type: "string", description: "开始日期,格式 YYYY-MM-DD" }, endDate: { type: "string", description: "结束日期,格式 YYYY-MM-DD" }, status: { type: "string", enum: ["PENDING", "SHIPPED", "DELIVERED", "CANCELED"] }, limit: { type: "number", default: 20 } }, required: ["site", "startDate", "endDate"] } }, { name: "get_sku_metrics", description: "查询 SKU 的周转天数、库存深度、近 30 天销量", parameters: { type: "object", properties: { skuCode: { type: "string", description: "SKU 编码" }, site: { type: "string", enum: ["US", "SEA", "ME", "LATAM"] } }, required: ["skuCode", "site"] } }, { name: "compare_gmv", description: "对比多个站点的 GMV,支持同比/环比", parameters: { type: "object", properties: { sites: { type: "array", items: { type: "string" }, description: "站点列表" }, compareType: { type: "string", enum: ["yoy", "mom"], description: "同比/环比" } }, required: ["sites"] } } ];

注意:Tool 的description就是 Agent 的"API 文档"。写得越精确,Agent 调用越准确。这里踩过一个坑 —— 最早compare_gmv没限制sites数组长度,Agent 一次传 12 个站点,后端 SQL 直接超时。

Step 3:实现 SSE MCP Server

// server.ts import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import express from "express"; import { TOOLS } from "./tools/schema"; import { OrderService } from "./services/order"; const app = express(); const transportMap = new Map<string, SSEServerTransport>(); // SSE endpoint — 建立长连接 app.get("/sse", async (req, res) => { const transport = new SSEServerTransport("/messages", res); const mcpServer = new McpServer({ name: "order-mcp-server", version: "1.0.0" }); // 注册 Tools for (const tool of TOOLS) { mcpServer.tool( tool.name, tool.description, tool.parameters, async (args: any) => { return await OrderService.handleToolCall(tool.name, args); } ); } transportMap.set(transport.sessionId, transport); await mcpServer.connect(transport); res.on("close", () => transportMap.delete(transport.sessionId)); }); // POST endpoint — 接收 JSON-RPC 消息 app.post("/messages", express.json(), async (req, res) => { const sessionId = req.query.sessionId as string; const transport = transportMap.get(sessionId); if (!transport) { res.status(404).end(); return; } await transport.handlePostMessage(req, res); }); app.listen(3001, () => console.log("MCP Server running on :3001"));

关键点:SSE 模式下需要维护sessionId → transport映射。每次请求带sessionIdquery param 来路由到正确的长连接。

Step 4:在 Agent 侧配置 MCP Client

以 Claude Desktop 为例,编辑claude_desktop_config.json

{ "mcpServers": { "order-service": { "url": "https://internal-api.your-company.com/mcp/sse", "headers": { "Authorization": "Bearer <your-api-token>" } } } }

自建 Agent(WorkBuddy 等)则需要在 Agent 侧实现 MCP Client 的 SSE transport。SDK 提供了标准客户端,接入代码如下:

import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; const transport = new SSEClientTransport( new URL("https://internal-api/mcp/sse") ); const client = new Client({ name: "my-agent", version: "1.0.0" }); await client.connect(transport); // 获取可用工具列表 const tools = await client.listTools(); // 调工具 const result = await client.callTool({ name: "compare_gmv", arguments: { sites: ["US", "SEA"], compareType: "mom" } });

踩坑记录

坑 1:SSE 重连风暴

现象:Agent 掉线后重连,短时间内创建了 200+ 个 SSE 连接,服务 OOM。

根因:Claude Desktop 的重连退避算法默认最大值太小(30s),突发重连时瞬间打满连接池。

解决

  • Server 侧加maxConnectionsPerClient限制(我们设 5)
  • 旧连接加 60s TTL,超时主动断
  • Agent 侧reconnect.backoff调到最大 120s
// 连接数限制 const MAX_PER_CLIENT = 5; const clientConnectionCount = new Map<string, number>(); app.get("/sse", (req, res) => { const clientId = req.headers["x-client-id"] as string || req.ip; const count = clientConnectionCount.get(clientId) || 0; if (count >= MAX_PER_CLIENT) { res.status(429).json({ error: "Too many connections" }); return; } clientConnectionCount.set(clientId, count + 1); res.on("close", () => { const c = clientConnectionCount.get(clientId) || 1; clientConnectionCount.set(clientId, Math.max(0, c - 1)); }); // ... rest of handler });

坑 2:Tool Result 太大导致上下文爆炸

现象query_orders一次返回 500 条订单,每条含完整地址、物流轨迹、备注。Agent 收到后 Token 直接飙到上限,后续对话全丢。

解决

  • Tool 返回做摘要化:只返回关键字段,列表类结果限制行数
  • 大量数据走Resource 模式而非 Tool Result。Agent 拿到 Resource URI 后按需读取
// Tool 返回精简版,附带 Resource URI async function queryOrders(args: QueryOrdersArgs) { const orders = await OrderService.query(args); return { content: [{ type: "text", text: JSON.stringify({ total: orders.total, summary: orders.items.slice(0, 20).map(o => ({ id: o.id, site: o.site, status: o.status, amount: o.amount, createdAt: o.createdAt })), _more: `mcp-resource://orders/detail?ids=${orders.itemIds.join(',')}` }) }] }; }

坑 3:认证 token 泄露到 LLM

现象:有一天翻 Agent 日志,发现一次 Tool 调用的错误信息里包含了服务端返回的Authorization header expired: Bearer sk-xxx...。这个信息构成了 LLM 的上下文,如果后续对话持续,token 有概率被泄露。

解决:MCP Server 层的错误信息做脱敏处理,不透露任何 credential/token/secrets:

async function handleToolCall(toolName: string, args: any) { try { return await callInternalService(toolName, args); } catch (err: any) { // 永远不要让原始错误信息进入 Agent 上下文 return { isError: true, content: [{ type: "text", text: "Service temporarily unavailable, please retry" }] }; } }

实际内网的错误信息打全量日志到 ELK,Agent 只看脱敏后的消息。

总结

MCP 的意义不在于技术本身有多复杂(它就是个 JSON-RPC over SSE),而在于标准化了 Agent ↔ 工具之间的契约

这跟当年互联网从各种自定义二进制协议收敛到 HTTP 的逻辑一样:标准化降低集成成本、催生生态。

几个关键收获:

  1. Tool description 是最重要的"文档",写得不精确 = Agent 调不对
  2. SSE 连接的生命周期管理是线上最大的坑,重连策略、连接池、TTL 都要提前设计
  3. Tool Result 的粒度决定了 Token 消耗,宁可多分几个小 Tool,也别用一个巨型 Tool 塞所有数据
  4. 安全审计要覆盖 Tool→Agent 的返回路径,任何错误信息都可能成为 LLM 的上下文

目前在出海业务侧,MCP Server 已经接了订单、库存、物流三个域。下一步打算把多站点的 BI 指标也通过 MCP 暴露,让运营能把「东南亚站上月 GMV 环比为什么掉了 15%」这种问题直接问 Agent。


作者:lotusxyhf,互联网老兵转型出海 + AI Agent 赛道。从门户到 AI,踩过的坑比写过的代码还多。欢迎评论区交流。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/6 12:15:03

深入掌握AMD Ryzen调试:SMUDebugTool完全技术指南

深入掌握AMD Ryzen调试&#xff1a;SMUDebugTool完全技术指南 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/8/6 12:14:28

CentOS7 安装 DockerDocker-compose

CentOS7 安装 Docker&&Docker-composeCentOS7 内核要求≥3.10&#xff0c;推荐使用 yum 安装官方 docker‑ce1. 卸载旧版本&#xff08;如有&#xff09; yum remove -y docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-lo…

作者头像 李华
网站建设 2026/8/6 12:11:25

LinkSwift网盘直链下载助手:终极指南解决九大网盘下载难题

LinkSwift网盘直链下载助手&#xff1a;终极指南解决九大网盘下载难题 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / …

作者头像 李华
网站建设 2026/8/6 12:09:51

终极指南:KMS智能激活工具一键解决Windows和Office激活难题

终极指南&#xff1a;KMS智能激活工具一键解决Windows和Office激活难题 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows和Office激活问题而烦恼吗&#xff1f;KMS_VL_ALL_AIO智能激…

作者头像 李华
网站建设 2026/8/6 12:09:08

Adobe GenP破解工具:5分钟免费解锁Creative Cloud全家桶的终极指南

Adobe GenP破解工具&#xff1a;5分钟免费解锁Creative Cloud全家桶的终极指南 【免费下载链接】Adobe-GenP Adobe CC 2019/2020/2021/2022/2023 GenP Universal Patch 3.0 项目地址: https://gitcode.com/gh_mirrors/ad/Adobe-GenP Adobe GenP破解工具为创意工作者提供…

作者头像 李华