# Connect MCP servers

Both directions. Inward: any MCP server's tools join Kaptain's catalog. Outward: Kaptain IS an MCP server named `kaptain-engine` for Claude/Codex/Gemini CLIs.

## Inward: add a server
Transports: stdio (command Kaptain spawns), http (streamable-HTTP URL), sse. Fill a command OR a URL — the transport follows. Install the server's own runtime first (npx/Docker/binary); Kaptain checks the launcher exists and refuses plainly before saving.

## In the UI
Krew view > MCP Servers category:
- "Add manually": name (lowercase id), command+args OR remote URL, one KEY=VALUE per line (env for local, headers for remote).
- "+ Add from JSON": paste a vendor README `{"mcpServers":{...}}` block — format-compatible on purpose.
Rows show live status, tool count, errors; actions: Enable/Disable, Reconnect, Remove, OAuth sign-in. Connected tools join the catalog with per-tool switches.

Dialog fields (one dialog, transport follows what you fill): Name (lowercase id — tools appear under it) | Local command (npx/uvx/binary; empty for remote) | Arguments | Remote URL (empty for local) | Env/headers (KEY=VALUE per line; env for local, headers for remote; API keys go here either way).

Models call these tools by themselves once the server is connected+enabled+discovered — or ask outright ("Use the GitHub MCP tool to list open pull requests"). Agent scoping: the `tools` allowlist in kapsule.json (+ use_kapsule_tools); not editable from the Agents view; no allowlist = globally enabled tools.

## Terminal
    kaptain mcp add tavily --env TAVILY_API_KEY=${TAVILY_API_KEY} -- npx -y tavily-mcp
    kaptain mcp add linear --url https://mcp.linear.app/mcp
    kaptain mcp add-json          # paste {"mcpServers":{...}}, "-" = stdin
    kaptain mcp list | enable | disable | remove <name>
Config: mcp_servers.json in the data folder (hand-editable, README-block shape). CLI updates a running Kaptain live; else applies next start.

## Keys and secrets
${VAR} in env/headers expands at connect time — never stored. UI shows key names only; URLs masked. OAuth 2.1 + PKCE; tokens in their own file.

## Approval gating
External tools get the same gate as built-ins (Ask / Read-only / Auto / Full). A kapsule can pre-trust one server via a `mcp:<name>` trusted scope. Only connect servers you trust.

## Outward: Kaptain as a server
Kaptain's toolbelt is ONE MCP server, `kaptain-engine`, started with `kaptain mcp`.
Two situations: inside Kaptain (a kapsule/chat on a CLI model) — nothing to install, Kaptain hands the CLI the session's server (grants, approval mode, project). On your own (terminal/VS Code) — the CLI needs a registration in its own config.

Connect (one action): the CLI model's ⚙ popover next to the chat composer › "Register standalone", or:
    kaptain mcp register claude|codex|gemini
What it writes: Claude → `claude mcp add -s user kaptain-engine -- kaptain mcp` (~/.claude.json mcpServers.kaptain-engine; check `claude mcp get kaptain-engine`). Codex → `[mcp_servers.kaptain-engine]` in ~/.codex/config.toml (check `codex mcp list`). Gemini → settings.json mcpServers.kaptain-engine.
Verify from Kaptain's side: `kaptain mcp install-status <cli>`; prove the server answers: `kaptain mcp health`.

Updates and old entries: the entry points at your installed kaptain binary; after `kaptain update`, re-run register if the CLI reports the server missing (safe to repeat; an automatic refresh is in progress). Old Kaptain entries (`kaptain-krew`, a kaptain-engine at a vanished path) → remove them: `claude mcp remove kaptain-krew`; delete the `[mcp_servers.kaptain-krew]` block in config.toml. Inside Kaptain, duplicate Kaptain entries are silenced per session; your other servers are never touched.

External tools connected TO Kaptain are re-served to CLIs as ext__<server>__<tool> behind Kaptain's approval gate; proxy answers only while Kaptain runs. `kaptain mcp unregister <cli>` removes exactly what Kaptain added.

## If it goes wrong
- Row error = the real launcher/connect error; fix what it names; Reconnect retries.
- Same-name tools: native models — first registered wins, clash reported on the row; CLI harnesses never clash (prefixed).
- Self-tests: `kaptain mcp health` (JSON, exit!=0 when unhealthy), `kaptain mcp smoke`.
