diff --git a/src/ad_seller/interfaces/api/main.py b/src/ad_seller/interfaces/api/main.py index 26a9aec..eb57e78 100644 --- a/src/ad_seller/interfaces/api/main.py +++ b/src/ad_seller/interfaces/api/main.py @@ -17,7 +17,9 @@ from typing import Any, Optional from fastapi import Depends, FastAPI, HTTPException +from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel +from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware logger = logging.getLogger(__name__) @@ -31,6 +33,7 @@ version="1.0.0", contact={"name": "IAB Tech Lab", "url": "https://iabtechlab.com"}, license_info={"name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0"}, + root_path_in_servers=False, openapi_tags=[ {"name": "Core", "description": "Health check and API root"}, {"name": "Products", "description": "Product catalog browsing"}, @@ -65,6 +68,21 @@ # Lifecycle: start/stop background services # ============================================================================= +# Trust X-Forwarded-Proto / X-Forwarded-For from Cloud Run so that Starlette +# generates https:// redirects instead of http:// ones behind the TLS proxy. +app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*") + +# Allow all browser-based clients — buyer UIs, claude.ai, SSP dashboards, etc. +# The MCP Streamable HTTP protocol requires CORS for browser-originated requests. +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_headers=["*"], + allow_credentials=False, + expose_headers=["*"], +) + _mcp_server_ref = None diff --git a/src/ad_seller/interfaces/mcp_server.py b/src/ad_seller/interfaces/mcp_server.py index 6395d7f..30daa4e 100644 --- a/src/ad_seller/interfaces/mcp_server.py +++ b/src/ad_seller/interfaces/mcp_server.py @@ -39,6 +39,13 @@ "and interact with buyer agents. On first connection, check setup status " "and offer the guided setup wizard if configuration is incomplete." ), + # streamable_http_path="/" so that when mounted at /mcp in FastAPI the + # endpoint resolves to /mcp (not /mcp/mcp which is the default). + streamable_http_path="/", + # host="0.0.0.0" disables the auto DNS-rebinding protection that FastMCP + # applies when host is 127.0.0.1/localhost. That protection blocks requests + # from Cloud Run (Host header is the public *.run.app domain) with 421. + host="0.0.0.0", )