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

# Connect to MCPs

> Manage MCP connections with a simple REST API - OAuth, tokens, and sessions handled for you.

Smithery gives you a simple REST interface for connecting to MCP servers. Instead of implementing the MCP protocol directly, handling OAuth flows, and managing credentials yourself, Smithery handles all of it for you.

The auth and credential layer is powered by the open-source [agent.pw](https://agent.pw).

## Why Smithery?

Smithery lets you add MCP server integrations to your app without managing the complexity yourself:

* **Zero OAuth configuration** — No redirect URIs, client IDs, or secrets to configure. Smithery maintains OAuth apps for popular integrations.
* **Automatic token refresh** — Tokens refresh automatically before expiry. If a refresh fails, the connection status changes to `auth_required`.
* **Secure credential storage** — Credentials are encrypted and write-only. They can be used to make requests but never read back.
* **Stateless for you** — Smithery manages connection lifecycle. Make requests without worrying about reconnects, keepalives, or session state.
* **Scoped service tokens** — Mint short-lived tokens for browser or mobile clients to call tools directly, scoped to specific users and namespaces.

## Quick Start

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # 1. Log in to Smithery
    smithery auth login

    # 2. Connect to the Exa search server
    smithery mcp add exa --id exa

    # 3. List available tools
    smithery tool list exa

    # 4. Call a tool
    smithery tool call exa search '{"query": "latest news about MCP"}'
    ```
  </Tab>

  <Tab title="AI SDK" icon="sparkles">
    ```bash theme={null}
    npm install @smithery/api @ai-sdk/mcp ai @ai-sdk/anthropic
    ```

    ```typescript theme={null}
    import { createMCPClient } from '@ai-sdk/mcp';
    import { generateText } from 'ai';
    import { anthropic } from '@ai-sdk/anthropic';
    import { createConnection } from '@smithery/api/mcp';

    const { transport } = await createConnection({
      mcpUrl: 'https://mcp.exa.ai',
    });

    const mcpClient = await createMCPClient({ transport });
    const tools = await mcpClient.tools();

    const { text } = await generateText({
      model: anthropic('claude-sonnet-4-20250514'),
      tools,
      prompt: 'Search for the latest news about MCP.',
    });

    await mcpClient.close();
    ```
  </Tab>

  <Tab title="MCP TypeScript SDK" icon="braces">
    ```bash theme={null}
    npm install @smithery/api @modelcontextprotocol/sdk
    ```

    ```typescript theme={null}
    import { Client } from '@modelcontextprotocol/sdk/client/index.js';
    import { createConnection } from '@smithery/api/mcp';

    const { transport } = await createConnection({
      mcpUrl: 'https://mcp.exa.ai',
    });

    // Connect using the MCP SDK Client
    const mcpClient = new Client({ name: 'my-app', version: '1.0.0' });
    await mcpClient.connect(transport);

    // Use the MCP SDK's ergonomic API
    const { tools } = await mcpClient.listTools();
    const result = await mcpClient.callTool({
      name: 'search',
      arguments: { query: 'latest news about MCP' }
    });
    ```
  </Tab>

  <Tab title="Typed SDK" icon="package">
    <Warning>
      Typed SDKs are in preview. Breaking changes may happen without notice.
    </Warning>

    Every MCP server published on Smithery gets a typed TypeScript SDK generated from its tool and trigger schemas. Use it when you already have a live Smithery connection and want typed tool calls instead of string-based `callTool` calls. Create or reuse a connection first, then pass its `namespace` and `connectionId`.

    ```bash theme={null}
    npm install https://pkg.smithery.ai/exa
    ```

    ```typescript theme={null}
    import { Exa } from '@smithery/exa';

    const exa = new Exa({
      namespace: 'my-app',
      connectionId: 'exa',
    });

    const result = await exa.tools.search({
      query: 'latest news about MCP',
    });
    ```

    For tools with output schemas, the typed SDK returns `structuredContent` typed from that schema. If a server returns structured data as a JSON or XML string, the SDK parses it first, converts XML into JSON-shaped data, and validates the parsed value before returning the result.

    SDKs are served from `pkg.smithery.ai` paths shaped like `namespace/slug`. The class name is the PascalCase form of the slug, so `smithery-ai/github` exports `Github`; if there is no slug, the namespace becomes the class name, like `exa` exporting `Exa`.

    ```typescript theme={null}
    // Use callTool when a tool was added after your SDK was generated.
    const result = await exa.callTool('search', { query: 'latest news about MCP' });
    ```
  </Tab>
</Tabs>

## Servers with Configuration

Some MCP servers require configuration like API keys or project IDs. How you pass each config value depends on the server's schema — some values go as **headers** (typically API keys), while others go as **query parameters** in the MCP URL.

Check the server's page on [smithery.ai](https://smithery.ai) to see what configuration it requires and where each value should go.

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # Add a server with config (API key as header, project ID as query param)
    smithery mcp add \
      '@browserbasehq/mcp-browserbase?browserbaseProjectId=your-project-id' \
      --id my-browserbase \
      --headers '{"browserbaseApiKey": "your-browserbase-api-key"}'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    import Smithery from '@smithery/api';
    import { createConnection } from '@smithery/api/mcp';

    const smithery = new Smithery();

    // 1. Create a connection with the server's config
    //    - API keys go in `headers`
    //    - Other config goes as query params in `mcpUrl`
    const conn = await smithery.connections.set('my-browserbase', {
      namespace: 'my-app',
      mcpUrl: 'https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id',
      headers: {
        'browserbaseApiKey': 'your-browserbase-api-key',
      },
    });
    // conn.status.state === "connected" — ready to use immediately

    // 2. Get a transport for the connection
    const { transport } = await createConnection({
      client: smithery,
      namespace: 'my-app',
      connectionId: conn.connectionId,
    });
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST "https://smithery.run/my-app" \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "mcpUrl": "https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id",
        "headers": {
          "browserbaseApiKey": "your-browserbase-api-key"
        }
      }'
    ```
  </Tab>
</Tabs>

Unlike OAuth-based servers that return `auth_required`, servers configured with API keys return `connected` immediately when all required fields are provided upfront. If any required fields are missing, the connection returns `input_required` with the config schema and missing fields — see [Handling Configuration](#handling-configuration-input_required) below.

<Note>
  Each server's config schema specifies whether a field is passed as a **header** or **query parameter** via the `x-from` metadata. See [Session Configuration](/docs/build/session-config) for details on how servers declare their config transport.
</Note>

## Multi-User Setup

When your agent serves multiple users, you'll need to track which connections belong to which user. Use the `metadata` field to associate connections with your users, then filter by metadata to retrieve a specific user's connections.

### 1. Create a Connection for a User

When a user wants to connect an integration (e.g., GitHub), create a connection with their `userId` in metadata:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery mcp add github \
      --id user-123-github \
      --name "GitHub" \
      --metadata '{"userId": "user-123"}'

    # If OAuth is required, the CLI outputs the auth URL:
    # → auth_required
    # → https://auth.smithery.ai/...
    # Visit the URL to authorize
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const conn = await smithery.connections.set('user-123-github', {
      namespace: 'my-app',
      mcpUrl: 'https://github.run.tools',
      name: 'GitHub',
      metadata: { userId: 'user-123' }
    });

    if (conn.status.state === 'auth_required') {
      // Redirect user to the hosted Smithery setup flow
      redirect(conn.status.setupUrl);
    }
    ```
  </Tab>
</Tabs>

### 2. List a User's Connections

When your agent needs to know what tools are available for a user, list their connections:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery mcp list --metadata '{"userId": "user-123"}'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const result = await smithery.connections.list('my-app', {
      metadata: { userId: 'user-123' }
    });

    // Show the user their connected integrations
    for (const conn of result.connections) {
      console.log(`${conn.name}: ${conn.status.state}`);
    }
    ```
  </Tab>
</Tabs>

### 3. Use Tools Across Connections

Create MCP clients for each connection and aggregate their tools:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # List tools for a connection
    smithery tool list user-123-github

    # Call a tool
    smithery tool call user-123-github search_repositories \
      '{"query": "mcp"}'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const allTools = [];

    for (const conn of result.connections) {
      if (conn.status.state === 'connected') {
        const { transport } = await createConnection({
          namespace: 'my-app',
          connectionId: conn.connectionId,
        });
        const client = await createMCPClient({ transport });
        allTools.push(...await client.tools());
      }
    }

    // Now your agent has tools from all the user's connected integrations
    const { text } = await generateText({
      model: anthropic('claude-sonnet-4-20250514'),
      tools: allTools,
      prompt: userMessage,
    });
    ```
  </Tab>
</Tabs>

Or skip the iteration entirely and hand a [single namespace URL](#namespace-mcp-endpoint) to an MCP client.

## Namespace MCP Endpoint

A namespace URL bundles all of a namespace's connections behind one MCP endpoint, so the same set of tools is portable across clients (Claude.ai, Cursor, ChatGPT, MCP Inspector) without configuring each connection in each app:

```text theme={null}
https://mcp.smithery.run/{namespace}
```

Tool names come back prefixed with their connection ID — `notion-personal.search`, `user-123-github.search_repositories` — so they stay unique. On `tools/call`, Connect strips the prefix and forwards to the matching connection.

To restrict the URL to one user's connections, mint a [service token](#service-tokens) scoped to `metadata.userId` — same metadata model as [Multi-User Setup](#multi-user-setup). The endpoint also advertises protected-resource metadata, so MCP clients run the [OAuth flow](#oauth-flow) on their own without extra wiring.

## Core Concepts

### Namespaces

A namespace is a globally unique identifier that groups your connections. Create one namespace per application or environment (e.g., `my-app`, `my-app-staging`). If you don't specify a namespace, the SDK uses your first existing namespace or creates one automatically.

### Connections

A connection is a long-lived session to an MCP server that persists until terminated. Each connection:

* Has a `connectionId` (developer-defined or auto-generated)
* Stores credentials securely (write-only—credentials can never be read back, only used to execute requests)
* Can include custom `metadata` for filtering (e.g., `userId` to associate connections with your users)
* Returns `serverInfo` with the MCP server's name and version

<Accordion title="createConnection Options">
  | Option         | Type        | Description                                                                                  |
  | -------------- | ----------- | -------------------------------------------------------------------------------------------- |
  | `client`       | `Smithery?` | The Smithery client instance. If not provided, auto-created using `SMITHERY_API_KEY` env var |
  | `mcpUrl`       | `string?`   | The MCP server URL. Required when `connectionId` is not provided                             |
  | `namespace`    | `string?`   | If omitted, uses first existing namespace or creates one                                     |
  | `connectionId` | `string?`   | If omitted, an ID is auto-generated                                                          |

  Returns a SmitheryConnection object (transport, connectionId, url).
  Throws `SmitheryAuthorizationError` if OAuth authorization is required (see [Handling Authorization](#handling-authorization)).
</Accordion>

### Connection Status

When you create or retrieve a connection, it includes a `status` field:

| Status           | Description                                                                                                                           |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `connected`      | Connection is ready to use                                                                                                            |
| `auth_required`  | OAuth authorization needed. Includes `setupUrl`                                                                                       |
| `input_required` | Server needs configuration (e.g., API keys). Includes `setupUrl`, `http` (the config schema), and `missing` (fields not yet provided) |
| `error`          | Connection failed. Includes error `message`                                                                                           |

### Authentication

Smithery uses two authentication methods:

| Token             | Use Case                | Access                                |
| ----------------- | ----------------------- | ------------------------------------- |
| **API Key**       | Backend only            | Full namespace access                 |
| **Service Token** | Browser, mobile, agents | Scoped access to specific connections |

Get your API key from [smithery.ai/account/api-keys](https://smithery.ai/account/api-keys).

<Warning>
  Never expose your API key to untrusted clients or agents. Use scoped service tokens for browser and mobile apps.
</Warning>

### OAuth Flow

When an MCP server requires OAuth:

1. Create a connection—the response status will be `auth_required` with a hosted `setupUrl`
2. Redirect the user to `setupUrl`
3. User completes OAuth with the upstream provider (e.g., GitHub)
4. User is redirected back to your app
5. The connection is now ready—subsequent requests will succeed

You don't need to register OAuth apps, configure redirect URIs, or handle token exchange. Smithery manages the OAuth relationship with upstream providers and stores credentials securely on your behalf.

### Handling Authorization

When you need to send a user through OAuth, prefer creating or updating the connection first and redirecting to the hosted `setupUrl`. That gives you a stable `connectionId` to retry with after the user returns to your app.

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # Connect to a server that requires OAuth
    smithery mcp add github

    # If auth is required, the CLI outputs the setup URL:
    # → auth_required
    # → https://auth.smithery.ai/...
    # → connection_id: abc-123-github
    # Visit the URL to authorize, then retry
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const conn = await smithery.connections.set('abc-123-github', {
      namespace: 'my-app',
      mcpUrl: 'https://github.run.tools',
    });

    if (conn.status?.state === 'auth_required') {
      redirect(conn.status.setupUrl);
    }

    // Save conn.connectionId and retry with it after the user returns
    ```
  </Tab>
</Tabs>

After the user completes authorization and returns to your app, retry with the saved `connectionId`:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # After authorization, the connection is ready
    smithery tool list abc-123-github
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { transport } = await createConnection({
      connectionId: savedConnectionId,
    });

    const mcpClient = await createMCPClient({ transport });
    const tools = await mcpClient.tools();
    ```
  </Tab>
</Tabs>

### Handling Configuration (`input_required`)

When a server requires configuration that wasn't provided, the connection returns `input_required` with:

* **`setupUrl`** — a hosted Smithery setup page you can redirect the user to instead of building your own form
* **`http`** — the config schema (headers and query parameters the server accepts)
* **`missing`** — which fields still need to be provided

In a TTY terminal, the CLI prompts for missing values automatically. Otherwise, provide them explicitly:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # Interactive: CLI prompts for missing fields
    smithery mcp add browserbase --id my-browserbase

    # Non-interactive: pass config upfront
    smithery mcp add \
      'https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id' \
      --id my-browserbase \
      --headers '{"browserbaseApiKey": "your-api-key"}'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const conn = await smithery.connections.set('my-browserbase', {
      namespace: 'my-app',
      mcpUrl: 'https://mcp.browserbase.com/mcp',
    });

    if (conn.status.state === 'input_required') {
      // Option 1: redirect(conn.status.setupUrl)
      // Option 2: render your own form from conn.status.http
      // conn.status.http has the config schema, conn.status.missing lists unfilled fields
      const updated = await smithery.connections.set('my-browserbase', {
        namespace: 'my-app',
        mcpUrl: 'https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id',
        headers: { browserbaseApiKey: 'your-api-key' },
      });
    }
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    # Create — returns input_required if config is missing
    curl -X PUT "https://smithery.run/my-app/my-browserbase" \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"mcpUrl": "https://mcp.browserbase.com/mcp"}'

    # Update with required config (same endpoint, PUT is an upsert)
    curl -X PUT "https://smithery.run/my-app/my-browserbase" \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "mcpUrl": "https://mcp.browserbase.com/mcp?browserbaseProjectId=your-project-id",
        "headers": { "browserbaseApiKey": "your-api-key" }
      }'
    ```
  </Tab>
</Tabs>

<Note>
  MCP requests to a connection in `input_required` state will be rejected until the required configuration is provided. While `input_required`, the `mcpUrl` can be updated with query parameters as long as the host and path remain the same.
</Note>

## Service Tokens

Service tokens let you safely use Smithery from browsers, mobile apps, and AI agents without exposing your API key. Your backend mints a scoped token, then your client uses it to call tools directly.

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    smithery auth token --policy '[{
      "namespaces": "my-app",
      "resources": "connections",
      "operations": ["read", "execute"],
      "metadata": { "userId": "user-123" },
      "ttl": "1h"
    }]'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    // Create a token scoped to a specific user's connections
    const { token } = await smithery.tokens.create({
      policy: [
        {
          namespaces: 'my-app',
          resources: 'connections',
          operations: ['read', 'execute'],
          metadata: { userId: 'user-123' },
          ttl: '1h',
        },
      ],
    })

    // Send `token` to your client — safe for browser use
    ```
  </Tab>

  <Tab title="cURL" icon="globe">
    ```bash theme={null}
    curl -X POST https://api.smithery.ai/tokens \
      -H "Authorization: Bearer $SMITHERY_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": [
          {
            "namespaces": "my-app",
            "resources": "connections",
            "operations": ["read", "execute"],
            "metadata": { "userId": "user-123" },
            "ttl": "1h"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

This token can only access connections in `my-app` where `metadata.userId` matches `user-123`. Initialize the client with the token:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # Use the scoped token to call tools
    SMITHERY_API_KEY=$TOKEN smithery tool list user-123-github
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const smithery = new Smithery({ apiKey: token })

    const { transport } = await createConnection({
      client: smithery,
      namespace: 'my-app',
      connectionId: 'user-123-github',
    })
    ```
  </Tab>
</Tabs>

<Note>
  Need workspace-level scoping, read-only tokens, or token narrowing? See [Token Scoping](/docs/use/token-scoping) for the full guide.
</Note>

## Advanced

For full API documentation, see the API Reference section in the sidebar.

### Calling tools

Use the CLI or an MCP client over your connection's transport:

<Tabs>
  <Tab title="CLI" icon="terminal">
    ```bash theme={null}
    # List available tools
    smithery tool list user-123-github

    # Call a tool
    smithery tool call user-123-github search_repositories \
      '{"query": "mcp"}'
    ```
  </Tab>

  <Tab title="TypeScript" icon="braces">
    ```typescript theme={null}
    const { transport } = await createConnection({
      client: smithery,
      namespace: 'my-app',
      connectionId: 'user-123-github',
    })

    const mcpClient = await createMCPClient({ transport })
    const tools = await mcpClient.tools()
    const result = await mcpClient.callTool({
      name: 'search_repositories',
      arguments: { query: 'mcp' },
    })
    await mcpClient.close()
    ```
  </Tab>
</Tabs>
