# MCP Gateway Plugin

`McpGatewayPlugin` activates the MCP Gateway internal routes on the runtime
router: the OAuth authorization server, upstream connection management,
well-known metadata endpoints, and the read-only
[MCP Server Registry](../mcp-gateway/server-registry.mdx). When no MCP-related
policy is present, the plugin registers no OAuth routes — it still records
`plugin.mcp-gateway` feature usage on construction so gateway adoption is
visible in telemetry.

Importing from `@zuplo/runtime/mcp-gateway` is the opt-in: the runtime core
doesn't depend on MCP Gateway code until the plugin is added.

## Registration

Register the plugin in `modules/zuplo.runtime.ts`:

```ts title="modules/zuplo.runtime.ts"
import { RuntimeExtensions } from "@zuplo/runtime";
import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway";

export function runtimeInit(runtime: RuntimeExtensions) {
  runtime.addPlugin(new McpGatewayPlugin());
}
```

The plugin accepts an optional configuration object. All options have defaults,
so the no-argument form works for most projects.

```ts title="modules/zuplo.runtime.ts"
import { RuntimeExtensions } from "@zuplo/runtime";
import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway";

export function runtimeInit(runtime: RuntimeExtensions) {
  runtime.addPlugin(
    new McpGatewayPlugin({
      basePath: "/__zuplo",
      registry: {
        enabled: true,
        path: "/mcp-registry",
      },
    }),
  );
}
```

## Options

| Option     | Type                        | Default      | Description                                                                                                                      |
| ---------- | --------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `basePath` | `string`                    | `"/__zuplo"` | Base path for all gateway internal routes (OAuth, well-known, registry). Must start with `/` and can't collide with route paths. |
| `registry` | `McpGatewayRegistryOptions` | See below    | Configures the read-only [MCP Server Registry](../mcp-gateway/server-registry.mdx).                                              |

### `basePath`

The base path prefixes every internal URL the gateway serves — OAuth endpoints
(`/oauth/*`), well-known metadata (`/.well-known/*`), and the registry mount
(`/mcp-registry`). With the default `"/__zuplo"`, the token endpoint lives at
`/__zuplo/oauth/token` and the registry at `/__zuplo/mcp-registry`.

```ts
new McpGatewayPlugin({ basePath: "/internal" });
// OAuth token:  /internal/oauth/token
// Registry:     /internal/mcp-registry
```

### `registry`

Configures the read-only MCP Server Registry API (v0.1) that advertises the
gateway's registered MCP routes. See
[MCP Server Registry](../mcp-gateway/server-registry.mdx) for the endpoint
reference and behavior.

| Option    | Type      | Default                     | Description                                                                                                                                               |
| --------- | --------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled` | `boolean` | `true`                      | Set to `false` to disable the registry entirely. No registry routes are registered when disabled.                                                         |
| `path`    | `string`  | `"{basePath}/mcp-registry"` | Absolute URL path where the registry API mounts. Registry endpoints live below this path (for example, `{path}/v0.1/servers`). Validated like `basePath`. |

The registry path is validated with the same schema as `basePath`, plus a
boot-time guard that rejects mounts shadowing the OAuth discovery
(`/.well-known`) or authorize wildcard routes.

:::note

When `registry.enabled` is `false`, the path collision guard is skipped — a
disabled registry registers no routes and must not fail boot over a mount that
will never exist.

:::

#### Default mount

With the default `basePath` of `"/__zuplo"` and no `registry` override, the
registry is served at:

```text
/__zuplo/mcp-registry/v0.1/servers
```

#### Custom registry path

Set `registry.path` to mount the registry independently of `basePath`:

```ts
new McpGatewayPlugin({
  registry: { path: "/registry" },
});
// Registry:  /registry/v0.1/servers
// OAuth:     /__zuplo/oauth/token  (basePath unchanged)
```

#### Disabled registry

Turn off the registry if you don't need server discovery:

```ts
new McpGatewayPlugin({
  registry: { enabled: false },
});
```

## Related

- [MCP Server Registry](../mcp-gateway/server-registry.mdx) — the read-only
  registry API the plugin serves by default.
- [Set up an MCP Gateway](../mcp-gateway/code-config/overview.mdx) — the how-to
  that puts this plugin into a project with policies and routes.
- [How the MCP Gateway works](../mcp-gateway/how-it-works.mdx) — the
  architecture and request lifecycle.
- [Gateway reference](../mcp-gateway/reference.mdx) — the full URL catalog,
  default TTLs, and configuration constants.
