> ## Documentation Index
> Fetch the complete documentation index at: https://wundergraphinc-ahmet-eng-9903-mcp-custom-scalars-produce-un.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> Complete reference for all MCP Gateway configuration options, including session handling, storage providers, and environment variables.

## Basic Configuration

To enable MCP in your Cosmo Router, add the following to your `config.yaml`:

```yaml theme={"system"}
mcp:
  enabled: true
  server:
    listen_addr: 'localhost:5025'
  graph_name: 'my-graph'
  exclude_mutations: true
  storage:
    provider_id: 'mcp'

storage_providers:
  file_system:
    - id: 'mcp'
      path: 'operations'
```

## Configuration Options

| Option                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                            | Default          |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `enabled`                      | Enable or disable the MCP server                                                                                                                                                                                                                                                                                                                                                                                                       | `false`          |
| `server.listen_addr`           | The address and port where the MCP server will listen for requests                                                                                                                                                                                                                                                                                                                                                                     | `localhost:5025` |
| `server.base_url`              | The public base URL of the MCP server. **Required when OAuth is enabled.** Used for the RFC 9728 metadata endpoint and `resource_metadata` in `WWW-Authenticate` headers. Set this to your externally-reachable URL when behind a reverse proxy or load balancer.                                                                                                                                                                      | -                |
| `server.version`               | The version reported to MCP clients as the server version in `serverInfo`, alongside the server name derived from `graph_name`. Use this to expose your own API version to AI agents.                                                                                                                                                                                                                                                  | Router version   |
| `server.title`                 | A human-readable display name for this MCP server, reported in `serverInfo`. MCP clients show it in UIs, falling back to the machine name derived from `graph_name` when unset.                                                                                                                                                                                                                                                        | -                |
| `server.description`           | A human-readable description of this MCP server, reported in `serverInfo`.                                                                                                                                                                                                                                                                                                                                                             | -                |
| `server.discover.instructions` | Natural-language guidance for MCP clients (AI agents) on how to use this server effectively. Served in the `server/discover` response. See [Server Discovery](#server-discovery).                                                                                                                                                                                                                                                      | -                |
| `router_url`                   | Custom URL to use for the router GraphQL endpoint in MCP responses. Use this when your router is behind a proxy.                                                                                                                                                                                                                                                                                                                       | -                |
| `storage.provider_id`          | The ID of a storage provider to use for loading GraphQL operations. Only `file_system` providers are supported.                                                                                                                                                                                                                                                                                                                        | -                |
| `session.stateless`            | Whether the MCP server should operate in stateless mode. When `true`, no server-side session state is maintained between requests.                                                                                                                                                                                                                                                                                                     | `true`           |
| `graph_name`                   | The name of the graph this router exposes via MCP. Converted to kebab-case and used to build the MCP server name (`wundergraph-cosmo-<kebab-case-name>`) and for logging; it does not select a different graph. For example, `MyGraph` becomes `wundergraph-cosmo-my-graph`.                                                                                                                                                           | `mygraph`        |
| `exclude_mutations`            | Whether to exclude mutation operations from being exposed                                                                                                                                                                                                                                                                                                                                                                              | `false`          |
| `enable_arbitrary_operations`  | Enables the `execute_graphql` built-in tool, allowing clients to run arbitrary GraphQL operations beyond the pre-defined operation set.                                                                                                                                                                                                                                                                                                | `false`          |
| `expose_schema`                | Enables the `get_schema` built-in tool, exposing the full GraphQL schema to MCP clients.                                                                                                                                                                                                                                                                                                                                               | `false`          |
| `omit_tool_name_prefix`        | When enabled, MCP tool names omit the `execute_operation_` prefix. For example, `GetUser` becomes `get_user` instead of `execute_operation_get_user`. See [Tools - Omitting the Tool Name Prefix](/router/mcp/tools#omitting-the-tool-name-prefix).                                                                                                                                                                                    | `false`          |
| `scalar_mappings`              | Maps custom scalar type names to the JSON Schema type advertised in MCP tool input schemas. Allowed values: `string`, `integer`, `number`, `boolean`, `object`, `array`. Custom scalars without a mapping default to `string`. A non-nullable variable uses the mapped type alone, for example `"object"`. A nullable variable adds `"null"`, for example `["object", "null"]`. See [Custom Scalar Mappings](#custom-scalar-mappings). | -                |

For OAuth-specific configuration, see [OAuth 2.1 Authorization](/router/mcp/oauth/overview).

## Environment Variables

All MCP options can also be set via environment variables:

| Environment Variable               | Configuration Path                 |
| ---------------------------------- | ---------------------------------- |
| `MCP_ENABLED`                      | `mcp.enabled`                      |
| `MCP_SERVER_LISTEN_ADDR`           | `mcp.server.listen_addr`           |
| `MCP_SERVER_BASE_URL`              | `mcp.server.base_url`              |
| `MCP_SERVER_VERSION`               | `mcp.server.version`               |
| `MCP_SERVER_TITLE`                 | `mcp.server.title`                 |
| `MCP_SERVER_DESCRIPTION`           | `mcp.server.description`           |
| `MCP_SERVER_DISCOVER_INSTRUCTIONS` | `mcp.server.discover.instructions` |
| `MCP_ROUTER_URL`                   | `mcp.router_url`                   |
| `MCP_STORAGE_PROVIDER_ID`          | `mcp.storage.provider_id`          |
| `MCP_SESSION_STATELESS`            | `mcp.session.stateless`            |
| `MCP_GRAPH_NAME`                   | `mcp.graph_name`                   |
| `MCP_EXCLUDE_MUTATIONS`            | `mcp.exclude_mutations`            |
| `MCP_ENABLE_ARBITRARY_OPERATIONS`  | `mcp.enable_arbitrary_operations`  |
| `MCP_EXPOSE_SCHEMA`                | `mcp.expose_schema`                |
| `MCP_OMIT_TOOL_NAME_PREFIX`        | `mcp.omit_tool_name_prefix`        |
| `MCP_SCALAR_MAPPINGS`              | `mcp.scalar_mappings`              |

Map-valued options use comma-separated `key:value` pairs. For example: `MCP_SCALAR_MAPPINGS=Foo:object,BigInt:integer`.

For OAuth-related environment variables, see [OAuth Configuration Reference](/router/mcp/oauth/configuration#environment-variables).

## Custom Scalar Mappings

The router generates each tool's input schema from the variables of the GraphQL operation. Custom scalars are opaque to JSON Schema, but MCP clients require every property to declare a type. The router therefore advertises custom scalar variables as `string` by default. This matches the wire format of most opaque scalars, such as cursors, IDs, and timestamps.

GraphQL has five built-in scalars: `Int`, `Float`, `String`, `Boolean`, and `ID`. Every other scalar in your schema is a custom scalar. The examples below use two custom scalars: `scalar Foo`, whose wire format is an object, and `scalar BigInt`, whose wire format is an integer.

Use `scalar_mappings` for custom scalars whose wire format is not a string:

```yaml theme={"system"}
mcp:
  enabled: true
  scalar_mappings:
    Foo: object
    BigInt: integer
```

A mapped scalar's schema states its GraphQL nullability. A non-nullable variable, such as `$filter: Foo!`, emits the mapped type alone: `"type": "object"`. A nullable variable, such as `$filter: Foo`, emits the type with `"null"`: `"type": ["object", "null"]`.

Two behaviors help you keep mappings correct:

* On startup, the router logs a warning that lists every custom scalar that fell back to the `string` default. Non-string arguments for these scalars are rejected by input validation, so add a mapping for any scalar with a different wire format.
* A mapping with a value outside the allowed set fails router startup. A wrong schema contract is a configuration error, not a warning.

<Note>
  The router forces only GraphQL input object variables to a non-nullable `object` type at the top level. A scalar mapped to `object` is not a GraphQL input object, so it keeps its own declared nullability.
</Note>

## Storage Providers

MCP loads operations from a configured storage provider. Currently, only the `file_system` provider is supported:

```yaml theme={"system"}
storage_providers:
  file_system:
    - id: 'mcp'
      path: 'operations' # Relative to the router binary
```

Then reference this storage provider in your MCP configuration:

```yaml theme={"system"}
mcp:
  storage:
    provider_id: 'mcp'
```

A storage provider **must** be specified to load GraphQL operations. See [Storage Providers](/router/storage-providers) for more details on configuring storage providers.

## Server Discovery

The MCP server implements the `server/discover` method. This method arrived in MCP protocol version `2026-07-28` as the successor to the `initialize` handshake. Clients call it to read the supported protocol versions, capabilities, and identity in one stateless request.

The `discover.instructions` option sends natural-language guidance to MCP clients. Use it to tell AI agents how to work with your graph:

```yaml theme={"system"}
mcp:
  enabled: true
  server:
    discover:
      instructions: |
        Prefer the pre-defined operation tools over execute_graphql.
        Employee data is refreshed nightly; do not treat it as real-time.
```

The server sends the instructions to every MCP client. This covers clients that connect with `server/discover` and clients that still use the legacy `initialize` handshake.

The router advertises protocol version `2026-07-28` by default. In session-based mode (`session.stateless: false`), clients negotiate `2025-11-25` or older.

## Session Handling

The MCP server uses the Streamable HTTP transport and maintains per-session state via the `Mcp-Session-Id` header. When deploying multiple Router instances, you need **sticky sessions** to ensure all requests for a session reach the same instance.

To configure sticky sessions:

1. The Router returns a unique `Mcp-Session-Id` response header when a session is established
2. Clients must include that value in subsequent requests as the `Mcp-Session-Id` request header
3. Your load balancer or reverse proxy must route requests with the same `Mcp-Session-Id` to the same instance

For details, see your load balancer or reverse proxy documentation (e.g., [F5 NGINX Plus - MCP Session Affinity](https://community.f5.com/kb/technicalarticles/mcp-session-affinity-with-f5-nginx-plus/341961)).

## CORS

The MCP server automatically configures CORS to allow cross-origin requests from MCP clients. It sets `Access-Control-Allow-Origin: *` and allows the required MCP headers (`Mcp-Protocol-Version`, `Mcp-Session-Id`, `Authorization`, `Last-Event-ID`). The `Mcp-Session-Id` and `WWW-Authenticate` headers are exposed in responses. If you have additional CORS headers configured on the router, they are merged with the MCP-specific headers.

## Full Configuration Example

```yaml theme={"system"}
mcp:
  enabled: true
  server:
    listen_addr: 'localhost:5025'
  router_url: 'https://your-public-router-url.example.com/graphql'
  graph_name: 'my-graph'
  exclude_mutations: true
  enable_arbitrary_operations: false
  expose_schema: false
  omit_tool_name_prefix: false
  scalar_mappings:
    Foo: object
    BigInt: integer
  storage:
    provider_id: 'mcp'

storage_providers:
  file_system:
    - id: 'mcp'
      path: 'operations'
```
