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

# MCP servers

> Connect MCP servers and configure their tools, permissions, and authentication

[MCP (Model Context Protocol)](https://modelcontextprotocol.io) is an open standard for connecting tools to models. Add a server such as Linear, Notion, or your own internal service to an agent config, and Omnara discovers its tools and makes them available to the model.

## Declaring a server

Each entry under `mcp:` defines one server:

```yaml theme={null}
mcp:
  linear:
    url: https://mcp.linear.app/mcp
    auth:
      type: oauth
      secret_id: sec_gik7mv4qtrwz3jehcyd5n6a2bf
    permission:
      mode: always_ask
    tools:
      get_issue:
        permission:
          mode: always_allow
      delete_issue:
        enabled: false
  internal-docs:
    url: https://mcp.internal.acme.dev/mcp
    auth:
      type: bearer
      secret_id: sec_7jehcyd5n6a2bfgik7mv4qtrwz
    default_enabled: false      # opt-in: only listed tools are exposed
    tools:
      search_docs:
        enabled: true
```

| Field             | Notes                                                                                                                                                                               |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`             | The server's MCP endpoint.                                                                                                                                                          |
| `auth.type`       | `bearer` (a token in a [generic secret](/organization/secrets)), `oauth` (an `oauth_token_set` secret), or `sigv4` (an `aws_credentials` secret). Omit for unauthenticated servers. |
| `auth.secret_id`  | The `sec_…` reference. The config never contains the credential itself.                                                                                                             |
| `auth.service`    | SigV4 signing service. Required for `sigv4`.                                                                                                                                        |
| `auth.region`     | AWS signing region. Required for `sigv4`.                                                                                                                                           |
| `permission`      | Server-wide default mode; per-tool `permission` overrides it. MCP tools default to `always_ask` — third-party code asks first.                                                      |
| `default_enabled` | `false` disables tools by default. Set `enabled: true` for each tool you want to expose.                                                                                            |

### How MCP tools are named

MCP tool names combine the server and tool: `mcp__{server}__{tool}`. For example, Linear's `get_issue` tool appears as `mcp__linear__get_issue`.

These names appear in `model_output` tool calls and in [`GET /tool-calls`](/tools/custom#find-calls-waiting-for-you) with `type: "mcp"`. Server names cannot contain underscores, and the combined name must fit within 64 characters.

## Bearer auth

For servers that take a static token, store the token as a generic secret and reference it:

<Tabs>
  <Tab title="API">
    The examples assume the client, `$ORG`/`orgID`, and `$PROJ`/`projectID` setup from the [quickstart](/quickstart).

    <CodeGroup>
      ```bash CLI theme={null}
      omnara secrets create \
        --owner-kind project \
        --owner-project-id proj_7mv4qtrwz3jehcyd5n6a2bfgik \
        --name internal-docs-mcp-token \
        --material-kind generic \
        --material-value "mcp-token-..."
      ```

      ```bash REST theme={null}
      curl "$OMNARA_API/orgs/$ORG/secrets" \
        -H "Authorization: Bearer $OMNARA_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
          "owner": { "kind": "project", "project_id": "'"$PROJ"'" },
          "name": "internal-docs-mcp-token",
          "material": { "kind": "generic", "value": "mcp-token-..." }
        }'
      ```

      ```typescript SDK theme={null}
      const secret = await sdk.createSecret({
        client,
        path: { orgID },
        body: {
          owner: { kind: 'project', project_id: projectID },
          name: 'internal-docs-mcp-token',
          material: { kind: 'generic', value: 'mcp-token-...' },
        },
      })
      console.log(secret.data.id)
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Dashboard">
    Under org, project, or user secrets, click **New secret**, name it, choose the **Generic** kind, and paste the token. You can add **Project grants** in the same dialog.
  </Tab>
</Tabs>

The response's `id` (`sec_…`) goes in `auth.secret_id` with `type: bearer`. Rotation is a [new secret version](/organization/secrets#rotate-a-secret) — configs keep referencing the same ID.

## AWS Signature Version 4 auth

For a SigV4-protected MCP server, create an **AWS credentials** secret in the dashboard, grant it to the project, and select **AWS Signature V4** for server authentication:

