On this page
Commander MCP services - umbrellas, commands, scopes and workflows
The commander-mcp gateway is the half of Commander's MCP story that faces inbound: a chat client - Claude on the web or desktop, ChatGPT, MCP Inspector, any client that speaks Streamable HTTP - signs in once and operates Commander through a small set of umbrella tools. The other half, Commander handing MCP connections to the agents it launches, is described under the application page.
At this version the gateway serves 15 umbrella tools with 70 commands - 51 of them read-only, 4 destructive - plus two resources and one prompt per persona. It is published at <commander origin>/mcp (for example https://commander-dev.myorg.ai/mcp), with OAuth discovery served for that path. Commander proxies the path to the gateway process (commander-mcp-dev on dev, commander-mcp on prod), so a client needs one hostname and nothing else.
Three boxes a call crosses
- The MCP client holds an access token minted by the gateway's own OAuth server after the operator signed in on the consent page and ticked scopes.
- The gateway verifies the token locally, resolves the caller's role, checks scope → phase → role, validates the command's parameters, and relays over the loopback to Commander with a service token - acting as the signed-in subject, which Commander logs as
acting=<subject>. - Commander answers the same REST API the browser uses. The gateway redacts the result (tokens, keys, PEM blocks, ANSI, invisible characters), frames anything agent-written as untrusted content, caps its size, and writes one audit row per call - denials included.
The umbrellas
Every tool is an umbrella: one MCP tool name, a command enum, and per-command parameters spelled out in the tool description. Call _hello first - it returns identity, role, effective phases and scopes, and a plan for the intent you state. Commands marked write need a phase above 0; destructive commands need confirm: true and are refused on prod.
| umbrella | phase | commands |
|---|---|---|
_hello | 0 | single call - identity, capabilities, a plan |
projects | 0 | list · get · environments · update (write) |
sessions | 0 | list · get · status · rename (write) · archive · restore · restart (destructive) · kill (destructive) |
transcripts | 0 | search · messages · session_log · stats · kinds |
artifacts | 0 | list · get · raw · rescan (write) |
personas | 0 | list · get · skill_packs · update · bind_skills · bind_subagents (writes) |
git | 0 | status · log · branches · commit_details · file_at_ref · diff · file_history - read-only; committing is not exposed |
deploy | 1 | status · history · releases · release · rollback_candidates - read-only; promote and rollback are never exposed |
workboard | 0 | tasks.list · tasks.create · tasks.update · tasks.delete (destructive) · notes.list · notes.patch · prompts.list · prompts.create · prompts.delete (destructive) · shots.list · roadmap · changelog |
usage | 0 | summary · hourly · window · session |
health | 0 | heartbeat · logs · activity · system · disk · deps · guardian |
settings | 1 | tunables.list · tunables.set (admin) · settings.get - registry tunables only; secrets are never readable |
access | 0 | me · roles · principals · grant · revoke - who may do what (admin scope for the last three) |
search | 0 | single call - the ChatGPT-shaped full-text façade over projects, sessions, artifacts and prompts |
fetch | 0 | single call - the full record behind a search result id |
Resources: commander://project/{slug}/sessions (a project's sessions; slug, short id or uuid) and commander://session/{id}/brief (Commander's own redacted conversation log). Prompts: every persona is offered as persona:<id>; the body is redacted, size-capped and scope-checked before it leaves.
Not on the list, on purpose: promote, rollback, pm2 restart, the Password Vault, Integrations, service accounts, license activation, the login seam and file uploads. Those remain the operator's hand in the browser.
Three gates every command passes
- Scope - what the human granted on the consent page.
- Phase - what the operator enabled on the instance (
mcp_gateway_enable_phases: 0 read-only, 1 workboard/persona/settings writes, 2 session control). Dev runs 0,1,2; prod stays at 0 by policy. - Role - what the operator assigned to the connector (or, in Auth mode, the signed-in subject). Effective power is role ∩ instance phases ∩ token scopes. Absent a grant, the default role applies (
mcp_gateway_default_role, normallyvisitor). Grants take effect on the next call, no reconnect needed.
| scope | unlocks | phase |
|---|---|---|
commander:read | every read-only command, both resources, persona prompts, search and fetch | 0 |
commander:workboard | projects.update · sessions.rename · artifacts.rescan · persona writes · workboard writes | 1 |
commander:sessions.write | sessions archive / restore / restart / kill | 2 |
commander:git.write | reserved - git stays read-only today | 1 |
commander:terminal | reserved - no handler in the registry | 2 |
commander:admin | settings.tunables.set, access grants, plus everything above | 1 |
| role | phases | scope ceiling |
|---|---|---|
visitor (default) | 0 | read |
editor | 0, 1 | read · workboard · git.write |
operator | 0, 1, 2 | + sessions.write · terminal |
admin | 0, 1, 2 | + admin |
Workflows
Connecting Claude (web or desktop)
- Add the connector - Settings → Connectors → Add custom connector →
<commander origin>/mcp. - Discovery - the client reads the protected-resource metadata (RFC 9728) and the authorization-server metadata (RFC 8414) the gateway publishes for its path.
- Registration - dynamic client registration (RFC 7591), bounded by rate, count and redirect-host rules; PKCE-only public clients.
- Consent - the gateway's login page takes the Commander app password and shows the requested scopes as checkboxes; grant a subset if you like.
- Token - authorization code → ES256 access token (1 h by default) + rotating refresh token (30 d). A replayed code revokes exactly its own lineage.
- Tools appear - namespaced by umbrella; destructive commands carry a hint so Claude asks before sending
confirm: true.
The step-by-step with screenshots and troubleshooting is on Connect a chat client to Commander over MCP.
Connecting ChatGPT
Create the connector with the same URL and OAuth. Standard connectors and Deep Research use only search and fetch; Developer Mode exposes the full umbrella set under the same scopes, phases and roles.
One tool call, end to end
- Transport -
POST /mcpwith a Bearer token verified locally (issuer, audience per RFC 8707, expiry, key id). Batches and sessions per subject are capped; a session'sDELETEmust come from its owner. - Resolve - umbrella and command are looked up on null-prototype maps; an unknown or phase-disabled command is refused by name, never silently hidden.
- Gates - missing scope →
-32001 Insufficient scope; destructive withoutconfirm: true→ an error that tells the model to ask the human and re-issue. - Validate and relay - parameters are validated against the command's schema;
commandandconfirmnever leak upstream. - Shape the result - structured content first; text is redacted, framed as untrusted with a per-call nonce, and capped at
mcp_gateway_result_max_bytes; long lists come back as one line per row. - Audit - one row per call with subject, client, tool, command, argument hash, outcome and latency. When the operator turns audit detail up, redacted arguments and results are kept for a bounded time as well, and every gateway session has its own id so a run can be studied afterwards.
Rolling out (operator, in short)
- Mint the service token with
scripts/mcp-gateway-setup.js --instance dev- it lands insecrets.envand the Password Vault, never in chat or git. - Start the gateway process with pm2 (
--only commander-mcp-dev); Commander itself is not restarted. - Publish it:
mcp_gateway_enabled,mcp_gateway_public_url(<origin>/mcp), and the reverse-proxy contexts for/mcpand the well-known discovery paths. - Phase 0 first, for as long as it takes to trust the audit trail; then 0,1 and 0,1,2 on dev. Phases are read at gateway boot - restart the gateway, not Commander.
- Revoke a client or subject from the runbook when needed; every token lineage is traceable to the code that issued it.
Tunables the operator owns
All live under Settings → Advanced → MCP gateway and resolve settings row → environment → named default.
| setting | default | what it governs |
|---|---|---|
mcp_gateway_enabled | false | whether Commander publishes the gateway (proxy + client-config) |
mcp_gateway_public_url | - | the URL clients are told to use (<origin>/mcp) |
mcp_gateway_upstream | http://127.0.0.1:3212 | where Commander proxies /mcp to |
mcp_gateway_proxy_connect_timeout_ms | 5000 | connect budget for that proxy hop |
mcp_gateway_enable_phases | 0 | tool phases served; read at gateway boot |
mcp_gateway_default_role | visitor | role for a connector with no grant |
mcp_gateway_roles | - | JSON override of the role catalogue |
mcp_gateway_access_token_ttl_s | 3600 | access token lifetime |
mcp_gateway_refresh_token_ttl_s | 2 592 000 | refresh token lifetime (30 d), rotating |
mcp_gateway_code_ttl_s | 300 | authorization-code lifetime |
mcp_gateway_dcr_enabled | true | dynamic client registration on/off |
mcp_gateway_login_rate_max | 10 | consent-page login attempts per window |
mcp_gateway_rate_limit_per_min | 60 | tool calls per subject per minute |
mcp_gateway_result_max_bytes | 65 536 | cap on any single tool result |
mcp_gateway_upstream_timeout_ms | 15 000 | loopback call budget to Commander |
mcp_gateway_request_log | true | Commander logs acting=<subject> on relayed requests |
mcp_gateway_audit_detail | hash | hash · args · args+result - how much of each call the audit keeps |
mcp_gateway_audit_max_bytes | 16 384 | cap on a kept argument object / result text |
mcp_gateway_audit_detail_retention_days | 14 | after this, kept bodies are blanked (rows and hashes stay) |
The other direction: Commander as a consumer
Commander also uses MCP servers. The broker resolves each credential path into one resolved connection that the per-session .mcp.json writer consumes when an agent is launched, and revokes tokens at session end. The gateway described here never touches that path; the two share only Commander's settings and audit conventions.
Reserved, not built
The terminal umbrella and git.commit have scopes but no handlers. ChatGPT Apps SDK widgets are a separate phase.
You've seen the proof
Ready for a number? Scope your deployment and we'll price it against your own economics.
Get your quote →