0%

MCP协议详解——AI Agent与工具标准化通信

今天在研究AI Agent架构,突然想到如果每个AI模型都能通过统一的方式与外部工具通信就好了。于是深入了解了MCP协议,感觉这是AI工具生态系统的重要基石…

介绍

  随着AI Agent技术的快速发展,模型与外部工具的集成需求日益增长。MCP(Model Context Protocol)协议作为一种标准化的通信协议,为AI Agent与外部工具之间的交互提供了统一的接口规范。本文将详细介绍MCP协议的设计理念、技术实现及其在AI Agent生态系统中的重要作用。

MCP协议概述

协议设计理念

  MCP协议的核心目标是解决AI Agent与外部工具之间的互操作性问题。通过标准化的请求-响应格式,MCP允许AI Agent以统一的方式调用不同类型的工具,无论这些工具是由何种编程语言实现或部署在何种平台上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// MCP协议的基本请求格式示例
class MCProtocolClient {
constructor(endpoint) {
this.endpoint = endpoint;
this.sessionId = this.generateSessionId();
}

// 生成会话ID
generateSessionId() {
return `mcp_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

// 调用外部工具
async callTool(toolName, params) {
const request = {
protocol: 'mcp',
version: '1.0',
sessionId: this.sessionId,
requestId: this.generateRequestId(),
action: 'call',
tool: toolName,
parameters: params,
timestamp: Date.now()
};

try {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.getAuthToken()}`
},
body: JSON.stringify(request)
});

if (!response.ok) {
throw new Error(`MCP request failed: ${response.status}`);
}

const result = await response.json();
return this.validateResponse(result);
} catch (error) {
console.error('MCP call error:', error);
throw error;
}
}

// 生成请求ID
generateRequestId() {
return `req_${Math.random().toString(36).substr(2, 12)}`;
}

// 验证响应格式
validateResponse(response) {
if (!response.protocol || response.protocol !== 'mcp') {
throw new Error('Invalid MCP response protocol');
}

if (response.version !== '1.0') {
throw new Error('Unsupported MCP version');
}

return response;
}

// 获取认证令牌
getAuthToken() {
return localStorage.getItem('mcp_auth_token') || sessionStorage.getItem('mcp_session_token');
}
}

// 使用示例
const mcpClient = new MCProtocolClient('https://api.tools.example.com/mcp');

// 调用天气查询工具
mcpClient.callTool('weather.query', {
location: 'Beijing',
unit: 'celsius',
forecast_days: 3
}).then(result => {
console.log('Weather data:', result.data);
}).catch(error => {
console.error('Failed to get weather data:', error);
});

MCP消息结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// MCP消息类型定义
const MCPTypes = {
REQUEST: 'request',
RESPONSE: 'response',
ERROR: 'error',
STREAM: 'stream',
PROGRESS: 'progress'
};

