外观
MCP协议实战:模型上下文协议与外部工具集成开发指南
给智能体接外部系统的日子并不好过:接飞书写一套函数声明,接数据库再写一套,换个宿主(从 CLI 换到 IDE)还得重写一遍适配层,工具一多,每个宿主和每个工具之间都是一格拼图。MCP(Model Context Protocol,模型上下文协议)解决的就是这个问题——它把「宿主怎么发现工具、怎么调用工具」标准化成一套协议,工具方实现一次 Server,任何支持 MCP 的智能体都能即插即用。本文带你从架构到代码跑通第一个 MCP 集成。
三层架构与两类核心能力
MCP 采用三层结构:Host 是承载智能体的应用(如 AI IDE、CLI 智能体),Client 是 Host 内维护与单个 Server 会话的组件,Server 是暴露能力的轻量进程。三者之间通过 JSON-RPC 通信,传输层在本地多用 stdio、远程部署用流式 HTTP。
Server 对外提供的能力中,最常用的是两类:Tool(工具)——由模型主动调用的动作,如「创建工单」「执行查询」,特征是有副作用;Resource(资源)——供宿主按需读取的数据,如配置文件、文档片段,特征是只读。二者职责不同:让模型「看」的数据走 Resource,让模型「做」的动作走 Tool,混着用会导致模型在该读数据时误触发写操作。
用 TypeScript 实现一个最小可用的 MCP Server
以官方 SDK 为例,实现一个查询订单状态的工具 Server,核心代码不到 40 行:
typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "order-service", version: "1.0.0" });
// 注册一个工具:模型可见的描述直接决定调用质量,务必写清边界
server.tool(
"query-order-status", // 工具名
"按订单号查询订单状态,仅支持 2026 年订单", // 描述:给模型看
{ orderId: z.string().describe("订单号,形如 SO2026xxxx") },
async ({ orderId }) => {
const order = await orderRepo.find(orderId);
if (!order) {
// 用结构化返回告诉模型「没查到」,而不是抛异常
return { content: [{ type: "text", text: "未找到该订单,请核对订单号" }] };
}
return {
content: [{ type: "text", text: `状态:${order.status},金额:${order.amount}` }]
};
}
);
await server.connect(new StdioServerTransport());三个细节决定这个 Server 的实际效果:第一,工具描述是写给模型的接口文档,「仅支持 2026 年订单」这类边界信息能避免模型拿错误参数反复重试;第二,入参用 zod 声明式校验,非法参数在协议层就被拦截,不会透传到业务代码;第三,「查不到」应作为正常文本返回而不是抛错,让模型有机会向用户澄清,而不是把异常栈当作上下文。
写完后在 IDE 的 MCP 配置中注册(以常见配置结构为例):
json
{
"mcpServers": {
"order-service": {
"command": "node",
"args": ["./mcp/order-service/dist/index.js"]
}
}
}重启宿主后,智能体会自动发现 query-order-status 工具,你说「查一下 SO20260012 的订单状态」,它就会发起调用。
调试与安全:上线前必做的两件事
调试推荐官方 Inspector(npx @modelcontextprotocol/inspector node dist/index.js),可以独立于宿主查看工具列表、手动传参调用、观察完整的 JSON-RPC 报文,能解决九成的「宿主里为什么不调用」问题。
安全约束要在设计期就固化:工具粒度最小化,宁可提供 query-pending-orders 也不要提供裸 SQL 执行;写操作一律要求显式确认参数,在工具内部做二次校验而不是信任模型;Server 进程以最小权限运行,只授予它真正需要的数据库账号与网络出口。此外,工具返回内容会进入模型上下文,来自外部系统的数据要过滤敏感字段,避免把用户手机号整段灌给模型。
实践清单
- 只读数据走 Resource、有副作用的动作走 Tool,职责不混用。
- 工具描述写清用途、参数格式与适用边界,它是模型的调用依据。
- 参数用 schema 校验,「查不到」用文本返回,别让异常污染上下文。
- 用 Inspector 独立调试通过后,再接入宿主排查集成问题。
- 写操作最小粒度 + 显式确认,Server 以最小权限运行。
MCP 之于智能体生态,意义类似于 LSP 之于编辑器生态:一次实现,处处可用。当团队把内部系统的能力逐步封装成 MCP Server,智能体就真正长在了你的工程体系上,而不是飘在对话框里。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。