You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(tui): explore a more capable MCP modal #36303
The V2 MCP modal is currently a minimal status list with an error-detail branch. It should become a useful control and diagnosis surface without turning into a dense dashboard.
@kitlangton is the design owner for this exploration.
Explore
Decide what users need to understand at a glance for pending, connected, failed, authentication-required, registration-required, and disabled servers.
Explore which actions belong directly in the list and which belong in a server detail view.
Consider enable/disable, retry or reconnect, authenticate, inspect capabilities, and error details without assuming all of them belong in the first version.
Make disabled and unavailable commands use the shared DialogSelect disabled-action treatment rather than disappearing or remaining executable.
Define loading, empty, and refresh states explicitly.
Verify narrow-terminal behavior once Drive supports deterministic viewport sizing.
Current source
packages/tui/src/component/dialog-mcp.tsx
packages/tui/src/ui/dialog-select.tsx
packages/tui/src/ui/dialog.tsx
Validation
Add deterministic opencode-drive states for pending, connected, failed with details, needs-auth, disabled, empty, and refresh behavior. The audit showed that pending-state capture needs a request barrier or controllable latency rather than screenshot sleeps.
Reproduction evidence: optional OAuth server appears connected but cannot authenticate in the TUI
Environment
OpenCode: v2.0.3
OS: Windows 11 10.0.26200.9445
Terminal: Windows Terminal, TERM=xterm-256color
Shell: C:\WINDOWS\system32\cmd.exe
Install: npm global, latest channel
Active plugins: none found
Reproduction
Configure an OAuth-capable remote MCP server that also exposes public tools.
Start OpenCode without stored OAuth credentials.
opencode mcp list and /mcps report the server as connected because anonymous initialization and public tools succeed.
Call an account-protected tool; it returns Unauthorized.
Open /mcps. The server can only be connected or disconnected with Space. Enter exposes no detail view or Authenticate action.
Run opencode mcp auth <server> externally and complete browser authorization.
Call the same protected tool again; it succeeds.
Expected behavior
The MCP modal should expose Authenticate/Re-authenticate for OAuth-capable remote servers even when their transport status is connected. Alternatively, a protected-tool authorization failure should transition the server to an actionable authentication-required state.
Actual behavior
Anonymous connectivity masks the missing OAuth session. The TUI reports connected and offers no authentication path, leaving opencode mcp auth <server> as the only working route.
This reproduces consistently with Avails. It is also the same detection ambiguity noted in #26195: an MCP server can return HTTP 200 without authentication while protected operations still require OAuth.
Context: I opened #53065 proposing an MCP observability surface before finding this exploration (and #34435, closed as completed). This is the right design track, so consolidating — closing mine with a pointer.
What I can usefully contribute to the "decide what users need to understand at a glance" checklist is failure-mode evidence: there are 10+ open MCP lifecycle issues whose diagnosis is blocked by exactly the facts a panel could surface:
Concrete data suggestion: the service already tracks per-server status internally; extending the status payload with transport type, pid, child-process count, uptime, and last error/time requires no new architecture and would give this modal a factual floor to design the states on. Happy to draft that status-payload extension as a PR if it's useful to the exploration.
Opened #56452 for the enable/disable part: space in /mcps toggles a server in any state (failed & pending too) & saves it to the config file that defines it.
Thanks @kitlangton! This is a design exploration and feature request, not a bug report, so there was nothing to reproduce: the current MCP modal (packages/tui/src/component/dialog-mcp.tsx) works as built today, a status list with an error-detail view. I've left this for the normal feature and design flow, along with the related nested-dialog work in #36302.
Narrow API prerequisite: non-booting lifecycle observations and generation-scoped terminal receipts
The V2 connect/disconnect/status APIs requested in #34435 exist; this is not another request for those endpoints or a duplicate broad observability dashboard (#53065).
On core 2.2.5 (3ba597f), the public Mcp.Server schema exposes name/status/title/integrationID, not the effective configured/client-hosted owner, connection generation or in-flight request termination. Configured server listings and effective tool routing are different: a same-name attached client may shadow configured tools, and detaching the newest client can expose an older connection. A name or tool catalog is therefore insufficient to identify the connection being stopped.
A normal status read is also not a documented no-start observation. OpenChamber 2.6.0 explicitly documents in its source that status reads can boot a directory's stdio fleet; its management UI refreshes on entry and after disconnect. This makes a passive-looking diagnosis unsuitable when no new connection is permitted.
Could the API provide a narrowly scoped read of ALREADY-loaded state, without loading a location, spawning stdio, listing tools, starting a relay, or reconnecting? Return not_loaded/unknown instead of activating anything. Expose only the authorized caller's relevant host-instance identity, effective owner kind, opaque connection generation and request phase/terminal state; do not enumerate other clients, tabs or credentials. A session ID alone must not be treated as authorization.
Pair that observation with a generation-conditional cancellation/disconnect receipt. Distinguish request acceptance, host loop interruption and actual terminal cleanup. A stale owner/generation must cause zero changes; stopping one generation must not fall back or retry onto an older same-name connection, nor affect a newer one. Unknown termination should remain unknown rather than being rendered as success. This may require server API work below the modal; it cannot be fabricated by a UI-only wrapper.
Suggested synthetic acceptance: a cold location with spawn/connect counters stays cold after observation; same-name configured/attached test generations resolve unambiguously; stale stop handles affect nothing; cancel/ready races cannot dispatch the cancelled request; unrelated synthetic pending forms and MCP connections remain unchanged. No real credentials or user-browser content are needed. These tests are proposed, not claimed executed here.
Activity
big-andy-coates commentedon Aug 19, 2026
Hey @kitlangton, +1 for being to re-authenticate mcp servers from within an active session :)
zhiganov commentedon Sep 15, 2026
Reproduction evidence: optional OAuth server appears connected but cannot authenticate in the TUI
Environment
v2.0.310.0.26200.9445TERM=xterm-256colorC:\WINDOWS\system32\cmd.exeReproduction
opencode mcp listand/mcpsreport the server asconnectedbecause anonymous initialization and public tools succeed.Unauthorized./mcps. The server can only be connected or disconnected with Space. Enter exposes no detail view or Authenticate action.opencode mcp auth <server>externally and complete browser authorization.Expected behavior
The MCP modal should expose Authenticate/Re-authenticate for OAuth-capable remote servers even when their transport status is
connected. Alternatively, a protected-tool authorization failure should transition the server to an actionable authentication-required state.Actual behavior
Anonymous connectivity masks the missing OAuth session. The TUI reports
connectedand offers no authentication path, leavingopencode mcp auth <server>as the only working route.This reproduces consistently with Avails. It is also the same detection ambiguity noted in #26195: an MCP server can return HTTP 200 without authentication while protected operations still require OAuth.
ggbdpq commentedon Oct 4, 2026
Context: I opened #53065 proposing an MCP observability surface before finding this exploration (and #34435, closed as completed). This is the right design track, so consolidating — closing mine with a pointer.
What I can usefully contribute to the "decide what users need to understand at a glance" checklist is failure-mode evidence: there are 10+ open MCP lifecycle issues whose diagnosis is blocked by exactly the facts a panel could surface:
last error + timestampwould make both diagnosable in place. mcp: mcp list reports failed while API reports connected after server reconnect #50725 (mcp listsays failed while the API says connected) is the same gap seen from the other side: two surfaces reading different state.pgrepsession.Concrete data suggestion: the service already tracks per-server status internally; extending the status payload with transport type, pid, child-process count, uptime, and last error/time requires no new architecture and would give this modal a factual floor to design the states on. Happy to draft that status-payload extension as a PR if it's useful to the exploration.
VlexWest commentedon Oct 17, 2026
Opened #56452 for the enable/disable part: space in
/mcpstoggles a server in any state (failed & pending too) & saves it to the config file that defines it.opencodejr commentedon Oct 28, 2026
Thanks @kitlangton! This is a design exploration and feature request, not a bug report, so there was nothing to reproduce: the current MCP modal (
packages/tui/src/component/dialog-mcp.tsx) works as built today, a status list with an error-detail view. I've left this for the normal feature and design flow, along with the related nested-dialog work in #36302.hiethos00-creator commentedon Nov 3, 2026
Narrow API prerequisite: non-booting lifecycle observations and generation-scoped terminal receipts
The V2 connect/disconnect/status APIs requested in #34435 exist; this is not another request for those endpoints or a duplicate broad observability dashboard (#53065).
On core 2.2.5 (3ba597f), the public Mcp.Server schema exposes name/status/title/integrationID, not the effective configured/client-hosted owner, connection generation or in-flight request termination. Configured server listings and effective tool routing are different: a same-name attached client may shadow configured tools, and detaching the newest client can expose an older connection. A name or tool catalog is therefore insufficient to identify the connection being stopped.
A normal status read is also not a documented no-start observation. OpenChamber 2.6.0 explicitly documents in its source that status reads can boot a directory's stdio fleet; its management UI refreshes on entry and after disconnect. This makes a passive-looking diagnosis unsuitable when no new connection is permitted.
Could the API provide a narrowly scoped read of ALREADY-loaded state, without loading a location, spawning stdio, listing tools, starting a relay, or reconnecting? Return not_loaded/unknown instead of activating anything. Expose only the authorized caller's relevant host-instance identity, effective owner kind, opaque connection generation and request phase/terminal state; do not enumerate other clients, tabs or credentials. A session ID alone must not be treated as authorization.
Pair that observation with a generation-conditional cancellation/disconnect receipt. Distinguish request acceptance, host loop interruption and actual terminal cleanup. A stale owner/generation must cause zero changes; stopping one generation must not fall back or retry onto an older same-name connection, nor affect a newer one. Unknown termination should remain unknown rather than being rendered as success. This may require server API work below the modal; it cannot be fabricated by a UI-only wrapper.
Suggested synthetic acceptance: a cold location with spawn/connect counters stays cold after observation; same-name configured/attached test generations resolve unambiguously; stale stop handles affect nothing; cancel/ready races cannot dispatch the cancelled request; unrelated synthetic pending forms and MCP connections remain unchanged. No real credentials or user-browser content are needed. These tests are proposed, not claimed executed here.
Sources: https://opencode.ai/v2/openapi.json ;
opencode/packages/core/src/mcp/index.ts
Lines 490 to 517 in 3ba597f
opencode/packages/core/src/mcp/index.ts
Lines 678 to 761 in 3ba597f