MCP server state

mandatory

Connection state visibility for every MCP server attached to a Koder client. Status chip (color-coded) + capabilities drawer + auto-reconnect + error-clear-on-success. Required for any debuggable MCP-aware product.

Spec — MCP server state

Histórico: Cursor #149363 e Claude Code #36308 — error state visualmente persistente após reconnect. Lição: state visual MUST clear automaticamente quando connection succeeds.

Princípios

  1. *lways-visible status*— todo MCP server attached é representado por um chip persistente em algum surface (header, sidebar, settings panel).
  2. *elf-healing visual*— error state NUNCA persiste após reconnect succeed; transitions são automáticas.
  3. *apabilities transparency*— user vê quais toolsresourcesprompts o server expõe.
  4. *anual override*— restart, disable, remove sempre disponível.

R1 — Status chip

Compact representation: dot (8×8dp) + server name + count badge.

🟢 my-server [12 tools]
🟡 my-server [reconnecting…]
🔴 my-server [error: timeout]
⚪ my-server [disabled]

4 states (per color-roles.kmd):

State Dot color Meaning Triggers
*onnected* success (green) Server reachable, capabilities loaded Successful initialize + at least one tools/list response
*onnecting* warning (yellow/amber) Initial handshake OR reconnect in progress Right after attach OR after error + within retry backoff
*rror* error (red) Connection failed; retries exhausted OR fatal protocol error Timeout / TLS error / protocol mismatch / server rejected
*isabled* text-muted (gray) Userdisabled OR autodisabled (too many failures) Manual toggle OR 5 consecutive errors

State transitions:

[new attach] → connecting → connected (T1 success)
                         ↘ error (T1 fail) → connecting (auto-retry) → connected (T2 success — CLEAR error!)
                                                                     ↘ error (T2 fail) ...
[manual disable] → disabled
[manual enable] → connecting
[5 consec errors] → disabled (auto)

*ritical regression contract (R4.1)* error → connecting → connected transition MUST clear the visual error state immediately upon connected. NO stale red dot. NO "still showing error after success".

R2 — Tooltip (hover / long-press)

Mouse hover (desktop) ou long-press (mobile) reveal:

my-server
status: connected
capabilities: 12 tools, 3 resources, 5 prompts
last sync: 2s ago
ping: 45ms

Error state inclui error message + last attempt timestamp + next retry ETA.

R3 — Drawer (expanded view)

Tap chip → opens drawer (sidepanel desktop, bottomsheet mobile):

┌───────────────────────────────────────────┐
│  my-server                  [status_chip] │
│  https://my-server.example.com            │
├───────────────────────────────────────────┤
│  Capabilities                             │
│  ▼ Tools (12)                             │
│    • search · readOnly · low risk         │
│    • fetch_url · readOnly · low risk      │
│    • write_file · destructive · high risk │
│    ...                                    │
│  ▼ Resources (3)                          │
│    ...                                    │
│  ▼ Prompts (5)                            │
│    ...                                    │
├───────────────────────────────────────────┤
│  Settings                                 │
│  [Auto-reconnect: ON ]                    │
│  [Keep-alive ping: 30s]                   │
├───────────────────────────────────────────┤
│  [ Restart ]   [ Disable ]   [ Remove ]   │
└───────────────────────────────────────────┘

R3.1 — Capability lists

  • Tools: name + annotation tags (readOnly / destructive / idempotent) + risk tier (crosslink `mcppermission-prompt.kmd` R2).
  • Resources: URI + MIME + size.
  • Prompts: name + description + argument schema preview.

R3.2 — Settings

  • *uto-reconnect*(default ON): exponential backoff (1s, 2s, 4s, 8s, 16s, then 30s ceiling).
  • *eep-alive ping*(default 30s): interval para ping request; failed ping triggers reconnect.
  • *ertool permission overrides* shortcut to permission store (crosslink mcp-permission-prompt.kmd R4).

R3.3 — Actions

  • *estart* graceful disconnect + new attach. UI mostra connecting → connected (T1).
  • *isable* stop reconnect attempts; state → disabled. Persists across sessions.
  • *emove* full uninstall from registry; permission entries autopurged (crosslink policies/identity-data-retention.kmd R5).

