Gateway reference
This page is the lookup table for facts about the gateway — every URL it exposes, every default TTL, the OAuth scope it issues, the headers it honors, and the configuration constants you need to set.
Public URLs
The URLs below are all relative to the gateway origin. For a project deployed to
https://my-gateway.zuplo.dev, the Linear example route is
https://my-gateway.zuplo.dev/v1/mcp/linear-prod.
Well-known metadata
| Path | Methods | Purpose |
|---|---|---|
/.well-known/oauth-authorization-server | GET, OPTIONS | RFC 8414 Authorization Server metadata for the gateway. Issuer is the gateway origin. |
/.well-known/oauth-authorization-server/{routePath*} | GET, OPTIONS | Per-route AS metadata. The issuer is rebound to the Virtual MCP's canonical URI, and authorization_endpoint points at /oauth/authorize/{routePath}. |
/.well-known/oauth-protected-resource/{routePath*} | GET, OPTIONS | RFC 9728 Protected Resource Metadata for a Virtual MCP. Lists resource, resource_name, authorization_servers, bearer_methods_supported, scopes_supported, and mcp_protocol_version. |
/.well-known/oauth-client/{connection} | GET | OAuth Client ID Metadata Document the gateway hosts to identify itself to an upstream provider. Requires the ?authProfileId= query parameter. |
These routes are CORS-permissive (Access-Control-Allow-Origin: *) because
spec-compliant browser-resident MCP clients fetch them cross-origin.
OAuth endpoints
| Path | Methods | Purpose |
|---|---|---|
/oauth/register | POST | RFC 7591 Dynamic Client Registration. Supports none, client_secret_basic, client_secret_post, and private_key_jwt token-endpoint auth methods. DCR clients expire after 90 days. |
/oauth/authorize | GET | Gateway-wide authorization endpoint. Requires the resource parameter unless exactly one Virtual MCP is configured. |
/oauth/authorize/{routePath*} | GET | Per-route authorization endpoint. The resource is implicit from the path. |
/oauth/callback | GET | Browser-login callback from the configured identity provider. Renders the consent page. |
/oauth/setup | GET, POST | Consent screen. Lists every upstream the requested Virtual MCP depends on. POST accepts decision=continue / approve / cancel. |
/oauth/token | POST | RFC 6749 token endpoint. Supports authorization_code and refresh_token grants. |
/oauth/revoke | POST | RFC 7009 revocation endpoint. Accepts public-client revocations without authentication. |
/oauth/dev-login | GET | Loopback-only dev shortcut. Returns 403 over non-loopback addresses. |
Upstream connection endpoints
| Path | Methods | Purpose |
|---|---|---|
/auth/connections/{connection}/connect | GET | Browser entry to the upstream OAuth flow. With redirect=true, returns a 302 to the upstream /authorize; otherwise returns 428 with the connect-required payload. |
/auth/connections/{connection}/callback | GET | Upstream OAuth callback. Renders a success or failure page. |
Customer-defined MCP routes
| Path | Methods | Purpose |
|---|---|---|
/v1/mcp/{slug} (one per Virtual MCP) | GET returns 405; POST proxies upstream | The Virtual MCP endpoints themselves. AI clients connect here. |
OAuth scopes
The gateway issues exactly one scope on access tokens:
| Scope | Meaning |
|---|---|
mcp:tools | Permission to call MCP methods (tools/call, tools/list, prompts/get, resources/read, and so on) on the bound Virtual MCP. |
DCR requests that include any other scope value are rejected with
invalid_client_metadata. Token responses always include scope: "mcp:tools".
Default TTLs
| What | Default | Where to override | Rationale |
|---|---|---|---|
Browser session (__mcp_session) | 8 hours | browserLogin.sessionTtlSeconds on the OAuth policy. | Aligns with a typical workday so users don't re-authenticate mid-session. |
| Access token | 15 minutes | gateway.accessTokenTtlSeconds on the OAuth policy. | Short window contains the blast radius of a leaked token. The token endpoint upper-bounds this by the grant's remaining lifetime, so refresh-rotated tokens shorten as the grant ages. |
| Refresh token / grant | ~10 years | gateway.refreshTokenTtlSeconds on the OAuth policy. | Downstream refresh grants are gateway client sessions, not upstream OAuth token lifetimes. The default is intentionally long so the gateway doesn't impose a shorter session bound than the upstream provider's refresh-token policy already does. |
| DCR-registered client | 90 days | Not configurable. | Encourages clients to use CIMD where possible; stale DCR clients age out automatically. |
| Authorization code | 60 seconds | Not configurable. | OAuth 2.1 recommendation. |
oauth_authorize state | 15 minutes | browserLogin.stateTtlSeconds. | Window between /oauth/authorize and /oauth/callback. |
Headers
Required on requests to Virtual MCPs
| Header | Required | Notes |
|---|---|---|
Authorization: Bearer <token> | Yes (after initial 401) | Opaque access token issued by /oauth/token. Tokens in query strings are rejected. |
Accept: application/json, text/event-stream | Yes | Per the Streamable HTTP transport spec. The gateway forwards the body as-is. |
MCP-Protocol-Version: 2025-11-25 | Yes after initialize | Per the MCP spec. The gateway tracks the current MCP protocol revision. |
Honored when present
| Header | Purpose |
|---|---|
Host | Source for the gateway's issuer URL in AS metadata. |
X-Forwarded-Host | Used when behind a reverse proxy or custom domain that rewrites Host. |
If the issuer in your AS metadata document looks wrong (for example,
https://*.zuplosite.com instead of your custom domain), check that your proxy
or CDN propagates one of those headers correctly.
Stripped before upstream
Inbound auth headers don't leak to the upstream — the gateway sets its own
upstream Authorization header.
Compatibility date
MCP Gateway features require compatibilityDate >= 2026-03-01 in zuplo.jsonc:
Code
See Compatibility dates.
Authorization Server metadata extensions
In addition to the standard RFC 8414 / OIDC discovery fields, the gateway publishes a vendor extension:
| Field | Type | Values | Purpose |
|---|---|---|---|
x-zuplo-browser-login-kind | string | "federated_oidc", "local_dev" | Lets client tooling special-case local development configurations (which use /oauth/dev-login and a loopback IdP). |
Public client URL pattern
Each Virtual MCP exposes a stable public URL:
Code
<gateway-origin>is your Zuplo deployment URL (for examplehttps://my-gateway.zuplo.dev) or your custom domain.<slug>matches the Virtual MCP slug configured in the Portal or set in the route's path inroutes.oas.json. Slugs are lowercase with hyphens.
Related references
- How it works — request lifecycle and architecture.
- Troubleshooting — symptoms, causes, and fixes for the issues these defaults most often cause.
- MCP authorization spec (2025-11-25) — the canonical reference for the auth model the gateway implements.
- MCP Streamable HTTP transport — the transport semantics the gateway uses.