diff --git a/depends-data/mcp.schema.json b/depends-data/mcp.schema.json new file mode 100644 index 000000000..38ce78ba7 --- /dev/null +++ b/depends-data/mcp.schema.json @@ -0,0 +1,144 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MoFox Bot MCP Configuration", + "description": "Configuration for Model Context Protocol (MCP) servers", + "type": "object", + "properties": { + "mcpServers": { + "type": "object", + "description": "Dictionary of MCP server configurations", + "patternProperties": { + "^[a-zA-Z0-9_-]+$": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Human-readable description of this MCP server" + }, + "enabled": { + "type": "boolean", + "description": "Whether this server is enabled", + "default": true + }, + "transport": { + "type": "object", + "description": "Transport configuration", + "properties": { + "type": { + "type": "string", + "enum": ["streamable-http", "stdio"], + "description": "Transport type" + }, + "url": { + "type": "string", + "description": "URL for HTTP-based transports", + "format": "uri" + }, + "command": { + "type": "string", + "description": "Command for stdio transport" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Arguments for stdio transport" + } + }, + "required": ["type"], + "oneOf": [ + { + "properties": { + "type": { + "enum": ["streamable-http"] + } + }, + "required": ["url"] + }, + { + "properties": { + "type": { + "enum": ["stdio"] + } + }, + "required": ["command"] + } + ] + }, + "auth": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["bearer", "oauth"] + }, + "token": { + "type": "string", + "description": "Bearer token" + } + }, + "required": ["type"] + } + ], + "description": "Authentication configuration" + }, + "timeout": { + "type": "number", + "description": "Request timeout in seconds", + "minimum": 1, + "default": 30 + }, + "retry": { + "type": "object", + "properties": { + "max_retries": { + "type": "integer", + "minimum": 0, + "default": 3 + }, + "retry_delay": { + "type": "number", + "minimum": 0, + "default": 1 + } + } + } + }, + "required": ["transport"] + } + } + }, + "global": { + "type": "object", + "description": "Global MCP configuration", + "properties": { + "default_timeout": { + "type": "number", + "minimum": 1, + "default": 30 + }, + "max_concurrent_connections": { + "type": "integer", + "minimum": 1, + "default": 5 + }, + "auto_reconnect": { + "type": "boolean", + "default": true + }, + "log_level": { + "type": "string", + "enum": ["DEBUG", "INFO", "WARNING", "ERROR"], + "default": "INFO" + } + } + } + }, + "required": ["mcpServers"] +} diff --git a/src/plugin_system/core/mcp_client_manager.py b/src/plugin_system/core/mcp_client_manager.py index de19383fe..bf7713ac7 100644 --- a/src/plugin_system/core/mcp_client_manager.py +++ b/src/plugin_system/core/mcp_client_manager.py @@ -6,6 +6,7 @@ MCP Client Manager import asyncio import json +import shutil from pathlib import Path from typing import Any @@ -72,8 +73,19 @@ class MCPClientManager: Dict[str, MCPServerConfig]: 服务器名称 -> 配置对象 """ if not self.config_path.exists(): - logger.warning(f"MCP 配置文件不存在: {self.config_path}") - return {} + # 尝试从模板创建配置文件 + template_path = Path("template/mcp.json") + if template_path.exists(): + try: + self.config_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy(template_path, self.config_path) + logger.info(f"已从模板创建 MCP 配置文件: {self.config_path}") + except Exception as e: + logger.error(f"从模板创建配置文件失败: {e}") + return {} + else: + logger.warning(f"MCP 配置文件和模板都不存在: {self.config_path}, {template_path}") + return {} try: with open(self.config_path, encoding="utf-8") as f: diff --git a/template/mcp.json b/template/mcp.json new file mode 100644 index 000000000..9d8a228e3 --- /dev/null +++ b/template/mcp.json @@ -0,0 +1,88 @@ +{ + "$schema": "../depends-data/mcp.schema.json", + "mcpServers": { + "demo_server": { + "description": "演示用的 MCP 服务器(无认证)", + "enabled": true, + "transport": { + "type": "streamable-http", + "url": "http://localhost:8000/mcp" + }, + "auth": null, + "timeout": 30, + "retry": { + "max_retries": 3, + "retry_delay": 1 + } + }, + "bearer_auth_server": { + "description": "使用 Bearer Token 认证的服务器", + "enabled": false, + "transport": { + "type": "streamable-http", + "url": "https://api.example.com/mcp" + }, + "auth": { + "type": "bearer", + "token": "your-secret-bearer-token-here" + }, + "timeout": 30, + "retry": { + "max_retries": 3, + "retry_delay": 1 + } + }, + "oauth_server": { + "description": "使用 OAuth 认证的服务器", + "enabled": false, + "transport": { + "type": "streamable-http", + "url": "https://api.example.com/mcp" + }, + "auth": { + "type": "oauth", + "client_id": "your-client-id", + "client_secret": "your-client-secret", + "token_url": "https://auth.example.com/oauth/token" + }, + "timeout": 60, + "retry": { + "max_retries": 5, + "retry_delay": 2 + } + }, + "local_stdio_server": { + "description": "本地进程通过 stdio 通信的 MCP 服务器", + "enabled": false, + "transport": { + "type": "stdio", + "command": "python", + "args": [ + "-m", + "my_mcp_server", + "--config", + "server_config.json" + ] + }, + "timeout": 30 + }, + "node_stdio_server": { + "description": "Node.js MCP 服务器示例", + "enabled": false, + "transport": { + "type": "stdio", + "command": "node", + "args": [ + "path/to/mcp-server.js" + ] + }, + "timeout": 30 + } + }, + "global": { + "default_timeout": 30, + "max_concurrent_connections": 5, + "auto_reconnect": true, + "log_level": "INFO" + } +}