// MCP请求对象
class MCPRequest {
constructor(action, tool, parameters = {}, options = {}) {
this.protocol = 'mcp';
this.version = '1.0';
this.type = MCPTypes.REQUEST;
this.action = action; // 'call', 'subscribe', 'unsubscribe'
this.tool = tool;
this.parameters = parameters;
this.options = {
timeout: options.timeout || 30000,
priority: options.priority || 'normal',
callback: options.callback || null,
metadata: options.metadata || {}
};
this.timestamp = Date.now();
this.correlationId = this.generateCorrelationId();
}

generateCorrelationId() {
return `corr_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}

// 序列化为JSON
toJSON() {
return {
protocol: this.protocol,
version: this.version,
type: this.type,
action: this.action,
tool: this.tool,
parameters: this.parameters,
options: this.options,
timestamp: this.timestamp,
correlationId: this.correlationId
};
}

// 验证请求格式
validate() {
const requiredFields = ['protocol', 'version', 'action', 'tool'];
for (const field of requiredFields) {
if (!this[field]) {
throw new Error(`Missing required field: ${field}`);
}
}

// 验证协议版本
if (this.version !== '1.0') {
throw new Error('Unsupported MCP version');
}

return true;
}
}

// MCP响应对象
class MCPResponse {
constructor(request, data = null, error = null) {
this.protocol = 'mcp';
this.version = '1.0';
this.type = error ? MCPTypes.ERROR : MCPTypes.RESPONSE;
this.correlationId = request.correlationId;
this.requestAction = request.action;
this.requestTool = request.tool;
this.data = data;
this.error = error;
this.timestamp = Date.now();
this.duration = this.timestamp - request.timestamp;
}

// 序列化为JSON
toJSON() {
const response = {
protocol: this.protocol,
version: this.version,
type: this.type,
correlationId: this.correlationId,
requestAction: this.requestAction,
requestTool: this.requestTool,
timestamp: this.timestamp,
duration: this.duration
};

if (this.type === MCPTypes.ERROR) {
response.error = this.error;
} else {
response.data = this.data;
}

return response;
}
}

工具注册与发现机制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// MCP工具注册器
class MCPToolRegistry {
constructor() {
this.tools = new Map();
this.capabilities = new Map();
}

// 注册工具
registerTool(name, handler, metadata = {}) {
if (this.tools.has(name)) {
throw new Error(`Tool already registered: ${name}`);
}

this.tools.set(name, {
handler: handler,
metadata: metadata,
registeredAt: Date.now()
});

// 生成能力描述
this.capabilities.set(name, {
name: name,
description: metadata.description || 'No description',
parameters: metadata.parameters || {},
returns: metadata.returns || {},
category: metadata.category || 'general',
version: metadata.version || '1.0',
deprecated: metadata.deprecated || false
});

console.log(`Tool registered: ${name}`);
}

// 调用工具
async executeTool(name, parameters) {
const tool = this.tools.get(name);
if (!tool) {
throw new Error(`Tool not found: ${name}`);
}

try {
// 验证参数
if (!this.validateParameters(parameters, tool.metadata.parameters)) {
throw new Error('Invalid parameters for tool');
}

const startTime = Date.now();
const result = await tool.handler(parameters);
const duration = Date.now() - startTime;

return {
success: true,
data: result,
metadata: {
executionTime: duration,
toolVersion: tool.metadata.version,
requestId: this.generateRequestId()
}
};
} catch (error) {
return {
success: false,
error: error.message,
metadata: {
errorType: error.constructor.name,
requestId: this.generateRequestId()
}
};
}
}

// 验证参数
validateParameters(params, schema) {
if (!schema || Object.keys(schema).length === 0) {
return true; // 无参数要求
}

for (const [paramName, paramSchema] of Object.entries(schema)) {
if (paramSchema.required && params[paramName] === undefined) {
return false; // 必需参数缺失
}

if (params[paramName] !== undefined) {
const value = params[paramName];
const expectedType = paramSchema.type;

if (expectedType && typeof value !== expectedType) {
return false; // 类型不匹配
}

// 验证数值范围
if (paramSchema.min && value < paramSchema.min) {
return false;
}

if (paramSchema.max && value > paramSchema.max) {
return false;
}

// 验证字符串长度
if (typeof value === 'string') {
if (paramSchema.minLength && value.length < paramSchema.minLength) {
return false;
}

if (paramSchema.maxLength && value.length > paramSchema.maxLength) {
return false;
}
}
}
}

return true;
}

// 获取工具列表
getAvailableTools() {
return Array.from(this.capabilities.values());
}

// 获取工具详情
getToolDetails(name) {
return this.capabilities.get(name);
}

// 搜索工具
searchTools(query) {
const tools = this.getAvailableTools();
return tools.filter(tool =>
tool.name.toLowerCase().includes(query.toLowerCase()) ||
tool.description.toLowerCase().includes(query.toLowerCase()) ||
tool.category.toLowerCase().includes(query.toLowerCase())
);
}

generateRequestId() {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`;
}
}

// 示例工具实现
const registry = new MCPToolRegistry();

// 注册天气查询工具
registry.registerTool('weather.query', async (params) => {
const { location, unit = 'celsius', forecast_days = 1 } = params;

// 模拟API调用
const weatherData = {
location: location,
temperature: Math.floor(Math.random() * 30) + 15, // 模拟温度
humidity: Math.floor(Math.random() * 50) + 30,
condition: ['sunny', 'cloudy', 'rainy'][Math.floor(Math.random() * 3)]);

return weatherData;
}, {
description: '查询指定地点的天气信息',
category: 'weather',
version: '1.0',
parameters: {
location: {
type: 'string',
required: true,
description: '城市名称或坐标'
},
unit: {
type: 'string',
required: false,
default: 'celsius',
description: '温度单位(celsius/fahrenheit)'
},
forecast_days: {
type: 'number',
required: false,
default: 1,
min: 1,
max: 7,
description: '预报天数(1-7)'
}
},
returns: {
type: 'object',
properties: {
location: 'string',
temperature: 'number',
humidity: 'number',
condition: 'string'
}
}
});

