# 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` with an MCP route at `/mcp/linear-v1`, the public
route is `https://my-gateway.zuplo.dev/mcp/linear-v1`.

### 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 route'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 an MCP route. 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 MCP route 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 the upstream the requested MCP route 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                                                                                        |
| ------------------------------------------------------ | -------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `/<route-path>` (one per upstream, e.g. `/mcp/linear`) | `GET` returns `405`; `POST` proxies upstream | The MCP route endpoints themselves. AI clients connect here. Path is set in `routes.oas.json`. |

## 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 MCP route. |

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 MCP routes

| 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`:

```jsonc
{
  "compatibilityDate": "2026-03-01",
}
```

See [Compatibility dates](./code-config/compatibility-dates.mdx).

## 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 route URL pattern

Each MCP route exposes a stable public URL:

```
https://<gateway-origin>/<route-path>
```

- `<gateway-origin>` is your Zuplo deployment URL (for example
  `https://my-gateway.zuplo.dev`) or your custom domain.
- `<route-path>` is the path set in `config/routes.oas.json` for the route — for
  example `/mcp/linear-v1`. The convention is `/mcp/<provider>-v<n>`, but any
  path works.

## Related references

- [How it works](./how-it-works.mdx) — request lifecycle and architecture.
- [Troubleshooting](./troubleshooting.mdx) — symptoms, causes, and fixes for the
  issues these defaults most often cause.
- [MCP authorization spec (2025-11-25)](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization)
  — the canonical reference for the auth model the gateway implements.
- [MCP Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
  — the transport semantics the gateway uses.
