跳到主内容

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,混着用会导致模型在该读数据时误触发写操作。

MCP 统一协议总线:一次集成,处处可用AI 助手Host + Client发起 JSON-RPCMCP 协议总线本地:stdio远程:流式 HTTP日历服务Tool:创建日程文件系统Resource:只读读取外部 APITool:执行查询Tool 让模型“做动作”(有副作用) · Resource 让模型“看数据”(只读)

用 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 进程以最小权限运行,只授予它真正需要的数据库账号与网络出口。此外,工具返回内容会进入模型上下文,来自外部系统的数据要过滤敏感字段,避免把用户手机号整段灌给模型。

实践清单 ​

  1. 只读数据走 Resource、有副作用的动作走 Tool,职责不混用。
  2. 工具描述写清用途、参数格式与适用边界,它是模型的调用依据。
  3. 参数用 schema 校验,「查不到」用文本返回,别让异常污染上下文。
  4. 用 Inspector 独立调试通过后,再接入宿主排查集成问题。
  5. 写操作最小粒度 + 显式确认,Server 以最小权限运行。

MCP 之于智能体生态,意义类似于 LSP 之于编辑器生态:一次实现,处处可用。当团队把内部系统的能力逐步封装成 MCP Server,智能体就真正长在了你的工程体系上,而不是飘在对话框里。

免责声明

本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。