|
@@ -2,11 +2,24 @@ import json
|
|
|
import subprocess
|
|
|
import asyncio
|
|
|
import sys
|
|
|
+import os
|
|
|
from mcp import ClientSession, StdioServerParameters
|
|
|
from mcp.client.stdio import stdio_client
|
|
|
from pydantic import BaseModel
|
|
|
-from http.server import HTTPServer, BaseHTTPRequestHandler
|
|
|
-from urllib.parse import urlparse, parse_qs
|
|
|
+from typing import Dict, List, Any, Optional
|
|
|
+import uvicorn
|
|
|
+from fastapi import FastAPI, HTTPException
|
|
|
+from fastapi.middleware.cors import CORSMiddleware
|
|
|
+
|
|
|
+class ToolModel(BaseModel):
|
|
|
+ name: str
|
|
|
+ description: Optional[str] = None
|
|
|
+ inputSchema: Optional[Dict] = None
|
|
|
+
|
|
|
+class CallRequest(BaseModel):
|
|
|
+ name: str
|
|
|
+ arguments: Optional[Dict] = {}
|
|
|
+
|
|
|
|
|
|
class MCPServerManager:
|
|
|
def __init__(self, config_file="mcp_config.json"):
|
|
@@ -146,6 +159,7 @@ class MCPServerManager:
|
|
|
"""
|
|
|
将MCP结果转换为可JSON序列化的格式
|
|
|
"""
|
|
|
+ from pydantic import BaseModel
|
|
|
if isinstance(result, BaseModel):
|
|
|
return result.model_dump()
|
|
|
elif isinstance(result, dict):
|
|
@@ -266,152 +280,65 @@ class MCPServerManager:
|
|
|
else:
|
|
|
print(f"✗ {server_name} 命令不可用")
|
|
|
|
|
|
-class MCPAPIHandler(BaseHTTPRequestHandler):
|
|
|
+
|
|
|
+
|
|
|
+# 创建FastAPI应用
|
|
|
+app = FastAPI(title="MCP API Server", description="MCP服务API接口")
|
|
|
+
|
|
|
+# 添加CORS中间件
|
|
|
+app.add_middleware(
|
|
|
+ CORSMiddleware,
|
|
|
+ allow_origins=["*"],
|
|
|
+ allow_credentials=True,
|
|
|
+ allow_methods=["*"],
|
|
|
+ allow_headers=["*"],
|
|
|
+)
|
|
|
+
|
|
|
+# 创建全局MCP服务器管理器实例
|
|
|
+mcp_manager = MCPServerManager()
|
|
|
+
|
|
|
+
|
|
|
+@app.get("/")
|
|
|
+async def root():
|
|
|
+ return {"message": "MCP API Server is running"}
|
|
|
+
|
|
|
+
|
|
|
+@app.get("/tools", response_model=List[ToolModel])
|
|
|
+async def get_tools():
|
|
|
"""
|
|
|
- MCP API HTTP请求处理器
|
|
|
+ 获取所有MCP工具列表
|
|
|
"""
|
|
|
-
|
|
|
- # 类变量,用于存储MCPServerManager实例
|
|
|
- server_manager = None
|
|
|
-
|
|
|
- def _set_headers(self, status_code=200, content_type='application/json'):
|
|
|
- """
|
|
|
- 设置HTTP响应头
|
|
|
- """
|
|
|
- self.send_response(status_code)
|
|
|
- self.send_header('Content-type', content_type)
|
|
|
- self.send_header('Access-Control-Allow-Origin', '*')
|
|
|
- self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
|
|
|
- self.send_header('Access-Control-Allow-Headers', 'Content-Type')
|
|
|
- self.end_headers()
|
|
|
-
|
|
|
- def do_OPTIONS(self):
|
|
|
- """
|
|
|
- 处理CORS预检请求
|
|
|
- """
|
|
|
- self._set_headers()
|
|
|
-
|
|
|
- def do_GET(self):
|
|
|
- """
|
|
|
- 处理GET请求
|
|
|
- """
|
|
|
- parsed_path = urlparse(self.path)
|
|
|
-
|
|
|
- # 处理 /tools 接口
|
|
|
- if parsed_path.path == '/tools':
|
|
|
- self._handle_tools_request()
|
|
|
- else:
|
|
|
- self._set_headers(404)
|
|
|
- self.wfile.write(json.dumps({"error": "未找到接口"}).encode('utf-8'))
|
|
|
-
|
|
|
- def do_POST(self):
|
|
|
- """
|
|
|
- 处理POST请求
|
|
|
- """
|
|
|
- parsed_path = urlparse(self.path)
|
|
|
-
|
|
|
- # 处理 /call 接口
|
|
|
- if parsed_path.path == '/call':
|
|
|
- self._handle_call_request()
|
|
|
- else:
|
|
|
- self._set_headers(404)
|
|
|
- self.wfile.write(json.dumps({"error": "未找到接口"}).encode('utf-8'))
|
|
|
-
|
|
|
- def _handle_tools_request(self):
|
|
|
- """
|
|
|
- 处理 /tools 请求,返回所有MCP工具列表
|
|
|
- """
|
|
|
- try:
|
|
|
- # 在新的事件循环中运行异步代码
|
|
|
- loop = asyncio.new_event_loop()
|
|
|
- asyncio.set_event_loop(loop)
|
|
|
-
|
|
|
- tools = loop.run_until_complete(
|
|
|
- self.server_manager.get_all_mcp_tools()
|
|
|
- )
|
|
|
- loop.close()
|
|
|
-
|
|
|
- self._set_headers()
|
|
|
- self.wfile.write(json.dumps(tools, ensure_ascii=False).encode('utf-8'))
|
|
|
- except Exception as e:
|
|
|
- self._set_headers(500)
|
|
|
- self.wfile.write(json.dumps({"error": str(e)}).encode('utf-8'))
|
|
|
-
|
|
|
- def _handle_call_request(self):
|
|
|
- """
|
|
|
- 处理 /call 请求,调用指定的MCP工具
|
|
|
- """
|
|
|
- try:
|
|
|
- # 读取请求体
|
|
|
- content_length = int(self.headers['Content-Length'])
|
|
|
- post_data = self.rfile.read(content_length)
|
|
|
-
|
|
|
- # 解析JSON数据
|
|
|
- data = json.loads(post_data.decode('utf-8'))
|
|
|
-
|
|
|
- # 获取必要参数
|
|
|
- tool_name = data.get('name')
|
|
|
- arguments = data.get('arguments', {})
|
|
|
-
|
|
|
- if not tool_name:
|
|
|
- self._set_headers(400)
|
|
|
- self.wfile.write(json.dumps({"error": "缺少工具名称"}).encode('utf-8'))
|
|
|
- return
|
|
|
-
|
|
|
- # 在新的事件循环中运行异步代码
|
|
|
- loop = asyncio.new_event_loop()
|
|
|
- asyncio.set_event_loop(loop)
|
|
|
-
|
|
|
- result = loop.run_until_complete(
|
|
|
- self.server_manager.call_mcp_tool(tool_name, arguments)
|
|
|
- )
|
|
|
- loop.close()
|
|
|
-
|
|
|
- # 检查是否有错误
|
|
|
- if isinstance(result, dict) and "error" in result:
|
|
|
- self._set_headers(500)
|
|
|
- else:
|
|
|
- self._set_headers()
|
|
|
-
|
|
|
- self.wfile.write(json.dumps(result, ensure_ascii=False).encode('utf-8'))
|
|
|
- except json.JSONDecodeError:
|
|
|
- self._set_headers(400)
|
|
|
- self.wfile.write(json.dumps({"error": "无效的JSON格式"}).encode('utf-8'))
|
|
|
- except Exception as e:
|
|
|
- self._set_headers(500)
|
|
|
- self.wfile.write(json.dumps({"error": str(e)}).encode('utf-8'))
|
|
|
+ try:
|
|
|
+ tools = await mcp_manager.get_all_mcp_tools()
|
|
|
+ return tools
|
|
|
+ except Exception as e:
|
|
|
+ raise HTTPException(status_code=500, detail=str(e))
|
|
|
+
|
|
|
|
|
|
-class MCPAPIServer:
|
|
|
+@app.post("/call")
|
|
|
+async def call_tool(request: CallRequest):
|
|
|
"""
|
|
|
- MCP API服务器主类
|
|
|
+ 调用指定的MCP工具
|
|
|
"""
|
|
|
-
|
|
|
- def __init__(self, host='localhost', port=8000, config_file='mcp_config.json'):
|
|
|
- self.host = host
|
|
|
- self.port = port
|
|
|
- self.server_manager = MCPServerManager(config_file)
|
|
|
- # 将server_manager设置为请求处理器的类变量
|
|
|
- MCPAPIHandler.server_manager = self.server_manager
|
|
|
-
|
|
|
- def start(self):
|
|
|
- """
|
|
|
- 启动MCP API服务器
|
|
|
- """
|
|
|
- # 初始化所有服务器
|
|
|
- print("正在初始化MCP服务器...")
|
|
|
- loop = asyncio.new_event_loop()
|
|
|
- asyncio.set_event_loop(loop)
|
|
|
- loop.run_until_complete(self.server_manager.initialize_all_servers())
|
|
|
- loop.close()
|
|
|
- print("MCP服务器初始化完成")
|
|
|
-
|
|
|
- # 启动HTTP服务器
|
|
|
- server_address = (self.host, self.port)
|
|
|
- httpd = HTTPServer(server_address, MCPAPIHandler)
|
|
|
- print(f"启动MCP API服务器: http://{self.host}:{self.port}")
|
|
|
- httpd.serve_forever()
|
|
|
+ try:
|
|
|
+ result = await mcp_manager.call_mcp_tool(request.name, request.arguments)
|
|
|
+ # 检查是否有错误
|
|
|
+ if isinstance(result, dict) and "error" in result:
|
|
|
+ raise HTTPException(status_code=500, detail=result["error"])
|
|
|
+ return result
|
|
|
+ except HTTPException:
|
|
|
+ raise
|
|
|
+ except Exception as e:
|
|
|
+ raise HTTPException(status_code=500, detail=str(e))
|
|
|
+
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
- # 创建并启动MCP API服务器
|
|
|
- api_server = MCPAPIServer()
|
|
|
- api_server.start()
|
|
|
+ # 初始化所有服务器
|
|
|
+ print("正在初始化MCP服务器...")
|
|
|
+ loop = asyncio.get_event_loop()
|
|
|
+ loop.run_until_complete(mcp_manager.initialize_all_servers())
|
|
|
+ print("MCP服务器初始化完成")
|
|
|
+
|
|
|
+ # 启动FastAPI服务器
|
|
|
+ print("启动MCP API服务器: http://localhost:8000")
|
|
|
+ uvicorn.run("mcp_api_server:app", host="localhost", port=8000, reload=False)
|