| 1 | # MCP (External Tool Servers) |
| 2 | |
| 3 | codewhale can load additional tools via MCP (Model Context Protocol). MCP servers can be local stdio processes that the TUI starts, or remote URL-based servers that speak Streamable HTTP with legacy SSE fallback. |
| 4 | |
| 5 | Browsing note: |
| 6 | - `Web` is the canonical, deferred built-in browsing tool; it provides |
| 7 | `search`, `fetch`, and `wait` actions when network policy permits. |
| 8 | - `web_search`, `fetch_url`, and `wait_for_dev_server` are hidden replay-only |
| 9 | aliases. New prompts and integrations should use `Web`. |
| 10 | |
| 11 | Server mode note: |
| 12 | - `codewhale-tui serve --mcp` runs the MCP stdio server. |
| 13 | - `codewhale-tui serve --http` runs the runtime HTTP/SSE API (separate mode). |
| 14 | - The `codewhale` dispatcher exposes `codewhale mcp-server` as an equivalent stdio |
| 15 | entrypoint used by the split CLI. |
| 16 | |
| 17 | ## Setup wizard vs manual MCP setup (#3407) |
| 18 | |
| 19 | The constitution-first `/setup` wizard includes an optional **Tools and MCP** |
| 20 | step. That step is discovery/readiness only: |
| 21 | |
| 22 | | Wizard can do | Still requires manual / explicit action | |
| 23 | | --- | --- | |
| 24 | | Show configured servers as `healthy` / `needs_config` / `off` | Start or connect MCP servers | |
| 25 | | Report config path presence (global + project) | Write or edit `mcp.json` contents | |
| 26 | | Safe static health probe (missing command/url, broken absolute path, missing bearer env) | `codewhale mcp validate`, live connect, OAuth login | |
| 27 | | Point at safe on-ramps (`/mcp`, `codewhale mcp init`, `codewhale doctor`) | Install community skills, trust skills, enable plugins | |
| 28 | | Share Hotbar source counts from the same skill/MCP adapters (#3399) | Bind Hotbar slots (Hotbar step / `H`) | |
| 29 | | Record optional/`needs_action` setup_state without blocking first-run | Anything that spawns processes or installs packages | |
| 30 | |
| 31 | Empty inventory is **not** an error: first-run users see “nothing configured |
| 32 | yet, that’s fine.” Failing or incomplete configured servers surface as |
| 33 | `needs_config` with an actionable hint and never block setup completion. |
| 34 | Enumeration never executes MCP/plugin commands beyond the static probe. |
| 35 | Summaries redact commands, args, env, headers, and tokens. |
| 36 | |
| 37 | `codewhale doctor` reports MCP/skills/tools/plugins health with the same |
| 38 | optional-surface intent (paths, counts, static checks) so wizard and doctor |
| 39 | stay consistent. |
| 40 | |
| 41 | ## Plugin-contributed MCP |
| 42 | |
| 43 | A reviewed local plugin bundle may contribute MCP servers without creating a |
| 44 | second transport or approval system. The servers use the same MCP manager, |
| 45 | tool approval, resource, prompt, timeout, and network-policy paths documented |
| 46 | here, and appear under namespaced `<plugin>-<server>` identities. |
| 47 | |
| 48 | The bundle boundary is intentionally stricter than user-authored `mcp.json`: |
| 49 | unknown fields and ambiguous transports fail closed; stdio environment values |
| 50 | must be exact environment-source references; remote literal headers and |
| 51 | secret-bearing URLs are rejected; declared network hosts must exactly match |
| 52 | the normalized endpoint host set; and redirects remain on the reviewed origin. |
| 53 | Reviewed plugin remotes also bypass ambient HTTP proxy configuration entirely; |
| 54 | proxy credentials and proxy-observed traffic are not part of the v1 review. |
| 55 | The plugin review discloses local host-user authority, structural argv, |
| 56 | environment provenance, endpoint, auth source names, scopes, and tool filters |
| 57 | without reading or printing secret values. |
| 58 | |
| 59 | Trust stages reviewed content but does not enable it. Enablement attaches that |
| 60 | staged snapshot to the current workspace's MCP pool. Disable, revoke, and other |
| 61 | cross-process generation changes remove catalog entries, cancel in-flight |
| 62 | operations, and terminate plugin stdio children. Source or staged-tree drift is |
| 63 | fully revalidated before each dispatch/catalogue boundary and fails the next |
| 64 | boundary closed; v0.9.1 does not continuously hash mutable trees during an |
| 65 | already-running call and therefore does not promise drift-triggered mid-call |
| 66 | cancellation. MCP subscriptions are not exposed through plugin bundles. See |
| 67 | [Plugin bundles](PLUGIN_BUNDLES.md) for the complete lifecycle contract. |
| 68 | |
| 69 | ## Bootstrap MCP Config |
| 70 | |
| 71 | Create a starter MCP config at your resolved MCP path: |
| 72 | |
| 73 | ```bash |
| 74 | codewhale-tui mcp init |
| 75 | ``` |
| 76 | |
| 77 | `codewhale-tui setup --mcp` performs the same MCP bootstrap alongside skills setup. |
| 78 | |
| 79 | Common management commands: |
| 80 | |
| 81 | ```bash |
| 82 | codewhale-tui mcp list |
| 83 | codewhale-tui mcp tools [server] |
| 84 | codewhale-tui mcp add <name> --command "<cmd>" --arg "<arg>" |
| 85 | codewhale-tui mcp add <name> --url "http://localhost:3000/mcp" |
| 86 | codewhale-tui mcp add <name> --url "https://example.com/mcp" --bearer-token-env-var MCP_TOKEN |
| 87 | codewhale-tui mcp login <name> |
| 88 | codewhale-tui mcp logout <name> |
| 89 | codewhale-tui mcp enable <name> |
| 90 | codewhale-tui mcp disable <name> |
| 91 | codewhale-tui mcp remove <name> |
| 92 | codewhale-tui mcp validate |
| 93 | ``` |
| 94 | |
| 95 | ## In-TUI Manager |
| 96 | |
| 97 | Inside the interactive TUI, `/mcp` opens a compact manager for the resolved |
| 98 | MCP config path. It shows each configured server, whether it is enabled or |
| 99 | disabled, its transport, command or URL, timeout values, connection errors, |
| 100 | and discovered tools/resources/prompts when discovery has been run. |
| 101 | |
| 102 | Supported in-TUI actions: |
| 103 | |
| 104 | ```text |
| 105 | /mcp init |
| 106 | /mcp init --force |
| 107 | /mcp add stdio <name> <command> [args...] |
| 108 | /mcp add http <name> <url> |
| 109 | /mcp login <name> [--scope scope] |
| 110 | /mcp logout <name> |
| 111 | /mcp enable <name> |
| 112 | /mcp disable <name> |
| 113 | /mcp remove <name> |
| 114 | /mcp validate |
| 115 | /mcp reload |
| 116 | ``` |
| 117 | |
| 118 | `/mcp validate` (alias `/mcp doctor`) reconnects for UI discovery only: it |
| 119 | refreshes the manager snapshot you see in the pager, not the catalog the model |
| 120 | gets. |
| 121 | |
| 122 | `/mcp reload` (aliases `/mcp reconnect`, `/mcp restart`) is the hot-reload path. |
| 123 | It re-reads the MCP config sources and reconnects through the engine-owned pool, |
| 124 | so the rebuilt catalog is the exact one the next model turn uses — no TUI |
| 125 | restart. Config edits made from the TUI are written immediately and the manager |
| 126 | marks the snapshot reload-required until you run it; a failed reload leaves the |
| 127 | previous live pool intact and says so. |
| 128 | |
| 129 | Headless surfaces are the exception: the `ConfigReload` app-server request does |
| 130 | **not** refresh MCP connections, so a headless runtime still needs a restart |
| 131 | after MCP config changes. |
| 132 | |
| 133 | ## Remote HTTP Auth |
| 134 | |
| 135 | URL-based MCP servers can use static headers, env-derived headers, bearer-token |
| 136 | env vars, or OAuth. Authorization precedence is conservative: |
| 137 | |
| 138 | 1. `headers` and `env_headers` are applied first. |
| 139 | 2. `bearer_token_env_var` adds `Authorization: Bearer <env value>` when no |
| 140 | Authorization header was already set. |
| 141 | 3. Stored OAuth credentials are used only when no Authorization header exists. |
| 142 | |
| 143 | For bearer-token auth, prefer env-backed config: |
| 144 | |
| 145 | ```json |
| 146 | { |
| 147 | "servers": { |
| 148 | "remote": { |
| 149 | "url": "https://example.com/mcp", |
| 150 | "bearer_token_env_var": "EXAMPLE_MCP_TOKEN" |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | ``` |
| 155 | |
| 156 | For generic remote MCP OAuth, add the URL server and run login: |
| 157 | |
| 158 | ```bash |
| 159 | codewhale-tui mcp add remote --url "https://example.com/mcp" |
| 160 | codewhale-tui mcp login remote |
| 161 | ``` |
| 162 | |
| 163 | Codewhale discovers the server OAuth metadata, opens the authorization URL in |
| 164 | your browser, listens on a local callback, exchanges the code, and stores the |
| 165 | token response through the Codewhale secrets backend. Stored OAuth tokens are |
| 166 | looked up by server name plus URL and refreshed when possible before requests. |
| 167 | During login, the CLI prints the authorization URL and a waiting status while |
| 168 | the local callback listener is active. If a URL-based server returns 401 or |
| 169 | Unauthorized during connect/discovery, `codewhale mcp connect <name>` reports |
| 170 | that OAuth authentication is required and points to |
| 171 | `codewhale mcp login <name>`. Resource helper listings also surface an |
| 172 | `authentication_required` entry for auth-shaped failures instead of silently |
| 173 | looking empty. |
| 174 | |
| 175 | Optional OAuth fields: |
| 176 | |
| 177 | ```json |
| 178 | { |
| 179 | "servers": { |
| 180 | "remote": { |
| 181 | "url": "https://example.com/mcp", |
| 182 | "scopes": ["tools/read"], |
| 183 | "oauth": { |
| 184 | "client_id": "public-client-id" |
| 185 | }, |
| 186 | "oauth_resource": "https://example.com" |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | ``` |
| 191 | |
| 192 | User-level config can set callback behavior when the provider requires a fixed |
| 193 | redirect: |
| 194 | |
| 195 | ```toml |
| 196 | mcp_oauth_callback_port = 1455 |
| 197 | mcp_oauth_callback_url = "http://127.0.0.1:1455/callback" |
| 198 | ``` |
| 199 | |
| 200 | These callback fields are ignored from project-scope config overlays. |
| 201 | |
| 202 | ## Hugging Face MCP |
| 203 | |
| 204 | Hugging Face provides a hosted MCP server for Hub resources, documentation, |
| 205 | datasets, Spaces, and community tools. Codewhale does not call Hugging Face's |
| 206 | Hub HTTP APIs from `/hf`; it only helps you inspect and set up the MCP config |
| 207 | that the regular MCP manager will load. |
| 208 | |
| 209 | The recommended setup path is Hugging Face's settings-generated configuration: |
| 210 | |
| 211 | 1. Visit <https://huggingface.co/settings/mcp> while signed in. |
| 212 | 2. Choose the MCP client closest to your Codewhale config shape and copy the |
| 213 | generated server snippet. |
| 214 | 3. Paste the Hugging Face server entry into your resolved MCP config file. |
| 215 | 4. Run `/mcp reload` to rebuild the live model-visible tool pool. |
| 216 | |
| 217 | Codewhale reads both `servers` and `mcpServers`, so settings-generated snippets |
| 218 | can be adapted without changing the rest of the MCP file. A placeholder-only |
| 219 | shape looks like this: |
| 220 | |
| 221 | ```json |
| 222 | { |
| 223 | "servers": { |
| 224 | "huggingface": { |
| 225 | "url": "https://huggingface.co/mcp", |
| 226 | "headers": { |
| 227 | "Authorization": "Bearer ${HF_TOKEN}" |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | ``` |
| 233 | |
| 234 | The placeholder above is not a runnable secret. Use the settings-generated |
| 235 | value in your private MCP config and never commit real Hugging Face tokens. |
| 236 | |
| 237 | Interactive helpers: |
| 238 | |
| 239 | ```text |
| 240 | /hf mcp status |
| 241 | /hf mcp setup |
| 242 | /hf concepts |
| 243 | ``` |
| 244 | |
| 245 | `/hf mcp status` checks the configured MCP file for common Hugging Face server |
| 246 | names or Hugging Face MCP URLs. `/hf concepts` explains the difference between |
| 247 | the Hugging Face provider route, Hugging Face MCP, and explicit Hub workflows. |
| 248 | |
| 249 | Official docs: <https://huggingface.co/docs/hub/hf-mcp-server> |
| 250 | |
| 251 | ## Config File Location |
| 252 | |
| 253 | Default path: |
| 254 | |
| 255 | - `~/.codewhale/mcp.json` (`~/.deepseek/mcp.json` is still read when the Codewhale file is absent) |
| 256 | |
| 257 | Overrides: |
| 258 | |
| 259 | - Config: `mcp_config_path = "/path/to/mcp.json"` |
| 260 | - Env: `DEEPSEEK_MCP_CONFIG=/path/to/mcp.json` |
| 261 | |
| 262 | `codewhale-tui mcp init` (and `codewhale-tui setup --mcp`) writes to this resolved path. |
| 263 | |
| 264 | The interactive `/config` editor also exposes `mcp_config_path`. Changing it in |
| 265 | the TUI updates the path used by `/mcp` and marks the pool reload-required; |
| 266 | `/mcp reload` then switches the live pool to the new config source. |
| 267 | |
| 268 | After editing the MCP file or changing `mcp_config_path`, run `/mcp reload`. No |
| 269 | TUI restart is needed. |
| 270 | |
| 271 | ## Tool Naming |
| 272 | |
| 273 | Discovered MCP tools are exposed to the model as: |
| 274 | |
| 275 | - `mcp_<server>_<tool>` |
| 276 | |
| 277 | Example: a server named `git` with a tool named `status` becomes `mcp_git_status`. |
| 278 | |
| 279 | The command palette includes MCP entries grouped by server. It shows disabled |
| 280 | and failed servers instead of hiding them, and uses the same runtime tool names |
| 281 | shown to the model. |
| 282 | |
| 283 | ## Resource and Prompt Helpers |
| 284 | |
| 285 | The CLI also exposes helper tools when MCP is enabled: |
| 286 | |
| 287 | - `list_mcp_resources` (optional `server` filter) |
| 288 | - `list_mcp_resource_templates` (optional `server` filter) |
| 289 | - `mcp_read_resource` / `read_mcp_resource` (aliases) |
| 290 | - `mcp_get_prompt` |
| 291 | |
| 292 | ## Minimal Example |
| 293 | |
| 294 | ```json |
| 295 | { |
| 296 | "timeouts": { |
| 297 | "connect_timeout": 10, |
| 298 | "execute_timeout": 60, |
| 299 | "read_timeout": 120 |
| 300 | }, |
| 301 | "servers": { |
| 302 | "example": { |
| 303 | "command": "node", |
| 304 | "args": ["./path/to/your-mcp-server.js"], |
| 305 | "env": {}, |
| 306 | "disabled": false |
| 307 | } |
| 308 | } |
| 309 | } |
| 310 | ``` |
| 311 | |
| 312 | You can also use `mcpServers` instead of `servers` for compatibility with other clients. |
| 313 | |
| 314 | ## Running DeepSeek as an MCP Server |
| 315 | |
| 316 | You can register your local DeepSeek binary as an MCP server so other DeepSeek sessions (or any MCP client) can call its tools. |
| 317 | |
| 318 | ### Quick Setup |
| 319 | |
| 320 | ```bash |
| 321 | codewhale-tui mcp add-self |
| 322 | ``` |
| 323 | |
| 324 | This resolves the current binary path, generates a config entry that runs `codewhale-tui serve --mcp`, and writes it to your MCP config file. The default server name is `codewhale`. |
| 325 | |
| 326 | Options: |
| 327 | |
| 328 | - `--name <NAME>` — custom server name (default: `codewhale`) |
| 329 | - `--workspace <PATH>` — workspace directory for the server |
| 330 | |
| 331 | ### Manual Config |
| 332 | |
| 333 | Equivalent manual entry in `~/.codewhale/mcp.json`: |
| 334 | |
| 335 | ```json |
| 336 | { |
| 337 | "servers": { |
| 338 | "codewhale": { |
| 339 | "command": "/path/to/codewhale", |
| 340 | "args": ["serve", "--mcp"], |
| 341 | "env": {} |
| 342 | } |
| 343 | } |
| 344 | } |
| 345 | ``` |
| 346 | |
| 347 | The `codewhale-tui` binary supports `serve --mcp` directly. The `codewhale` |
| 348 | dispatcher offers the equivalent `codewhale mcp-server` stdio entrypoint. Use |
| 349 | whichever is on your `PATH` (run `which codewhale` or `which codewhale-tui` to |
| 350 | find the full path). The `mcp add-self` command automatically resolves the |
| 351 | correct binary. |
| 352 | |
| 353 | ### Prerequisites |
| 354 | |
| 355 | - The binary referenced in `command` must exist and be executable. |
| 356 | - The MCP server runs as a child process via stdio — no network ports required. |
| 357 | - Each MCP client session spawns its own server process. |
| 358 | |
| 359 | ### Tool Naming |
| 360 | |
| 361 | Tools from an MCP server follow the standard naming convention: |
| 362 | |
| 363 | - `mcp_<server>_<tool>` |
| 364 | |
| 365 | For example, the `shell` tool from the default server (named `codewhale`) |
| 366 | becomes `mcp_codewhale_shell`. |
| 367 | |
| 368 | ### MCP Server vs HTTP/SSE API vs ACP |
| 369 | |
| 370 | | | `codewhale-tui serve --mcp` | `codewhale-tui serve --http` | `codewhale-tui serve --acp` | |
| 371 | |---|---|---|---| |
| 372 | | **Protocol** | MCP stdio | HTTP/SSE JSON-RPC | ACP stdio | |
| 373 | | **Use case** | Tool server for MCP clients | Runtime API for apps | Editor agent for Zed/custom ACP clients | |
| 374 | | **Config** | `~/.codewhale/mcp.json` entry | Direct URL connection | Editor `agent_servers` custom command | |
| 375 | | **Lifecycle** | Spawned per client session | Long-running daemon | Spawned per editor agent session | |
| 376 | |
| 377 | Use `mcp add-self` when you want DeepSeek tools available to other MCP clients. |
| 378 | Use `serve --http` when building applications that consume the API directly. |
| 379 | Use `serve --acp` when an editor wants to talk to DeepSeek as an ACP agent. |
| 380 | |
| 381 | ### Verification |
| 382 | |
| 383 | After adding, test the connection: |
| 384 | |
| 385 | ```bash |
| 386 | codewhale-tui mcp validate |
| 387 | codewhale-tui mcp tools codewhale |
| 388 | ``` |
| 389 | |
| 390 | ## Server Fields |
| 391 | |
| 392 | Per-server settings: |
| 393 | |
| 394 | - `command` (string, required) |
| 395 | - `args` (array of strings, optional) |
| 396 | - `env` (object, optional) |
| 397 | - `connect_timeout`, `execute_timeout`, `read_timeout` (seconds, optional) |
| 398 | - `disabled` (bool, optional) |
| 399 | - `enabled` (bool, optional, default `true`) |
| 400 | - `required` (bool, optional): startup/connect validation fails if this server cannot initialize. |
| 401 | - `enabled_tools` (array, optional): allowlist of tool names for this server. |
| 402 | - `disabled_tools` (array, optional): denylist applied after `enabled_tools`. |
| 403 | - `url` (string, optional): Streamable HTTP endpoint for a remote MCP server. |
| 404 | - `transport` (string, optional): set to `"sse"` for legacy SSE endpoints. |
| 405 | - `headers` (object, optional): literal HTTP headers for URL-based servers. |
| 406 | - `env_headers` or `env_http_headers` (object, optional): header names mapped to environment variable names. |
| 407 | - `bearer_token_env_var` (string, optional): environment variable containing a bearer token. |
| 408 | - `scopes` (array, optional): default OAuth scopes for `mcp login`. |
| 409 | - `oauth.client_id` (string, optional): pre-registered OAuth client ID. |
| 410 | - `oauth_resource` (string, optional): resource parameter appended to the authorization URL. |
| 411 | |
| 412 | ## Safety Notes |
| 413 | |
| 414 | MCP tools flow through the same approval framework as built-in tools. Read-only |
| 415 | MCP helpers (resource/prompt listing and reads) can run without prompts in Ask |
| 416 | and Auto-Review when policy permits, while side-effectful MCP tools require |
| 417 | approval. Full Access does not bypass hard policy holds. |
| 418 | |
| 419 | You should still only configure MCP servers you trust, and treat MCP server configuration as equivalent to running code on your machine. |
| 420 | Avoid committing literal `Authorization` headers. Prefer `env_headers`, |
| 421 | `bearer_token_env_var`, or OAuth login so secrets stay outside the MCP file. |
| 422 | |
| 423 | ## Troubleshooting |
| 424 | |
| 425 | - Run `codewhale-tui doctor` to confirm the MCP config path it resolved and whether it exists. |
| 426 | - In the TUI, run `/mcp validate` to refresh the visible server/tool snapshot. |
| 427 | - If tools are missing from the model's catalog after a config or credential |
| 428 | change, run `/mcp reload` — `/mcp validate` only refreshes the UI snapshot. |
| 429 | - If the MCP config is missing, run `codewhale-tui mcp init --force` to regenerate it. |
| 430 | - If tools don’t appear, verify the server command works from your shell and that the server supports MCP `tools/list`. |
| 431 |