> ## Documentation Index
> Fetch the complete documentation index at: https://smithery.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Session Configuration

> Accept API keys, settings, and preferences from users connecting to your MCP server.

## Overview

Most MCP servers need user-provided values like API keys, preferences, or settings. How these values reach your server depends on how it's deployed:

| Server Type       | How Users Provide Config         |
| ----------------- | -------------------------------- |
| **Remote (HTTP)** | Query parameters or HTTP headers |
| **Local (stdio)** | Command-line arguments           |

When you define a configuration schema, Smithery automatically:

* Generates an OAuth UI form for remote servers
* Passes values to your server in the appropriate format
* Validates inputs and applies defaults

<Warning>
  Configuration schemas are limited to **20 fields** and **1KB total size**. Keep schemas focused on essential settings.
</Warning>

## Defining Your Schema

<Tabs>
  <Tab title="TypeScript" icon="braces">
    Export a `configSchema` using Zod to declare what configuration your server accepts:

    ```typescript theme={null}
    // src/index.ts
    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { z } from "zod/v4";
    import type { ServerContext } from "@smithery/sdk";

    export const configSchema = z.object({
      apiKey: z.string()
        .meta({ "x-from": { header: "x-api-key" } })
        .describe("Your API key"),
      model: z.string().default("gpt-4").describe("Model to use"),
      temperature: z.number().min(0).max(1).default(0.7).describe("Temperature"),
    });

    export default function createServer({
      config,
    }: ServerContext<z.infer<typeof configSchema>>) {
      const server = new McpServer({
        name: "My Server",
        version: "1.0.0",
      });

      // Access user-provided values
      console.log(`API Key: ${config.apiKey}`);
      console.log(`Model: ${config.model}`);

      return server.server;
    }
    ```

    Smithery extracts this schema automatically — no additional configuration needed.
  </Tab>

  <Tab title="JSON Schema" icon="globe">
    For URL-published servers deployed via CLI, use JSON Schema with the `x-from` extension:

    ```json theme={null}
    {
      "type": "object",
      "properties": {
        "apiKey": {
          "type": "string",
          "title": "API Key",
          "x-from": { "header": "x-api-key" }
        },
        "model": {
          "type": "string",
          "title": "Model",
          "default": "gpt-4"
        }
      },
      "required": ["apiKey"]
    }
    ```

    See [Publish via CLI](/docs/build/publish#cli-advanced) for how to deploy with a config schema.
  </Tab>
</Tabs>

## Config Transport (`x-from` and `x-to`)

The `x-from` and `x-to` extensions control how config values flow through the gateway:

### `x-from` — Where Smithery reads config

Specifies where Smithery looks for the value when a user connects:

```typescript theme={null}
z.string().meta({
  "x-from": { header: "x-api-key" }  // Read from header
})

z.string().meta({
  "x-from": { query: "model" }  // Read from query param
})
```

**Default:** If no `x-from` is specified, defaults to `{ query: "<propertyName>" }`.

### `x-to` — Where Smithery sends config to upstream

Specifies how Smithery forwards the value to your upstream server. Use this when your server expects a different header name than what clients provide:

```typescript theme={null}
z.string().meta({
  "x-from": { header: "api-key" },      // Client sends: api-key header
  "x-to": { header: "Authorization" }   // Upstream receives: Authorization header
})
```

This is useful when:

* Your upstream server expects an `Authorization` header, but you can't use `authorization` as `x-from` (it's reserved for Smithery OAuth)
* You want to rename headers for compatibility with existing APIs
* You need to map user-friendly parameter names to technical header names

**Default:** If no `x-to` is specified, values are forwarded using the same location as `x-from`.

### Example: PostHog API Key

```typescript theme={null}
export const configSchema = z.object({
  posthogApiKey: z.string()
    .meta({
      "x-from": { header: "posthog-api-key" },  // Client provides this header
      "x-to": { header: "Authorization" }       // PostHog expects Authorization
    })
    .describe("Your PostHog API key"),
});
```

With this config:

* Clients connect with header `posthog-api-key: sk-xxx`
* Your server receives header `Authorization: sk-xxx`

### Type Support

Only simple types support `x-from`:

* `string`
* `number`
* `boolean`

Nested objects and arrays are not supported — only flat schemas are allowed.

### Reserved Headers

The following headers cannot be used as `x-from` sources:

* `authorization` — Used for Smithery OAuth
* `cookie` — Reserved for session management
* `cf-*` — Cloudflare infrastructure headers
* `smithery-*` — Internal service headers

<Note>
  These restrictions only apply to `x-from`. You can use any header name (including `Authorization`) in `x-to` to forward values to your upstream server.
</Note>

## How Configuration Reaches Your Server

<Tabs>
  <Tab title="URL" icon="globe">
    For URL-published servers, Smithery Gateway passes through all query parameters and headers to your upstream server.

    ```
    GET /mcp?apiKey=sk-xxx&model=gpt-4
    x-api-key: sk-xxx
    ```

    Your server receives headers and query params directly — Smithery proxies them as-is.
  </Tab>

  <Tab title="Local" icon="terminal">
    For local servers, Smithery translates the configuration schema into command-line arguments:

    ```bash theme={null}
    my-server --api-key=sk-xxx --model=gpt-4 --temperature=0.7
    ```

    The schema field names are converted to kebab-case flags automatically. Your `createServer` function receives the parsed `config` object.
  </Tab>
</Tabs>

## Type Coercion

Since query parameters, headers, and CLI arguments are strings, Smithery automatically coerces values:

| Schema Type | Coercion                                               |
| ----------- | ------------------------------------------------------ |
| `string`    | No coercion                                            |
| `number`    | `Number(value)` — fails if non-numeric                 |
| `boolean`   | `"true"` / `"1"` → `true`, `"false"` / `"0"` → `false` |

## Best Practices

<Accordion title="Schema Design">
  * **Use clear descriptions** — These become form labels and help text
  * **Set sensible defaults** — Minimize required fields
  * **Use enums for fixed options** — Creates dropdown menus in the UI
  * **Keep required fields minimal** — Only require what's essential
</Accordion>

<Accordion title="Security">
  * **Use headers for secrets** — Configure `"x-from": { header: "x-api-key" }` for API keys
  * **Never log sensitive values** — Treat keys and tokens as secrets
  * **Validate server-side** — Don't rely solely on client validation
</Accordion>

## Troubleshooting

<Accordion title="Configuration not detected?">
  * Export `configSchema` from the same file as `createServer`
  * Ensure schema is a valid Zod object
</Accordion>

<Accordion title="Type errors?">
  * Accept `{ config }` in your `createServer` function
  * Use `z.infer<typeof configSchema>` for typing
</Accordion>

## Common Questions

<Accordion title="Can users change configuration mid-session?">
  No — configuration is bound at connection time. A new connection is needed for different settings.
</Accordion>

<Accordion title="Can all fields be optional?">
  Yes — use `.optional()` or provide `.default()` values.
</Accordion>

<Accordion title="Where can I see a server's configuration?">
  View the API tab on any server's page on Smithery.
</Accordion>

## See Also

* [Publish](/docs/build/publish) — Publish your MCP on Smithery
