Skip to main content
Glama
http_server.py7.85 kB
"""IDA MCP HTTP 代理服务器 - HTTP 传输入口 直接复用 proxy/_server.py 中的 FastMCP server,只是改为 HTTP 传输方式。 架构: ┌─────────────────────────────────────────────────┐ │ proxy/_server.server │ │ (FastMCP 实例,唯一的工具定义源) │ └───────────────┬─────────────────┬───────────────┘ │ │ ┌───────▼───────┐ ┌───────▼───────┐ │ stdio 传输 │ │ HTTP 传输 │ │ server.run() │ │ http_app() │ └───────────────┘ └───────────────┘ │ │ └────────┬────────┘ ▼ 协调器 (11337) ▼ IDA 实例 (10001, ...) """ from __future__ import annotations import os import sys import threading import time from typing import Optional, Any # ============================================================================ # 导入共享的 server # ============================================================================ # 添加 proxy 目录到路径 _this_dir = os.path.dirname(os.path.abspath(__file__)) _proxy_dir = os.path.join(os.path.dirname(_this_dir), "proxy") if _proxy_dir not in sys.path: sys.path.insert(0, _proxy_dir) # 导入共享的 server 实例(与 stdio proxy 完全相同) from _server import server # type: ignore # ============================================================================ # 全局状态 # ============================================================================ _http_thread: Optional[threading.Thread] = None _http_server: Any = None # uvicorn.Server 实例 _http_port: Optional[int] = None _stop_lock = threading.Lock() # ============================================================================ # HTTP 服务器管理 # ============================================================================ def start_http_proxy(host: str = "127.0.0.1", port: int = 11338, path: str = "/mcp") -> bool: """启动 HTTP MCP 代理服务器。 参数: host: 监听地址 port: 监听端口 path: MCP 端点路径 返回: 是否启动成功 """ global _http_thread, _http_server, _http_port with _stop_lock: if _http_thread is not None and _http_thread.is_alive(): return True # 已在运行 def worker(): global _http_server try: # Windows 控制台噪音抑制 if os.name == "nt": try: import asyncio if hasattr(asyncio, "WindowsSelectorEventLoopPolicy"): asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) except Exception: pass # 使用共享的 server 创建 HTTP app app = server.http_app(path=path) import uvicorn config = uvicorn.Config(app, host=host, port=port, log_level="warning", access_log=False) _http_server = uvicorn.Server(config) import asyncio def _exception_handler(loop, context): exc = context.get("exception") if exc is not None: winerr = getattr(exc, "winerror", None) if winerr == 10054 and isinstance(exc, (ConnectionResetError, OSError)): return msg = str(context.get("message") or "") if "10054" in msg and "ConnectionResetError" in msg: return loop.default_exception_handler(context) loop = asyncio.new_event_loop() try: asyncio.set_event_loop(loop) loop.set_exception_handler(_exception_handler) if hasattr(_http_server, "serve"): loop.run_until_complete(_http_server.serve()) else: _http_server.run() finally: try: loop.run_until_complete(loop.shutdown_asyncgens()) except Exception: pass try: loop.run_until_complete(loop.shutdown_default_executor()) except Exception: pass try: loop.close() except Exception: pass except Exception as e: print(f"[IDA-MCP-HTTP][ERROR] Server failed: {e}") finally: _http_server = None _http_thread = threading.Thread(target=worker, name="IDA-MCP-HTTP-Proxy", daemon=True) _http_thread.start() _http_port = port # 等待服务器启动 time.sleep(0.5) return _http_thread.is_alive() def stop_http_proxy() -> None: """停止 HTTP MCP 代理服务器。""" global _http_thread, _http_server, _http_port with _stop_lock: if _http_server is not None: try: _http_server.should_exit = True except Exception: pass if _http_thread is not None: _http_thread.join(timeout=5) _http_thread = None _http_server = None _http_port = None def is_http_proxy_running() -> bool: """检查 HTTP 代理是否正在运行。""" return _http_thread is not None and _http_thread.is_alive() def get_http_url() -> Optional[str]: """获取当前 HTTP 代理的 URL。""" if _http_port is None: return None # 从配置获取 try: from ..config import get_http_host, get_http_path host = get_http_host() path = get_http_path() except Exception: host = "127.0.0.1" path = "/mcp" return f"http://{host}:{_http_port}{path}" # ============================================================================ # 独立运行入口 # ============================================================================ if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="IDA MCP HTTP Proxy Server") parser.add_argument("--host", default="127.0.0.1", help="Host to bind (default: 127.0.0.1)") parser.add_argument("--port", type=int, default=11338, help="Port to bind (default: 11338)") parser.add_argument("--path", default="/mcp", help="MCP endpoint path (default: /mcp)") args = parser.parse_args() print(f"[IDA-MCP-HTTP] Starting HTTP proxy at http://{args.host}:{args.port}{args.path}") print(f"[IDA-MCP-HTTP] Reusing shared server from proxy/_server.py") if start_http_proxy(args.host, args.port, args.path): print(f"[IDA-MCP-HTTP] Server started successfully") try: while is_http_proxy_running(): time.sleep(1) except KeyboardInterrupt: print("\n[IDA-MCP-HTTP] Shutting down...") stop_http_proxy() else: print("[IDA-MCP-HTTP] Failed to start server") sys.exit(1)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jelasin/IDA-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server