""" FastMCP-style minimal MCP server for local testing (HTTP JSON-RPC 2.0). This script prefers running with FastMCP if installed; otherwise it falls back to a tiny FastAPI JSON-RPC server that implements initialize/tools.list/tools.call. Usage (fallback HTTP server): uv pip install fastapi uvicorn uvicorn examples.mcp_adapters.fastmcp_server:http_app --host 127.0.0.1 --port 8010 The MCP endpoint will be: http://127.0.0.1:8010/mcp/ If you have FastMCP server utilities available, you can replace the fallback with your real FastMCP server. """ try: # If you have a real FastMCP server implementation, import and expose here. # Example (pseudo): # from fastmcp import MCPServer, tool # ... define @tool functions ... # fastmcp_app = MCPServer(...) # Then you can provide an ASGI http_app = fastmcp_app.asgi_app() fastmcp_app = None # placeholder; fallback below except Exception: # pragma: no cover fastmcp_app = None # Fallback: FastAPI JSON-RPC 2.0 minimal server from fastapi import FastAPI, Request from fastapi.responses import JSONResponse http_app = FastAPI() def _rpc_result(result, id_): return {"jsonrpc": "2.0", "result": result, "id": id_} def _rpc_error(message, id_=None, code=-32000): return {"jsonrpc": "2.0", "error": {"code": code, "message": message}, "id": id_} @http_app.post("/mcp/") async def mcp_endpoint(request: Request): try: data = await request.json() except Exception: return JSONResponse(_rpc_error("Invalid JSON"), status_code=400) method = data.get("method") id_ = data.get("id") params = data.get("params") or {} if method == "initialize": return JSONResponse(_rpc_result({"sessionId": "demo-session"}, id_)) if method in ("tools/list", "tool/list", "tools.list"): tools = [ { "name": "echo", "description": "Echo back provided text.", "input_schema": { "type": "object", "properties": {"text": {"type": "string"}}, "required": ["text"], }, }, { "name": "add", "description": "Add two integers a and b.", "input_schema": { "type": "object", "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}}, "required": ["a", "b"], }, }, ] return JSONResponse(_rpc_result({"tools": tools}, id_)) if method in ("tools/call", "tool/call", "tools.call"): name = params.get("name") or params.get("tool") arguments = params.get("arguments") or params.get("params") or {} if name == "echo": text = arguments.get("text", "") result = {"content": [{"type": "text", "text": text}]} return JSONResponse(_rpc_result(result, id_)) if name == "add": try: a = int(arguments.get("a", 0)) b = int(arguments.get("b", 0)) result = {"content": [{"type": "text", "text": str(a + b)}]} return JSONResponse(_rpc_result(result, id_)) except Exception: return JSONResponse(_rpc_error("Invalid arguments for add", id_=id_), status_code=400) return JSONResponse(_rpc_error("Unknown tool", id_=id_), status_code=400) return JSONResponse(_rpc_error("Method not found", id_=id_), status_code=400)