```yaml theme={null}
mcp:
  aws:
    url: https://aws-mcp.us-east-1.api.aws/mcp
    auth:
      type: sigv4
      secret_id: sec_7jehcyd5n6a2bfgik7mv4qtrwz
      service: aws-mcp
      region: us-east-1
```

Omnara optionally assumes the role stored with the credentials, then signs each request with AWS Signature Version 4 using the configured service and region. It does not modify the MCP request body or create a bearer token.

`auth.region` is the MCP endpoint's signing region; it does not limit the AWS resource regions selected in tool calls. Omnara does not refresh a session token stored in the AWS credentials secret, so rotate that secret before the token expires.

## Connect with OAuth

For servers such as Linear, Omnara handles OAuth registration, authorization, and token exchange. It stores the resulting credentials in an `oauth_token_set` secret that your config references.

<Tabs>
  <Tab title="API">
    The CLI command runs the whole flow — it opens the server's authorization page in your browser, waits for approval, and prints the created secret's ID (`--no-browser` prints the authorization URL instead of opening it). The REST API and the SDK start the flow with one request and return an authorization URL to open yourself:

    <CodeGroup>
      ```bash CLI theme={null}
      omnara secrets mcp-oauth \
        --owner-kind project \
        --owner-project-id proj_7mv4qtrwz3jehcyd5n6a2bfgik \
        --name linear-mcp \
        --mcp-url https://mcp.linear.app/mcp
      ```

      ```bash REST theme={null}
      curl "$OMNARA_API/orgs/$ORG/secrets/mcp-oauth" \
        -H "Authorization: Bearer $OMNARA_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
          "owner": { "kind": "project", "project_id": "'"$PROJ"'" },
          "name": "linear-mcp",
          "mcp_url": "https://mcp.linear.app/mcp",
          "return_to": "/projects/'"$PROJ"'/secrets"
        }'
      ```

      ```typescript SDK theme={null}
      const start = await sdk.startSecretMcpoAuth({
        client,
        path: { orgID },
        body: {
          owner: { kind: 'project', project_id: projectID },
          name: 'linear-mcp',
          mcp_url: 'https://mcp.linear.app/mcp',
          return_to: `/projects/${projectID}/secrets`,
        },
      })
      console.log(start.data.authorization_url)
      ```
    </CodeGroup>

    ```json theme={null}
    {
      "authorization_url": "https://linear.app/oauth/authorize?client_id=…&state=…",
      "expires_at": "2026-08-03T20:28:00Z"
    }
    ```

    Open `authorization_url` in a browser and approve access. Omnara reads the server's OAuth metadata, registers a client when supported, exchanges the authorization code, and stores the result as an `oauth_token_set` secret. You can also pass an existing client ID and secret (`--client-id` and `--client-secret` on the CLI, `client_id` and `client_secret` in the start request).

    The browser returns to the dashboard-relative `return_to` path with `?mcp_oauth=success&secret_id=sec_…` appended. Absolute return URLs are rejected. Use that secret ID with `auth.type: oauth`. The authorization link is single-use and expires in 10 minutes.

    To authorize a server and attach it to an existing config in one step, use `omnara agents mcp-add {agent-id} --server-name linear --mcp-url …` or `omnara profiles mcp-add {agent-profile-id} --server-name linear --mcp-url …`. Both create the OAuth secret and add the `mcp:` entry to the agent's or profile's config for you.
  </Tab>

  <Tab title="Dashboard">
    On any Secrets page, click **New secret**, pick the **MCP OAuth secret** kind, name it, and enter the MCP server URL. **Authorize and Create Secret** sends you to the server's authorization page; approve, and you land back in the dashboard with the secret saved.

    The secret's row action **Copy MCP config** then puts a ready-to-paste `mcp:` YAML block — the server URL plus `auth.type: oauth` and the `secret_id` — on your clipboard.
  </Tab>
</Tabs>

Re-running the flow with the same owner and name creates a new *version* of the same secret, so re-authorizing never forces a config change.

Troubleshooting:

* If the MCP server doesn't actually require auth, the start call returns `409` — declare it without an `auth` block instead.
* If a token expires and cannot be refreshed, affected tool calls return `mcp_connection_failed`. Re-run the OAuth flow to create a fresh secret version; the config can keep using the same secret ID.

<Info>
  Full schema and playground: [Start MCP OAuth for a new secret](/api-reference/endpoints/secrets/start-mcp-oauth-for-a-new-secret).
</Info>
