From 6db23b032344ff1bb586d0b4df22f406f7e16028 Mon Sep 17 00:00:00 2001 From: mavneox Date: Thu, 30 Jul 2026 10:17:38 -0500 Subject: [PATCH] Serve MCP at bare root; keep /mcp as legacy alias Canonical hosted URL becomes https://mcp.gen.pro (no path). The --http entrypoint now builds the streamable-http app at path="/" and wraps it in a tiny ASGI shim that maps /mcp (and /mcp/) onto / so every pre-existing client config keeps working. Alias, not redirect: MCP clients are not guaranteed to re-POST a JSON-RPC body across a 30x. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 6 +++--- src/gen_mcp_server/__main__.py | 21 +++++++++++++++++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 186c4f9..3e745a8 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The server runs in **two modes** from one codebase: - **Hosted (Streamable HTTP)** — for cloud agents that connect to a URL: **Manus** custom MCP, claude.ai connectors, ChatGPT. Multi-tenant — each caller sends their own PAT as `Authorization: Bearer `, served at - `https://mcp.gen.pro/mcp`. + `https://mcp.gen.pro` (bare root; `/mcp` still works as a legacy alias). ## Install (local / stdio) @@ -55,13 +55,13 @@ No install — point the agent at the hosted endpoint and authenticate with your GEN PAT as a bearer token. **Manus:** Settings → Integrations → Custom MCP Servers → Add Server -- **Server URL:** `https://mcp.gen.pro/mcp` +- **Server URL:** `https://mcp.gen.pro` - **Authentication:** Bearer token → your `gen_…` PAT **Self-host the HTTP transport:** ```bash -GEN_MCP_PORT=8080 gen-mcp-server --http # serves streamable-http on :8080/mcp +GEN_MCP_PORT=8080 gen-mcp-server --http # serves streamable-http on :8080 at `/` and `/mcp` ``` ## The 5-Step Journey diff --git a/src/gen_mcp_server/__main__.py b/src/gen_mcp_server/__main__.py index fd35a8c..4fcec04 100644 --- a/src/gen_mcp_server/__main__.py +++ b/src/gen_mcp_server/__main__.py @@ -2,7 +2,9 @@ gen-mcp-server -> stdio (default; what the PyPI/npm package ships and what Claude Code / Cursor / VS Code run) - gen-mcp-server --http -> streamable-http on 0.0.0.0:8080/mcp + gen-mcp-server --http -> streamable-http on 0.0.0.0:8080, served at + BOTH `/` (canonical: https://mcp.gen.pro) and + `/mcp` (legacy alias for existing configs) (hosted mode for Manus / claude.ai connectors / ChatGPT — fronted by Cloudflare at mcp.gen.pro) @@ -35,7 +37,22 @@ def main() -> None: args = parser.parse_args() if args.http: - mcp.run(transport="streamable-http", host=args.host, port=args.port) + import uvicorn + + # Canonical MCP endpoint is the BARE root (`{"url": "https://mcp.gen.pro"}`). + # `/mcp` (the old FastMCP-default path) stays as an alias so every client + # configured before the switch keeps working — alias, not redirect, because + # MCP clients are not guaranteed to re-POST a JSON-RPC body across a 30x. + app = mcp.http_app(path="/") + + async def dual_path_app(scope, receive, send): # ASGI wrapper + if scope["type"] == "http" and scope.get("path") in ("/mcp", "/mcp/"): + scope = dict(scope) + scope["path"] = "/" + scope["raw_path"] = b"/" + await app(scope, receive, send) + + uvicorn.run(dual_path_app, host=args.host, port=args.port) else: # stdio: PAT must be present in env (fail fast, like the TS server). if not os.environ.get("GEN_API_KEY"):