// 注册数据库查询工具
registry.registerTool('database.query', async (params) => {
const { query, parameters = [], connection_id } = params;

// 模拟数据库查询
const mockResults = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];

return {
results: mockResults,
rowCount: mockResults.length,
executionTime: 42 // 模拟执行时间
};
}, {
description: '执行数据库查询操作',
category: 'database',
version: '1.0',
parameters: {
query: {
type: 'string',
required: true,
maxLength: 1000,
description: 'SQL查询语句'
},
parameters: {
type: 'array',
required: false,
default: [],
description: '查询参数数组'
},
connection_id: {
type: 'string',
required: true,
description: '数据库连接ID'
}
}
});

MCP协议实现

服务器端实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// MCP协议服务器端实现
const express = require('express');
const cors = require('cors');
const rateLimit = require('express-rate-limit');

class MCPProtocolServer {
constructor(options = {}) {
this.app = express();
this.port = options.port || 3000;
this.registry = new MCPToolRegistry();
this.middleware = options.middleware || [];
this.setupMiddlewares();
this.setupRoutes();
this.setupErrorHandling();
}

// 设置中间件
setupMiddlewares() {
// CORS配置
this.app.use(cors({
origin: this.getAllowedOrigins(),
credentials: true
}));

// 请求限流
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 限制每个IP 100个请求
message: 'Too many requests from this IP'
});

this.app.use(limiter);

// JSON解析
this.app.use(express.json({
limit: '10mb',
verify: (req, res, buf, encoding) => {
// 验证MCP协议头部
if (buf.length > 10 * 1024 * 1024) {
throw new Error('Request too large');
}
}
}));

// 日志中间件
this.app.use((req, res, next) => {
console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
next();
});

// 自定义中间件
this.middleware.forEach(middleware => {
this.app.use(middleware);
});
}

// 获取允许的源
getAllowedOrigins() {
return process.env.MCP_ALLOWED_ORIGINS?.split(',') || [
'http://localhost:3000',
'https://yourdomain.com'
];
}

// 设置路由
setupRoutes() {
// MCP主入口
this.app.post('/mcp', async (req, res) => {
try {
const request = req.body;

// 验证MCP协议格式
if (!this.validateMCPRequest(request)) {
return res.status(400).json({
error: 'Invalid MCP request format',
protocol: 'mcp',
version: '1.0'
});
}

// 认证请求
if (!await this.authenticateRequest(request)) {
return res.status(401).json({
error: 'Authentication failed',
protocol: 'mcp',
version: '1.0'
});
}

// 授权检查
if (!this.authorizeRequest(request)) {
return res.status(403).json({
error: 'Unauthorized access to tool',
protocol: 'mcp',
version: '1.0'
});
}

// 执行工具调用
const result = await this.executeRequest(request);

res.status(200).json(result);
} catch (error) {
console.error('MCP request error:', error);

res.status(500).json({
error: error.message,
protocol: 'mcp',
version: '1.0'
});
}
});

// 工具发现端点
this.app.get('/mcp/discovery', (req, res) => {
const tools = this.registry.getAvailableTools();
res.json({
protocol: 'mcp',
version: '1.0',
type: 'discovery',
tools: tools,
timestamp: Date.now()
});
});

// 健康检查
this.app.get('/health', (req, res) => {
res.json({
status: 'healthy',
protocol: 'mcp',
version: '1.0',
timestamp: Date.now()
});
});
}

// 验证MCP请求格式
validateMCPRequest(request) {
if (!request.protocol || request.protocol !== 'mcp') {
return false;
}

if (request.version !== '1.0') {
return false;
}

if (!request.action || !request.tool) {
return false;
}

return true;
}

