Google Cloud Run
Cloud Run is the simplest target — serverless containers with built-in HTTPS, session affinity, and Secret Manager integration. Best for teams already on GCP.
Container
Cloud Run expects the container to listen on the port given by the PORT environment variable (8080 by default). Either hard-code 8080 or read PORT in your server.
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
COPY . .
RUN uv sync --frozen
ENV MCP_HTTP_PORT=8080
EXPOSE 8080
CMD ["uv", "run", "python", "server.py"]Deploy
gcloud run deploy my-mcp \
--source . \
--region us-central1 \
--allow-unauthenticated \
--session-affinity \
--set-secrets=MY_SERVICE_API_KEY=my-service-api-key:latestKey flags:
--session-affinity— required for streamable-HTTP MCP sessions. Without it, Cloud Run load-balances every request and your session breaks.--allow-unauthenticated— Cloud Run's native auth is orthogonal to your MCP's auth. Your MCP handles auth itself (forwarded bearer token, API key, etc.), so leave Cloud Run open.--set-secrets— mounts Secret Manager values as environment variables. Use this for anything your MCP reads from the environment.
Register with an agent
The deploy output includes a URL like https://my-mcp-xxxx.run.app. Register https://my-mcp-xxxx.run.app/mcp on your agent. Make sure the Sema4.ai platform has network line of sight to that URL — if you use internal-only ingress, the platform's network must be able to route to it.
Tips
- Min instances ≥ 1 if cold-start latency bothers your agent. This costs money; weigh it against per-call latency.
- Cloud Logging captures stdout — your MCP's
print()andloggingcalls land there. - Auth gatekeeper — if you need an auth proxy in front of the MCP, run Nginx as a sidecar that forwards to the Python server. This is the pattern Sema4.ai uses for its own internal MCPs.