摘要: MCP(Model Context Protocol,模型上下文协议)是 Anthropic 提出的一种标准化协议,旨在解耦大语言模型(LLM)与外部工具(Tool)、数据源(Resource)之间的通信。本文基于
mcp-demo项目,从问题背景出发,逐步深入 MCP 的核心概念、架构设计,并通过一个完整的 Node.js MCP Server 实战案例,带你理解 MCP 的跨进程通信机制。
目录
1. 为什么需要 MCP?
在传统的 AI Agent 开发中,工具(Tool)往往与 LLM 紧密耦合,存在两个核心痛点:
- 工具无法跨项目复用 —— 在一个项目中编写的 Tool,很难直接迁移到另一个项目中使用。
- 语言绑定限制 —— 用 Node.js 写的工具,Java / Python / Rust 等其他语言的项目如何调用?
这些问题的本质是:Tool 与 LLM 之间缺乏一个标准化的通信协议。
MCP 正是为了解决这些问题而生。它的核心理念是:
Tool 独立于 LLM,通过标准化协议实现本地/远程、跨进程、跨语言的调用。
2. MCP 协议是什么?
2.1 定义
MCP(Model Context Protocol,模型上下文协议) 是一种标准化 LLM 与外部工具和资源之间通信的协议。它的目标是:
- 解耦 LLM 和 Tool,让工具可以独立开发、独立部署、跨项目复用。
- 为 Model 扩展 Context(上下文),让它能做更多(Tool)、知道更多(Resource)。
2.2 MCP 的定位
MCP 不是一种 API 调用方式,它和传统的 HTTP Fetch 有本质区别:
| 对比维度 | 传统 API 调用 (Fetch) | MCP 协议 |
|---|---|---|
| 目的 | 获取接口数据 | 扩展 LLM 的 Context(Tool & Resource) |
| 通信方式 | 单向请求-响应 | 双向、持久化的进程通信 |
| 标准化 | 每个 API 有自己的规范 | 统一的协议标准 |
| 跨语言 | 需要各自实现 HTTP 客户端 | 基于 stdio/HTTP,天然跨语言 |
简而言之,MCP 的目标是:不管是本地工具还是远程工具,Agent 想跨进程调用某个工具,通过 MCP 协议就行。
3. MCP 的核心特点
3.1 跨进程调用
MCP 最大的特点就是跨进程调用工具:
- 本地跨进程 → 使用 stdio(标准输入输出流)
- 远程跨进程 → 使用 HTTP

