MCP 协议入门:从零理解 Model Context Protocol

不只是"又一个协议"------MCP 可能是 AI Agent 工具系统最重要的基础设施。本文从开发者视角,拆解它的架构、通信流程和关键设计。


一、AI Agent 需要一个"USB 协议"

2024 年以来,AI Agent 的形态逐渐清晰:一个 LLM 大脑,通过调用工具与外部世界交互。

但有一个尴尬的问题:每个框架、每个平台、每个 Agent 都定义了自己的一套工具格式 。LangChain 用 DynamicStructuredTool,OpenAI 用 function,Anthropic 用 tool_use。同一个"查数据库"的能力,在不同框架里要写不同的适配代码。

MCP(Model Context Protocol)的出现就是为了解决这个问题。它定义了一套标准,让:

  • 工具提供者只需写一次 MCP Server
  • 任何 MCP Client(Agent)都能直接使用
  • 生态可以独立于具体框架生长

类比:

  • USB 让任何外设能接入任何电脑
  • HTTP 让任何浏览器能访问任何服务器
  • MCP 让任何工具能被任何 AI Agent 调用

二、MCP 的核心架构:Client ↔ Server

2.1 基本模型

arduino 复制代码
┌──────────────────────┐                    ┌──────────────────────┐
│     MCP Client        │                    │     MCP Server        │
│   (Host/Agent)        │    JSON-RPC 2.0     │   (Tool Provider)    │
│                       │ ◄──────────────────►│                       │
│  - 发起请求            │    via stdio/HTTP    │  - 响应请求            │
│  - 管理连接            │                    │  - 执行业务逻辑         │
│  - 消费结果            │                    │  - 暴露能力            │
└──────────────────────┘                    └──────────────────────┘

MCP 基于 JSON-RPC 2.0 ------ 一种轻量的远程过程调用协议。每条消息都是一个 JSON 对象:

json 复制代码
// 请求
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "search_files",
    "arguments": { "pattern": "*.ts" }
  }
}

// 响应
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{ "type": "text", "text": "src/main.ts\nsrc/config.ts" }]
  }
}

2.2 两种传输方式

stdio(标准输入输出)

Server 作为 Client 的子进程运行,通过 stdin/stdout 通信。

arduino 复制代码
Client ──spawn──► Server 子进程
  stdin  ──────►  Server 接收请求
  stdout ◄──────  Server 返回响应
json 复制代码
// mcp-servers.json 配置
{
  "transport": "stdio",
  "command": "node",
  "args": ["./node_modules/xxx/dist/index.js", "--allowed-dir", "."],
  "env": { "API_KEY": "xxx" }
}
  • 优点:零网络配置,进程级隔离,安全
  • 适用:本地工具(文件系统、Git、数据库 CLI)

Streamable HTTP

Server 作为独立 HTTP 服务运行,通过 POST 请求通信。

arduino 复制代码
Client ──HTTP POST──► http://remote-server/mcp
json 复制代码
{
  "transport": "streamableHttp",
  "url": "http://localhost:3000/mcp"
}
  • 优点:跨机器访问,集中管理,团队共享
  • 适用:远程服务、企业内部 API 网关

2.3 完整的通信生命周期

css 复制代码
1. 握手(initialize)
    Client → Server: { method: "initialize", params: { protocolVersion, capabilities, clientInfo } }
    Server → Client: { result: { protocolVersion, capabilities, serverInfo } }

2. 发现工具(tools/list)
    Client → Server: { method: "tools/list" }
    Server → Client: { result: { tools: [{ name, description, inputSchema }, ...] } }

3. 调用工具(tools/call)
    Client → Server: { method: "tools/call", params: { name, arguments } }
    Server → Client: { result: { content: [{ type: "text", text: "..." }] } }

4. (可选)读取资源(resources/read)
    Client → Server: { method: "resources/read", params: { uri } }
    Server → Client: { result: { contents: [{ uri, mimeType, text }] } }

5. (可选)获取 Prompt(prompts/get)
    Client → Server: { method: "prompts/get", params: { name } }
    Server → Client: { result: { messages: [{ role, content }] } }

三、MCP 的三种原语

MCP 不只是"工具调用协议",它定义了三种原语:

3.1 Tools(工具)--- 最常用的

