# MCP

Connect any MCP (Model Context Protocol) server and its tools appear in chat as `<name>__<tool>` for the model to call. This page covers adding servers, where the configuration lives, and the supported transports.

## Quick start

```bash
openprogram mcp add drawio npx -y @drawio/mcp     # add a stdio server, effective immediately
openprogram mcp list                              # status of every configured server
openprogram mcp show drawio                       # that server's tools and full schemas
```

`mcp add` options: `--env KEY=VALUE` (inject an environment variable into the subprocess, repeatable), `--timeout` (startup and per-call timeout in seconds), `--disabled` (write the config without starting the server). The `name` becomes the prefix (`<name>__<tool>`) for all of that server's tools.

All subcommands:

```bash
openprogram mcp token create       # create a token for the local stdio MCP server
openprogram mcp serve              # serve the authenticated MCP server over stdio
openprogram mcp list | show | add | rm | restart | enable | disable | edit | test
```

`token create` prints the newly created token as one raw line; it does not set the
shell environment. Run it once, copy that line, and bind it to the serving
process before `serve`:

```bash
openprogram mcp token create
export OPENPROGRAM_MCP_TOKEN="<paste the token printed above>"
openprogram mcp serve
```

If the token already exists, reuse the token you saved instead of running
`token create` again. `serve` rejects a missing or mismatched
`OPENPROGRAM_MCP_TOKEN`.

- `rm` stops the server and deletes its config; `enable` / `disable` toggle it (disable keeps the config).
- `edit` is retained only as a compatibility command and reports that raw config editing was removed because it exposed stored secrets. Use `add` / `rm` or the MCP settings page; `add` covers stdio servers.
- `test` spins the server up with a throwaway config and confirms it returns a tool list, without writing anything to disk.

The management commands talk to the resident OpenProgram background worker; if it is not running, start it with `openprogram worker start` (check with `openprogram status`).


Configured MCP servers connect in the background when the worker starts. The App and core API stay available while an optional server connects or waits for OAuth. Until that server is ready, its remote tools are unavailable; `mcp list` and the MCP settings page report its actual status. Each server keeps its configured startup and call timeouts.

## Where the config lives

`~/.openprogram/mcp_servers.json` (with `--profile <name>`, `~/.openprogram-<name>/mcp_servers.json`). Format:

```json
{
  "servers": {
    "drawio": {
      "type": "local",
      "command": ["npx", "-y", "@drawio/mcp"],
      "env": {},
      "enabled": true,
      "timeout_seconds": 30
    },
    "linear": {
      "type": "http",
      "url": "https://mcp.linear.app/mcp",
      "auth": {"kind": "oauth", "client_name": "OpenProgram"},
      "enabled": true
    }
  }
}
```

## Transports and auth

| `type` | Description | Fields used |
|---|---|---|
| `local` | stdio subprocess | `command`, `env` |
| `http` | Streamable HTTP | `url`, `headers`, `auth` |
| `sse` | legacy SSE | `url`, `headers`, `auth` |

`auth.kind` supports `none` / `bearer` (a `token` field) / `oauth` (OAuth 2.1 PKCE; servers with dynamic client registration work with zero config — only servers requiring a pre-registered client need `client_id` / `client_secret`).

### OAuth sign-in happens once

The first time an OAuth server connects, OpenProgram opens the consent page in your browser and captures the redirect on a localhost callback. Everything the flow produced — access and refresh tokens, the dynamic client registration, and the discovered authorization endpoints — is persisted to `~/.openprogram/mcp_tokens/<server>.json` (mode `0600`). Every later connection, including after a worker restart, reuses the stored token; when it has expired, the refresh token renews it silently in the background. The browser only reappears when the refresh token itself is rejected (revoked or expired server-side) — the management UI then shows the server as needing re-authentication. To switch accounts or start over, `POST /api/mcp/servers/{name}/auth/clear` wipes the stored state and restarts the server.

Beyond tools, MCP's other two primitives — resources and prompts — are also exposed to the model through built-in meta tools (see `mcp_meta` in [Built-in tools](tools.md)).