// 认证请求
async authenticateRequest(request) {
const authHeader = this.getRequestAuthHeader(request);
if (!authHeader) {
return false;
}

try {
// 这里应该是实际的认证逻辑
// 例如验证JWT令牌、API密钥等
return await this.verifyAuthToken(authHeader);
} catch (error) {
console.error('Authentication error:', error);
return false;
}
}

// 授权检查
authorizeRequest(request) {
const { tool, parameters } = request;

// 检查工具是否存在
if (!this.registry.getToolDetails(tool)) {
return false;
}

// 检查参数是否符合权限要求
// 这里可以根据具体业务需求实现更复杂的授权逻辑

return true;
}

// 获取请求认证头部
getRequestAuthHeader(request) {
// 从请求体或HTTP头部获取认证信息
return request.authorization ||
request.auth_token ||
request.headers?.authorization;
}

// 验证认证令牌
async verifyAuthToken(token) {
// 实际的令牌验证逻辑
// 这里可以集成JWT验证、API密钥验证等
if (!token) {
return false;
}

// 简化的验证逻辑
if (token.startsWith('Bearer ')) {
const actualToken = token.substring(7);
return actualToken.length > 10; // 简单验证
}

return token.length > 10; // 简单验证
}

// 执行请求
async executeRequest(request) {
const { tool, parameters } = request;

const result = await this.registry.executeTool(tool, parameters);

return new MCPResponse(request, result.data, result.error).toJSON();
}

// 错误处理
setupErrorHandling() {
this.app.use((error, req, res, next) => {
console.error('Unhandled error:', error);

res.status(500).json({
error: 'Internal server error',
protocol: 'mcp',
version: '1.0'
});
});
}

// 启动服务器
start() {
this.app.listen(this.port, () => {
console.log(`MCP Protocol Server running on port ${this.port}`);
console.log(`Discovery endpoint: http://localhost:${this.port}/mcp/discovery`);
});
}

// 停止服务器
stop() {
// 清理资源
console.log('Stopping MCP Protocol Server...');
}
}

// 启动MCP服务器
const mcpServer = new MCPProtocolServer({
port: 3001
});

// 注册一些示例工具
// 天气工具已在上面注册

// 时间工具
mcpServer.registry.registerTool('time.now', async (params) => {
return {
timestamp: Date.now(),
iso: new Date().toISOString(),
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
unix: Math.floor(Date.now() / 1000)
};
}, {
description: '获取当前时间信息',
category: 'utility',
version: '1.0',
parameters: {}
});

// 启动服务器(注意:实际部署时需要考虑环境变量等)
// mcpServer.start();

客户端SDK实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// MCP协议客户端SDK
class MCPClientSDK {
constructor(config) {
this.config = {
endpoint: config.endpoint || 'http://localhost:3001/mcp',
authToken: config.authToken,
timeout: config.timeout || 30000,
retryAttempts: config.retryAttempts || 3,
retryDelay: config.retryDelay || 1000
};

this.cache = new Map();
this.cacheTimeout = config.cacheTimeout || 300000; // 5分钟
}

// 调用工具
async call(toolName, parameters = {}, options = {}) {
const request = new MCPRequest('call', toolName, parameters, options);

// 检查缓存
if (options.cache && this.isCacheValid(request)) {
return this.getFromCache(request);
}

let attempts = 0;
let lastError;

while (attempts < this.config.retryAttempts) {
try {
const response = await this.makeRequest(request);

// 缓存响应
if (options.cache) {
this.putToCache(request, response);
}

return response;
} catch (error) {
lastError = error;
attempts++;

if (attempts < this.config.retryAttempts) {
await this.delay(this.config.retryDelay * attempts); // 指数退避
}
}
}

throw lastError;
}

// 批量调用
async batch(calls) {
const promises = calls.map(call =>
this.call(call.tool, call.parameters, call.options).catch(err => ({
error: err.message,
tool: call.tool
}))
);

return Promise.all(promises);
}

// 订阅工具事件(适用于流式数据)
async subscribe(toolName, callback, parameters = {}) {
const request = new MCPRequest('subscribe', toolName, parameters, {
stream: true
});

// 使用EventSource或WebSocket实现订阅
const eventSource = new EventSource(
`${this.config.endpoint}?tool=${encodeURIComponent(toolName)}&subscribe=true`
);

eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.protocol === 'mcp' && data.type === 'stream') {
callback(data);
}
} catch (error) {
console.error('Error parsing stream data:', error);
}
};

