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

# MCP Integration

> How Orca uses the Model Context Protocol to give agents a unified interface for platform tools and external APIs.

## What is MCP?

The **Model Context Protocol (MCP)** is an open standard for exposing tools to LLM agents over HTTP. Orca uses MCP as the **universal tool interface** — every session gets its own MCP endpoint, and agents discover and invoke tools through it.

***

## Session-Scoped MCP Endpoint

When a session is created, the runner spins up a **session-scoped MCP server** at:

```
POST /runner/sessions/{sessionId}/mcp
```

This endpoint uses MCP's **streamable HTTP transport** and serves:

1. **Platform tools** — the session's scoped toolkit (tools allowed by the profile)
2. **External MCP servers** — inline servers defined in the profile's `mcpServers` list
3. **[Connected apps](/concepts/connected-apps)** — provider-managed grants invoked through platform facade tools and the tenant-isolated MCP bridge

The runner passes `sessionMcpUrl` in the run envelope to the sidecar, which uses it to connect its MCP client.

***

## How Tools Flow

```mermaid theme={null}
flowchart TB
  worker["agent-worker<br/>sidecar"]
  endpoint["Session MCP endpoint<br/>http://runner:7070/runner/sessions/sess-.../mcp"]
  runner["runner<br/>MCP server"]
  platform["Platform toolkit<br/>session-scoped registry"]
  platformTools["web_search<br/>time_now<br/>delegate_run<br/>..."]
  external["External MCP servers<br/>profile.mcpServers"]
  externalTools["company-db<br/>my-api<br/>..."]

  worker -->|"MCP client connects"| endpoint --> runner
  runner --> platform --> platformTools
  runner --> external --> externalTools
```

The LLM sees platform tools and inline external MCP tools through one tool interface. Connected-app catalogs stay deferred: the model sees the `search_connected_app_tools` and `call_connected_app_tool` facade tools, then loads only the provider tool schemas it needs.

***

## Provider Support

| Runtime   | MCP via                                          |
| --------- | ------------------------------------------------ |
| `general` | Vercel AI SDK `@ai-sdk/mcp` — native MCP client  |
| `claude`  | Native SDK tool surface (MCP bridge in progress) |
| `codex`   | Native SDK tool surface (MCP bridge in progress) |

<Note>
  The `general` runtime has full MCP client support via `@ai-sdk/mcp`. Claude and Codex runtimes currently use native SDK tool surfaces; MCP bridging is tracked on the roadmap.
</Note>

***

## External MCP Servers in Profiles

Add external MCP servers to a profile's `mcpServers` array:

```json theme={null}
{
  "name": "data-analyst",
  "runtime": "general",
  "model": "anthropic:claude-sonnet-4-6",
  "systemPrompt": "You are a data analyst.",
  "tools": ["@introspection"],
  "mcpServers": [
    {
      "name": "warehouse",
      "transport": "http",
      "url": "https://warehouse.internal/mcp",
      "headers": {
        "Authorization": "Bearer ${WAREHOUSE_API_KEY}",
        "X-Tenant": "acme-corp"
      }
    },
    {
      "name": "metrics-api",
      "transport": "http",
      "url": "https://metrics.internal/mcp",
      "headers": {
        "X-API-Key": "${METRICS_API_KEY}"
      }
    }
  ]
}
```

### Secret Resolution

Header values containing `${VAR}` are resolved from the **runner's environment** — see [Secrets](/concepts/secrets) for how these are provisioned:

```mermaid theme={null}
flowchart LR
  env["Runner environment<br/>WAREHOUSE_API_KEY=secret-token-123"]
  profile["Profile header<br/>Authorization: Bearer ${WAREHOUSE_API_KEY}"]
  resolved["Resolved header<br/>Authorization: Bearer secret-token-123"]

  env --> profile --> resolved
```

<Warning>
  If `${VAR}` cannot be resolved (the env var is not set), the placeholder is passed through **as-is**. This will likely cause the external MCP server to reject the request. Always verify that runner environment variables are set for every placeholder used in profiles.
</Warning>

***

## MCP Catalog

The **MCP Catalog** is a conductor-local registry of reusable MCP server definitions. It lets you pre-configure servers once and reference them when building profiles in the dashboard.

<Note>
  User-authored catalog entries are a convenience layer copied into profiles. Provider-managed entries also authorize connected-app calls: profiles store them as credential-free `catalog://<name>` references, and the runtime resolves them through the bridge rather than as native sidecar MCP transports.
</Note>

### Dashboard MCP Page

The dashboard groups MCP management into three tabs:

| Tab                | Purpose                                                                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **Servers**        | Manual catalog entries and managed app-backed MCP servers. The table shows the server host, with the full URL available in the row tooltip. |
| **Connected Apps** | OAuth app gallery. Apps can be searched and filtered by category; connecting an app registers its MCP server automatically.                 |
| **Connections**    | Active and in-flight OAuth connections. Revoke access from this table when an app-backed server should be disconnected.                     |

In v1, Connected Apps uses Composio as its provider. App category labels come from the provider payload when available, with dashboard fallbacks for common app slugs so the gallery remains filterable while provider metadata rolls out.

When a managed app is attached to a profile, its `mcpServers` entry has only a name and matching reference, for example `{"name":"composio-gmail","ref":"catalog://composio-gmail"}`. The runtime does not send the managed URL or provider credentials to the worker. Agents discover matching tools on demand with `search_connected_app_tools` and execute an exact result with `call_connected_app_tool`; both are part of `@introspection`.

### Managing the Catalog

```bash theme={null}
# List catalog entries
GET  /api/mcp-servers

# Add a server
POST /api/mcp-servers
{
  "name": "my-db",
  "transport": "http",
  "url": "https://db.internal/mcp",
  "headers": { "Authorization": "Bearer ${DB_API_KEY}" }
}

# Update
PUT /api/mcp-servers/{name}

# Delete
DELETE /api/mcp-servers/{name}
```

### Reserved Names

The name `runner` is **reserved** and cannot be used in the MCP catalog. It refers to the session-scoped platform MCP endpoint.

***

## Writing an MCP-Compatible Tool Server

Any HTTP server implementing the MCP streamable HTTP transport can be attached to Orca profiles. Minimal requirements:

1. Accept `POST /` requests with MCP protocol messages (JSON-RPC 2.0)
2. Return Server-Sent Events for streaming responses
3. Handle `tools/list` and `tools/call` method calls

```bash theme={null}
# Test your MCP server with curl
curl -X POST https://my-mcp-server.example.com/ \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
```

See the [MCP specification](https://spec.modelcontextprotocol.io) for the full protocol reference.

***

## Platform MCP vs External MCP

| Feature           | Platform MCP (session-scoped)            | External MCP                            |
| ----------------- | ---------------------------------------- | --------------------------------------- |
| Hosted by         | Runner                                   | You                                     |
| Configured in     | Profile `tools` list                     | Profile `mcpServers` list               |
| Secret resolution | N/A (built-in)                           | `${VAR}` from runner env                |
| Tool scoping      | Enforced (HTTP 403 if out of scope)      | Not enforced by Orca                    |
| Examples          | `web_search`, `delegate_run`, `time_now` | `warehouse`, `company-db`, `github-api` |