工具是 AI 可以调用的函数。Server 通过 tools/list 暴露工具,Client 通过 tools/call 调用。

javascript 复制代码
// Server 端定义的 Tool Schema
{
  name: "search_files",
  description: "按 glob 模式搜索文件,返回匹配的路径列表",
  inputSchema: {
    type: "object",
    properties: {
      pattern: { type: "string", description: "glob 模式,如 *.ts" },
      path: { type: "string", description: "搜索起始目录" }
    },
    required: ["pattern"]
  }
}

3.2 Resources(资源)--- 可读取的数据

资源是 Server 暴露的只读数据。跟工具不同,资源是数据而不是函数。

ruby 复制代码
// 资源 URI 示例
file:///project/README.md          → 返回 README 内容
docs://api-reference/auth          → 返回 API 认证文档
db://users/schema                  → 返回数据库表结构

Agent 可以在决策前读取相关资源作为上下文。比如在写代码前,先读取项目的 CLAUDE.md 了解规范。

3.3 Prompts(提示模板)--- 复用指令

Server 可以提供预定义的 Prompt 模板。

javascript 复制代码
// Server 端
{
  name: "write-commit-message",
  description: "根据 git diff 生成规范化的 commit message",
  arguments: [{ name: "diff", description: "git diff 输出", required: true }]
}

Agent 可以调用这个 Prompt 获取模板化的指令,而不是每次都从零写 Prompt。


四、关键 npm 包拆解

4.1 @modelcontextprotocol/sdk

这是 MCP 协议的 JS/TS 官方实现。核心模块:

arduino 复制代码
@modelcontextprotocol/sdk
├── client/
│   ├── stdio.js            stdio 传输的 Client 实现
│   ├── streamableHttp.js   HTTP 传输的 Client 实现
│   └── auth.js             OAuth 认证(Bearer token、API key)
├── server/
│   ├── stdio.js            stdio 传输的 Server 实现
│   └── streamableHttp.js   HTTP 传输的 Server 实现
└── types/                   TypeScript 类型定义

你一般不需要直接使用这个包------除非你要自己写 MCP Server 或做一个框架级的集成。

4.2 @langchain/mcp-adapters

这是 LangChain 官方出品的桥接层。它做两件事:

① 连接 Server,加载工具

javascript 复制代码
const client = new MultiServerMCPClient({
  mcpServers: { filesystem: { transport: 'stdio', command: 'node', args: [...] } }
});
await client.initializeConnections();
const tools = await client.getTools();
// tools 是 DynamicStructuredTool[] --- 跟本地工具完全一样

② Schema 转换(MCP JSON Schema → LangChain Zod Schema)

scss 复制代码
MCP Server 返回 inputSchema (JSON Schema)
        │
        ▼
  dereferenceJsonSchema()    → 解引用 $ref、$defs
        │
        ▼
  simplifyJsonSchemaForLLM() → 去除 LLM 不需要的字段(如 $schema、const 等)
        │
        ▼
  new DynamicStructuredTool({ schema: simplified, func: callTool }) → LangChain 工具

这个过程对用户透明,你拿到的就是可以直接 bindTools 的 LangChain 工具。


五、设计 MCP 集成时的 4 个关键决策

基于我在 min-cursor 项目中的实践,以下是集成 MCP 时必须考虑的 4 个问题:

决策 1:本地工具有 MCP 还要不要?

要。 文件读写、命令执行这种高频、高权限操作,保留本地实现更好:

  • 没有 IPC 开销
  • 没有序列化/反序列化损耗
  • 权限控制更灵活

MCP 工具做扩展:搜索、Git、GitHub、数据库等。

决策 2:重名工具如何处理?

MCP Server 提供的工具可能和本地工具同名(我就遇到 read_filewrite_filelist_directory 三个冲突)。

策略:本地优先,MCP 重名的跳过

javascript 复制代码
const localNames = new Set(localTools.map(t => t.name));
const uniqueMcpTools = mcpTools.filter(t => !localNames.has(t.name));

决策 3:MCP Server 挂了怎么办?

降级,不要阻塞。 MCP 连接失败时,Agent 仍应以本地工具启动。

javascript 复制代码
try {
  await client.initializeConnections();
} catch (e) {
  this.connected = false;  // 仅本地工具,Agent 继续跑
}

