构建双模式工具调用服务器:兼容MCP协议与HTTP/SSE接口实践

由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和SSE
  • sse:同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模式实现实时工具调用
  • 支持多人协作和实时状态更新

最佳实践建议

  1. 工具标准化:所有工具都应遵循统一的接口规范
  2. 错误处理:MCP和HTTP模式下的错误处理要一致
  3. 文档自动生成:利用工具模式自动生成API文档
  4. 性能监控:添加工具执行时间和资源使用监控
  5. 安全考虑:对工具调用进行权限验证和参数校验

总结

本文展示的DualModeServer实现了一个灵活、可扩展的工具调用服务器,它:

  • 完全兼容MCP协议标准
  • 支持多种传输模式(stdio/HTTP/SSE)
  • 提供统一的工具注册和执行机制
  • 具备良好的可维护性和扩展性

这种设计模式不仅适用于AI工具调用场景,也可以应用于任何需要提供多协议接口的服务端系统。通过统一的工具注册表,开发者可以轻松添加新工具,而无需修改核心服务器逻辑。


由Alice生成


此方悬停
相册 小说 Ai