3.2 架构角色
在 MCP 的架构中,有三个关键角色:
| 角色 | 说明 |
|---|---|
| MCP Host(宿主) | AI Agent 本身,作为 MCP 客户端,发起工具调用请求 |
| MCP Client(客户端) | 与 MCP Server 建立连接,管理通信通道 |
| MCP Server(服务端) | 提供具体的 Tool 和 Resource,响应客户端请求 |
一个 AI Agent(MCP Host)可以通过配置多个 MCP Client,连接到不同的 MCP Server,实现跨进程工具调用。
3.3 通信原理
基于 stdio(标准输入输出流) 的通信原理:
- 键盘输入 → 控制台输出
- 当一个进程(Agent)调用子进程(如
node child_process)时,通过 stdio 标准输入输出流来实现通信 - 对于远程场景,MCP 同样支持基于 HTTP 的通信方式
4. 项目实战:构建一个 MCP Server
下面我们通过 mcp-demo 项目,从零开始构建一个完整的 MCP Server。
4.1 项目初始化
首先来看项目的 package.json 配置:
{
"name": "mcp-demo",
"version": "1.0.0",
"description": "MCP Demo 项目",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@langchain/core": "^1.2.3",
"@langchain/mcp-adapters": "^1.1.3",
"@langchain/openai": "^1.5.5",
"@modelcontextprotocol/sdk": "^1.29.0",
"chalk": "^5.6.2",
"zod": "^4.4.3"
}
}
4.2 核心依赖解析
项目依赖几个关键包,各司其职:
| 依赖包 | 作用 |
|---|---|
@modelcontextprotocol/sdk | MCP 官方 SDK,提供 McpServer、StdioServerTransport 等核心 API |
@langchain/mcp-adapters | LangChain 的 MCP 适配器,让 Agent 能以 MCP Client 身份连接 MCP Server |
@langchain/core | LangChain 核心库,提供消息类型(HumanMessage、ToolMessage 等) |
@langchain/openai | LangChain 的 OpenAI 兼容接口,用于连接 DeepSeek 等 LLM |
zod | TypeScript 优先的 Schema 声明与验证库,用于定义 Tool 的输入参数 Schema |
chalk | 终端彩色输出工具,用于美化命令行日志 |
4.3 MCP Server 代码详解
下面我们逐段解析 src/my-mcp-server.mjs 的实现:
4.3.1 导入依赖
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
关键点:
McpServer:MCP 服务端的核心类,用于创建服务器实例、注册工具。StdioServerTransport:基于标准输入输出流的传输层,实现跨进程通信。z(Zod):用于声明和验证工具参数的数据结构。
4.3.2 定义数据源
// 假数据,未来可以走数据库
const database = {
users: {
'001': { id: '001', name: '张三', email: 'zs@qq.com', role: 'admin' },
'002': { id: '002', name: '李四', email: 'ls@qq.com', role: 'user' },
'003': { id: '003', name: '王五', email: 'wu@qq.com', role: 'user' },
}
}
这里使用内存中的静态数据模拟数据库。在实际项目中,这里可以替换为真实的数据库连接(MySQL、PostgreSQL、MongoDB 等)。这正是 MCP 的优势所在:工具的实现细节对 LLM 完全透明。
4.3.3 创建 MCP Server 实例
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0',
});
每个 MCP Server 都有自己的名称和版本号,这是 MCP 协议规范的一部分,便于 MCP Client 识别和管理多个 Server。
4.3.4 注册工具(Tool)
server.registerTool('query-user', {
description: `查询数据库中的用户信息。输入用户ID,返回该用户的详细信息(姓名、邮箱、角色)`,
inputSchema: {
user_id: z.string().describe('用户ID,例如:001,002,003')
}
}, async (userId) => {
const user = database.users[userId];
if (!user) {
return {
content: [
{ type: 'text', text: `用户 ID ${userId} 不存在。可用的ID:001, 002, 003` }
]
}
}
return {
content: [
{
type: 'text',
text: `用户 ${user.id}的信息是:
姓名:${user.name},邮箱:${user.email},角色:${user.role}`
}
]
}
})
这是 MCP Server 的核心。registerTool 方法接收三个参数:
| 参数 | 说明 |
|---|---|
工具名称 ('query-user') | Tool 的唯一标识符,LLM 通过名称来调用工具 |
| 工具元数据 | 包含 description(描述,供 LLM 理解工具用途)和 inputSchema(输入参数的 Zod Schema,供 LLM 知道如何传参) |
| 处理函数 | 异步函数,接收参数并返回执行结果,结果以 { content: [...] } 格式返回 |
关键设计思想:
description是写给 LLM 看的 —— LLM 通过描述来判断何时调用该工具。inputSchema使用 Zod 定义,LLM 根据 Schema 生成结构化的参数。- 返回值遵循 MCP 协议的
content格式,支持多种内容类型(text、image 等)。
4.3.5 启动传输层
// 跨进程通信方式 stdio
const transport = new StdioServerTransport();
await server.connect(transport);
这是整个 Server 的最后一步,也是最关键的一步:
StdioServerTransport()创建一个基于标准输入输出流的传输层。server.connect(transport)将 Server 绑定到该传输层,开始监听来自 MCP Client 的请求。
这意味着: 任何能够启动子进程并与其 stdio 通信的程序(Node.js、Python、Java、Rust 等),都可以作为 MCP Client 来调用这个 Server 中的工具。这就是 MCP 跨语言、跨进程的核心实现。
5. MCP 的通信机制
5.1 Stdio 通信模型
┌──────────────┐ stdin ┌──────────────┐
│ │ ─────────> │ │
│ MCP Client │ │ MCP Server │
│ (Agent) │ <───────── │ (Tool 提供) │
│ │ stdout │ │
└──────────────┘ └──────────────┘
- MCP Client(Agent 端)通过
child_process启动 MCP Server 子进程。 - Client 通过 stdin 向 Server 发送 JSON-RPC 格式的请求(如:调用工具
query-user,参数{user_id: "001"})。 - Server 处理请求后,通过 stdout 返回 JSON-RPC 格式的响应。
- Client 接收响应,将其传递给 LLM 进行下一步推理。
5.2 HTTP 通信模型
对于远程工具调用,MCP 同样支持基于 HTTP 的传输方式,允许 Agent 调用部署在远程服务器上的工具。
6. MCP Tool 的本质
在 MCP 的视角下,Tool 的本质可以概括为:
Tool = 描述(Description) + 输入约束(Input Schema) + 执行逻辑(Handler)
| 组成部分 | 作用 | 面向对象 |
|---|---|---|
| Description | 用自然语言描述工具的功能 | 面向 LLM,让模型理解何时使用 |
| Input Schema | 用结构化 Schema 定义输入参数 | 面向 LLM,让模型知道如何传参 |
| Handler | 实际的业务逻辑代码 | 面向 开发者,执行真实的操作 |
这种设计将 语义层(给 LLM 看)和 执行层(给机器跑)清晰地分离开来,实现了 LLM 与 Tool 的彻底解耦。
7. 总结与展望
7.1 本文要点回顾
- MCP 解决了什么问题? —— Tool 无法跨项目复用、跨语言调用的痛点。
- MCP 是什么? —— 一种标准化 LLM 与 Tool/Resource 通信的协议,核心是解耦和扩展 Context。
- MCP 的核心特点 —— 跨进程调用(本地 stdio + 远程 HTTP)。
- 如何构建 MCP Server? —— 使用
@modelcontextprotocol/sdk,通过McpServer+registerTool+StdioServerTransport三步即可完成。 - Tool 的本质 —— Description + Input Schema + Handler 三位一体。
7.2 未来展望
MCP 作为 AI Agent 生态的关键基础设施,未来有望在以下方向持续发展:
- 多语言 SDK 生态 —— 随着 Python、Java、Rust 等语言的 SDK 成熟,跨语言工具调用将更加便捷。
- 工具市场(Tool Marketplace) —— 标准化的 MCP Server 可以被发布和共享,形成类似 npm/PyPI 的工具生态。
- 企业级 MCP 网关 —— 统一管理、鉴权、监控企业内部的各种 MCP Server。
- 与 Agent 框架深度集成 —— LangChain、AutoGen、CrewAI 等框架将 MCP 作为一等公民支持。