MCP 是锦上添花,不是单点故障。

决策 4:stdio 还是 HTTP?

stdio HTTP
延迟 极低(进程内通信) 取决于网络
部署 零配置 需要启动 HTTP 服务
安全 进程级隔离 需要认证/鉴权
跨机器
适用 本地工具 团队共享服务

对于个人开发者的 Agent,stdio 是默认选择


六、一个最小可用的 MCP 集成

如果你也想给自己的 Agent 加 MCP 支持,这是最小化的集成代码:

javascript 复制代码
import { MultiServerMCPClient } from '@langchain/mcp-adapters';

// 1. 配置 Server
const servers = {
  filesystem: {
    transport: 'stdio',
    command: 'node',
    args: ['./node_modules/@modelcontextprotocol/server-filesystem/dist/index.js', '.'],
  }
};

// 2. 初始化
const mcpClient = new MultiServerMCPClient({ mcpServers: servers });

try {
  await mcpClient.initializeConnections();
} catch (e) {
  console.warn('MCP 连接失败,仅用本地工具');
}

// 3. 获取工具
const localTools = [readFile, writeFile, listDir, execCommand];
const mcpTools = await mcpClient.getTools();

// 4. 去重 + 合并
const localNames = new Set(localTools.map(t => t.name));
const uniqueMcpTools = mcpTools.filter(t => !localNames.has(t.name));
const allTools = [...localTools, ...uniqueMcpTools];

// 5. 绑定到模型
const modelWithTools = model.bindTools(allTools);

// 6. 运行 Agent
const agent = new ReactAgent({ model: modelWithTools, tools: allTools, ... });
await agent.run(task);

// 7. 清理
await mcpClient.close();

核心就 7 步,不到 30 行代码。


七、MCP 的局限性(诚实地说)

  1. 生态还在早期。官方 Server 不到 20 个,质量参差不齐。但社区增长很快。

  2. stdio 有平台兼容问题 。部分 Server 依赖 bun 或 Unix 特性,Windows 上跑不了。选 Server 时注意检查。

  3. 没有版本协商。如果 Server 升级了 Tool Schema,Client 侧不会自动感知------需要重启。

  4. 调试困难。stdio 通信是进程内的,不像 HTTP 可以用浏览器抓包。debug 主要靠日志。

  5. 工具发现是静态的tools/list 只在初始化时调一次。如果 Server 动态增删工具,Client 感知不到(这是协议层面的设计选择------简单优于灵活)。


八、下一步:MCP 的想象空间

MCP 最大的价值不在于它现在能做什么,而在于它定义了一个标准接口。当足够多的工具都以 MCP Server 形式发布时:

  • 个人开发者不需要为每个新工具写适配代码
  • 工具作者只需写一次,就能被所有 MCP Client 使用
  • Agent 框架不需要维护自己的工具生态

这有点像 npm 对 JavaScript 的意义------一个标准化的包管理协议,催生了一个生态系统。

目前,MCP 是 Agent 工具系统最接近"标准化"的协议。值得每一个做 AI Agent 的开发者关注。


上一篇:从 4 个工具到无限扩展:给 AI Agent 装上 MCP 协议

相关推荐
老梁agent3 小时前
为什么你的 Agent 答错问题你查不出来?
物联网·agent
不好听6133 小时前
从 4 个工具到无限扩展:给 AI Agent 装上 MCP 协议
agent
leeyi3 小时前
Eino 的“你好世界“背后发生了什么(第48篇-E34)
aigc·agent·ai编程
志凌海纳SmartX3 小时前
构建 Agent Ready 的企业云基础设施(白皮书下载)
人工智能·ai·agent·smartx·企业云·榫卯企业云
葫芦和十三13 小时前
图解 MongoDB 30|查询路由与广播查询:带片键定向,不带就广播
后端·mongodb·agent
葫芦和十三14 小时前
图解 MongoDB 29|分片键陷阱:jumbo chunk、孤儿文档和写入热点
后端·mongodb·agent
花椒技术16 小时前
告别狂野式 AI Coding:Harness Engineering 在 H5 项目里的最小闭环实践
agent·ai编程·前端工程化
米小虾17 小时前
从RAG到GraphRAG:2026年知识增强生成技术的进化之路与实战指南
人工智能·agent