由Alice生成,注意鉴别
构建双模式工具调用服务器:兼容MCP协议与HTTP/SSE接口实践
作者:Alice
发布日期:2025-12-31
分类:技术教程、后端开发、AI工具
前言
在现代AI应用开发中,工具调用(Tool Calling)已成为增强大语言模型能力的重要手段。Model Context Protocol(MCP)作为新兴的标准化协议,为工具调用提供了统一的接口规范。本文将结合一个实际的双模式服务器实现,深入探讨如何同时满足MCP协议并兼容传统的HTTP/SSE接口。
项目架构概览
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
// ... 其他导入
核心服务器类 DualModeServer 支持三种运行模式:
- stdio模式:标准输入输出,适合CLI工具集成
- HTTP模式:传统RESTful API
- SSE模式:Server-Sent Events,支持实时通信
MCP协议实现详解
1. MCP服务器初始化
class DualModeServer {
private mcpServer: Server;
constructor() {
this.mcpServer = new Server(
{
name: 'custom-tools-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
this.setupMCPHandlers();
}
MCP服务器使用官方SDK创建,声明了工具调用能力,这是MCP协议的基础。
2. 工具列表查询(ListTools)
MCP协议要求服务器必须实现 ListToolsRequestSchema 处理器:
this.mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
const allManifests = toolRegistry.getAllToolManifests();
return {
tools: allManifests.map((tool: any) => ({
name: tool.name,
description: tool.description,
inputSchema: toolRegistry.getToolSchema(tool.name) || {
type: 'object',
properties: {},
},
})),
};
});
关键点:
- 返回所有注册工具的清单
- 每个工具包含名称、描述和输入模式(JSON Schema)
- 通过工具注册表(
toolRegistry)统一管理
3. 工具调用(CallTool)
MCP协议的核心功能是工具调用:
this.mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
const result = await toolRegistry.executeTool(name, args || {});
return {
content: [
{
type: 'text',
text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
},
],
};
} catch (error: any) {
throw new McpError(
ErrorCode.InternalError,
`工具执行失败: ${error.message}`
);
}
});
实现要点:
- 解析请求中的工具名称和参数
- 通过工具注册表执行对应工具
- 统一结果格式:文本类型的内容数组
- 错误处理使用MCP标准错误码
HTTP接口兼容设计
1. RESTful API端点
// 执行工具
this.expressApp.post('/execute', async (req, res) => {
const { function: funcName, parameters } = req.body;
if (!funcName || !parameters) {
return res.status(400).json({ error: 'Missing function or parameters' });
}
// 工具列表查询(元工具)
if (funcName === 'list_available_tools') {
const category = parameters?.category;
const allManifests = toolRegistry.getAllToolManifests();
const filteredTools = allManifests.filter((t: any) =>
!category || t.category === category
);
const categories = [...new Set(allManifests.map((t: any) => t.category))];
return res.json({
result: {
categories,
tools: filteredTools.map((t: any) => ({
name: t.name,
description: t.description,
category: t.category
}))
}
});
}
// 工具模式获取
if (funcName === 'get_tool_schema') {
const name = parameters?.name;
if (!name) {
return res.status(400).json({ error: 'Missing name parameter' });
}
const schema = toolRegistry.getToolSchema(name);
return res.json({ result: schema || null });
}
// 执行实际工具
try {
const result = await toolRegistry.executeTool(funcName, parameters);
res.json({ result });
} catch (error: any) {
console.error(`执行工具 ${funcName} 失败:`, error);
res.status(500).json({
error: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
}
});
2. 辅助端点设计
// 健康检查
this.expressApp.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
toolCount: toolRegistry.getAllToolManifests().length,
tools: toolRegistry.getToolNames(),
mode: 'http'
});
});
// 工具列表
this.expressApp.get('/tools', (req, res) => {
res.json({
tools: toolRegistry.getAllToolManifests(),
count: toolRegistry.getToolNames().length
});
});
SSE(Server-Sent Events)支持
MCP over SSE 提供了实时通信能力:
// MCP over SSE 端点
this.expressApp.get('/sse', async (req, res) => {
console.log('收到SSE连接请求');
const transport = new SSEServerTransport('/message', res);
await this.mcpServer.connect(transport);
});
this.expressApp.post('/message', async (req, res) => {
// SSE消息处理由SDK自动完成
res.status(200).end();
});
实现特点:
- 使用MCP SDK内置的SSE传输层
- 复用相同的MCP处理器逻辑
- 支持长连接和实时双向通信
工具注册表设计
核心的 toolRegistry 负责统一管理所有工具:
// 工具目录动态加载
const toolsDir = join(__dirname, 'tools');
console.log(`工具目录: ${toolsDir}`);
// 手动设置工具目录
(toolRegistry as any).toolsDir = toolsDir;
// 初始化工具注册表(启用热重载)
await toolRegistry.initialize();
关键功能:
- 动态加载指定目录下的所有工具模块
- 支持热重载,便于开发调试
- 提供统一的工具执行接口
多模式启动策略
async start() {
// 确定工具目录路径
const toolsDir = join(__dirname, 'tools');
console.log(`工具目录: ${toolsDir}`);
// 手动设置工具目录
(toolRegistry as any).toolsDir = toolsDir;
// 初始化工具注册表(启用热重载)
await toolRegistry.initialize();
switch (MODE) {
case 'stdio':
console.error('启动MCP服务器 (stdio模式)');
const stdioTransport = new StdioServerTransport();
await this.mcpServer.connect(stdioTransport);
console.error('已加载工具:', toolRegistry.getToolNames());
break;
case 'sse':
case 'http':
console.log('启动HTTP/SSE服务器模式');
this.setupHTTPServer();
break;
default:
throw new Error(`未知的服务器模式: ${MODE}`);
}
}
通过环境变量 SERVER_MODE 控制运行模式:
stdio:直接对接MCP客户端http:启动Web服务器,支持HTTP和SSEsse:同http模式,强调SSE功能
优雅关闭处理
// 优雅关闭
process.on('SIGINT', async () => {
console.log('\n正在关闭服务器...');
await server.stop();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.log('\n正在关闭服务器...');
await server.stop();
process.exit(0);
});
实际应用场景
场景1:AI助手集成
- 使用stdio模式集成到Claude、GPTs等AI助手
- AI通过MCP协议直接调用本地工具
场景2:Web应用后端
- 使用HTTP模式为前端应用提供工具调用API
- 支持浏览器直接调用后端工具
场景3:实时协作系统
- 使用SSE模式实现实时工具调用
- 支持多人协作和实时状态更新
最佳实践建议
- 工具标准化:所有工具都应遵循统一的接口规范
- 错误处理:MCP和HTTP模式下的错误处理要一致
- 文档自动生成:利用工具模式自动生成API文档
- 性能监控:添加工具执行时间和资源使用监控
- 安全考虑:对工具调用进行权限验证和参数校验
总结
本文展示的DualModeServer实现了一个灵活、可扩展的工具调用服务器,它:
- 完全兼容MCP协议标准
- 支持多种传输模式(stdio/HTTP/SSE)
- 提供统一的工具注册和执行机制
- 具备良好的可维护性和扩展性
这种设计模式不仅适用于AI工具调用场景,也可以应用于任何需要提供多协议接口的服务端系统。通过统一的工具注册表,开发者可以轻松添加新工具,而无需修改核心服务器逻辑。
由Alice生成
此方悬停