eventSource.onerror = (error) => {
console.error('Stream error:', error);
};

return eventSource;
}

// 执行请求
async makeRequest(request) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);

try {
const response = await fetch(this.config.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.authToken}`,
'X-MCP-Version': request.version
},
body: JSON.stringify(request.toJSON()),
signal: controller.signal
});

clearTimeout(timeoutId);

if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}

const result = await response.json();

if (result.type === 'error') {
throw new Error(`MCP Error: ${result.error}`);
}

return result;
} catch (error) {
clearTimeout(timeoutId);

if (error.name === 'AbortError') {
throw new Error('Request timeout');
}

throw error;
}
}

// 缓存相关方法
isCacheValid(request) {
const cacheKey = this.getCacheKey(request);
const cached = this.cache.get(cacheKey);

if (!cached) {
return false;
}

return Date.now() - cached.timestamp < this.cacheTimeout;
}

getFromCache(request) {
const cacheKey = this.getCacheKey(request);
return this.cache.get(cacheKey).data;
}

putToCache(request, data) {
const cacheKey = this.getCacheKey(request);
this.cache.set(cacheKey, {
data: data,
timestamp: Date.now()
});
}

getCacheKey(request) {
return `${request.tool}:${JSON.stringify(request.parameters)}`;
}

delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

// 获取可用工具列表
async getAvailableTools() {
const response = await fetch(`${this.config.endpoint.replace('/mcp', '/discovery')}`, {
headers: {
'Authorization': `Bearer ${this.config.authToken}`
}
});

if (!response.ok) {
throw new Error('Failed to fetch tools list');
}

const data = await response.json();
return data.tools;
}

// 测试连接
async testConnection() {
try {
const response = await fetch(`${this.config.endpoint.replace('/mcp', '/health')}`);
const health = await response.json();
return health.status === 'healthy';
} catch (error) {
return false;
}
}
}

// 使用示例
async function example() {
const client = new MCPClientSDK({
endpoint: 'https://api.mcp.example.com/mcp',
authToken: 'your-api-token-here',
cacheTimeout: 600000 // 10分钟缓存
});

try {
// 测试连接
const isConnected = await client.testConnection();
console.log('MCP connection:', isConnected);

// 获取可用工具
const tools = await client.getAvailableTools();
console.log('Available tools:', tools);

// 调用天气工具
const weather = await client.call('weather.query', {
location: 'Shanghai',
unit: 'celsius'
}, { cache: true });

console.log('Weather data:', weather);

// 批量调用
const batchResults = await client.batch([
{ tool: 'time.now', parameters: {} },
{ tool: 'weather.query', parameters: { location: 'Beijing' } }
]);

console.log('Batch results:', batchResults);

} catch (error) {
console.error('Error:', error);
}
}

// example(); // 取消注释以运行示例

MCP协议最佳实践

安全考虑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// MCP安全中间件
class MCPSecurityMiddleware {
constructor(options = {}) {
this.options = {
maxRequestSize: options.maxRequestSize || 10 * 1024 * 1024, // 10MB
rateLimit: options.rateLimit || 100, // 每分钟请求次数
allowedOrigins: options.allowedOrigins || [],
requireHTTPS: options.requireHTTPS !== false, // 默认要求HTTPS
enforceEncryption: options.enforceEncryption !== false,
auditLogging: options.auditLogging !== false
};
}

// 验证请求安全性
validateSecurity(req, res, next) {
// 检查请求大小
if (req.headers['content-length'] > this.options.maxRequestSize) {
return res.status(413).json({
error: 'Request too large',
protocol: 'mcp',
version: '1.0'
});
}

// 检查协议安全性
if (this.options.requireHTTPS && req.protocol !== 'https') {
return res.status(400).json({
error: 'HTTPS required for MCP protocol',
protocol: 'mcp',
version: '1.0'
});
}

// 检查内容类型
if (req.headers['content-type'] !== 'application/json') {
return res.status(400).json({
error: 'Content-Type must be application/json',
protocol: 'mcp',
version: '1.0'
});
}

next();
}

// 输入验证
validateInput(req, res, next) {
const request = req.body;

// 验证工具名称格式
if (typeof request.tool !== 'string' || !this.isValidToolName(request.tool)) {
return res.status(400).json({
error: 'Invalid tool name format',
protocol: 'mcp',
version: '1.0'
});
}

// 验证参数类型安全
if (!this.isSafeParameters(request.parameters)) {
return res.status(400).json({
error: 'Potentially unsafe parameters detected',
protocol: 'mcp',
version: '1.0'
});
}

next();
}

// 验证工具名称格式
isValidToolName(name) {
// 工具名称应为字母、数字、点、下划线组成,长度合理
return /^[a-zA-Z0-9._-]{3,50}$/.test(name);
}

// 检查参数安全性
isSafeParameters(params) {
if (typeof params !== 'object' || params === null) {
return true; // 基本类型或null是安全的
}

// 检查是否包含潜在危险的属性
const dangerousPatterns = [
/\.\./, // 路径遍历
/__proto__/, // 原型污染
/constructor/, // 构造函数访问
/eval|exec|setTimeout|setInterval/i, // 代码执行函数
];

const jsonStr = JSON.stringify(params);

for (const pattern of dangerousPatterns) {
if (pattern.test(jsonStr)) {
return false;
}
}

return true;
}

// 审计日志
logAuditEvent(request, response, user) {
if (!this.options.auditLogging) return;

const auditLog = {
timestamp: new Date().toISOString(),
userId: user?.id || 'anonymous',
ip: request.ip,
userAgent: request.get('User-Agent'),
tool: request.body?.tool,
parameters: this.sanitizeParameters(request.body?.parameters),
responseStatus: response.statusCode,
duration: Date.now() - request.timestamp
};

console.log('MCP Audit:', JSON.stringify(auditLog));
// 在实际应用中,这里应该写入专门的审计日志系统
}

// 脱敏参数(避免敏感信息泄露)
sanitizeParameters(params) {
if (!params) return params;

const sanitized = { ...params };
const sensitiveKeys = ['password', 'token', 'secret', 'key', 'auth', 'credential'];

for (const key of sensitiveKeys) {
if (sanitized.hasOwnProperty(key)) {
sanitized[key] = '[REDACTED]';
}
}

return sanitized;
}

// 获取中间件函数
getMiddleware() {
return [
(req, res, next) => {
req.timestamp = Date.now();
next();
},
this.validateSecurity.bind(this),
this.validateInput.bind(this)
];
}
}

// 使用安全中间件的服务器
class SecureMCPProtocolServer extends MCPProtocolServer {
constructor(options = {}) {
super(options);

const securityMiddleware = new MCPSecurityMiddleware({
maxRequestSize: 5 * 1024 * 1024, // 5MB
rateLimit: 50,
allowedOrigins: ['https://trusted-domain.com'],
requireHTTPS: true
});

// 替换原有的中间件设置
this.securityMiddleware = securityMiddleware;

// 重新设置中间件
this.setupSecureMiddlewares();
}

setupSecureMiddlewares() {
// 安全相关的中间件
this.middleware.unshift(...this.securityMiddleware.getMiddleware());

// 设置CORS策略
this.app.use(cors({
origin: this.securityMiddleware.options.allowedOrigins,
credentials: true,
methods: ['POST', 'GET', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With']
}));
}
}

总结

  • MCP协议为AI Agent与外部工具的标准化通信提供了统一接口
  • 通过协议设计实现了工具的即插即用和动态发现
  • 安全机制确保了通信过程的安全性
  • 客户端SDK简化了集成过程
  • 缓存和批量处理优化了性能
  • 审计日志提供了操作追踪能力
  • 限流机制保护了服务稳定性

MCP协议就像是AI Agent的”通用插座”,让任何工具都能轻松接入AI生态系统。正如电器设备只需要找到对应的插座就能使用电力一样,未来的AI应用也将通过MCP协议轻松集成各种工具和服务。

MCP协议未来发展

  1. 版本演进: 支持更多消息类型和异步通信
  2. 标准化: 推进行业标准制定
  3. 安全性: 增强加密和认证机制
  4. 性能优化: 流式处理和批量优化
  5. 生态系统: 更丰富的工具集成

扩展阅读

  1. MCP Protocol Specification
  2. AI Agent Architecture Patterns
  3. Tool Calling Best Practices
bulb