R4 — Error state lifecycle (lição Cursor + Claude Code bugs)

R4.1 — Auto-clear contract (NORMATIVE)

Quando state transitions de connectingconnected:

  1. Visual dot MUST update synchronously (next render frame).
  2. Error message MUST be removed from tooltip and drawer.
  3. Last error timestamp MUST be cleared.
  4. Capability lists MUST be reloaded from tools/list + resources/list + prompts/list (server may have changed).
  5. NO race condition where dot stays red while internal state is green.

R4.2 — Auto-disable threshold

After * consecutive connection errors*within 10 minutes: state → disabled (not error). User MUST manually re-enable. Prevents zombie retry loops draining battery / quota.

Counter resets after one connected state.

R4.3 — Error categorization

Error category Recoverable? Display
Network timeout Yes (auto-retry) "Connection timeout · retrying in 8s"
TLS/certificate No "TLS error · check server config"
Protocol mismatch No "Protocol version unsupported"
Server rejected (401/403) No (user action needed) "Authentication failed · check credentials"
Server unreachable (DNS/refused) Yes (auto-retry) "Server unreachable · retrying"
Rate limit (429) Yes (delayed retry) "Rate limited · retrying in 30s"

R5 — Multi-tenant scoping

Server registry e state per (koder_user_id, workspace_id):

  • User A em workspace 1 attach my-server → visible só pra user A em workspace 1.
  • Cross-workspace switch: state chip atualiza automaticamente.
  • Shared workspace (multiuser): server visible para todos members; state global; permission decisions peruser (crosslink `mcppermission-prompt.kmd` R4).

Storage: kdb-kv table mcp_servers:<koder_user_id>:<workspace_id>:<server_id>.

R6 — Surface bindings

Surface API
Flutter KoderMCPServerChip (compact) + KoderMCPServerDrawer (expanded) em koder_kit/lib/src/ai/
Web <koder-mcp-server-chip> + <koder-mcp-server-drawer>
Compose Android KoderMCPServerChip em koder-design-compose (futuro)
SwiftUI iOS idem em koder-design-swift (futuro)
CLI / TUI Status line: MCP: 🟢 server1 🟡 server2 🔴 server3; koder mcp status lists detalhe

R7 — Acessibilidade

  • Chip é role="status" aria-live="polite"; state change announced.
  • Dot tem aria-label="connected" etc.
  • Drawer é role="dialog" quando aberto.
  • Keyboard: Tab to chip, Enter to expand drawer, ESC to close, arrows nav lista.
  • Reduced-motion: state transitions sem animação.
  • Color contrast: dot color MUST atender AAA contrast em ambos themes (lightdark) per `themescolor-roles.kmd`.

R8 — i18n

Key en-US pt-BR
mcp.server.state.connected "Connected" "Conectado"
mcp.server.state.connecting "Connecting…" "Conectando…"
mcp.server.state.error "Error" "Erro"
mcp.server.state.disabled "Disabled" "Desativado"
mcp.server.action.restart "Restart" "Reiniciar"
mcp.server.action.disable "Disable" "Desativar"
mcp.server.action.remove "Remove" "Remover"

T-suite

  • *1*Initial attach: state shows connecting → connected; capability count populates from toolsresourcesprompts list.
  • *2*Network outage: connected → error (timeout); chip color red; tooltip mostra error message.
  • *3*Auto-retry: error → connecting → connected; *4.1 regression: error message + red dot CLEAR immediately upon connected*
  • *4*Manual restart: tap restart → connecting → connected.
  • *5*Disable: tap disable → state disabled; reconnect loop stops; capability lists hidden but cached.
  • *6*Re-enable: tap enable → connecting → connected; lists reload from server (may have changed).
  • *7*Auto-disable after 5 errors: simulate 5 timeouts within 10min → state → disabled (not error); counter resets after successful connect.
  • *8*Multi-tenant: user A attach server X → user B no workspace 2 NÃO vê server X.
  • *1*Stale state regression (Cursor #149363): connection succeeds while old error visible → assert visual updates within 1 frame.
  • *2*TLS error não dispara auto-retry (R4.3); display permanent error message.

Source: ../home/koder/dev/koder/meta/docs/stack/specs/ai-ui/mcp-server-state.kmd