From a7e439acfe9f09ea33edb63dae698cc7738d31d5 Mon Sep 17 00:00:00 2001 From: Kyle Altendorf Date: Tue, 6 Jan 2026 14:53:16 -0500 Subject: [PATCH] fix(tui): display dynamically registered MCP servers in status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MCP servers registered via POST /mcp were working (tools available) but not appearing in the TUI /status dialog. This was because MCP.status() only returned config-based servers, and the TUI didn't refresh after dynamic registration. Changes: - MCP.status() now includes dynamically registered MCPs from state - Added TuiEvent.McpRefresh event to signal MCP status changes - MCP.add() publishes McpRefresh when a new server is added - TUI sync context listens for McpRefresh and refetches status 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- packages/opencode/src/cli/cmd/tui/context/sync.tsx | 5 +++++ packages/opencode/src/cli/cmd/tui/event.ts | 1 + packages/opencode/src/mcp/index.ts | 10 ++++++++++ packages/sdk/js/src/v2/gen/sdk.gen.ts | 8 +++++++- packages/sdk/js/src/v2/gen/types.gen.ts | 10 +++++++++- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 8a14d8b2e77..543cc71e9d6 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -257,6 +257,11 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ break } + case "tui.mcp.refresh": { + sdk.client.mcp.status().then((x) => setStore("mcp", reconcile(x.data!))) + break + } + case "vcs.branch.updated": { setStore("vcs", { branch: event.properties.branch }) break diff --git a/packages/opencode/src/cli/cmd/tui/event.ts b/packages/opencode/src/cli/cmd/tui/event.ts index 7c75523c136..56ba24931ca 100644 --- a/packages/opencode/src/cli/cmd/tui/event.ts +++ b/packages/opencode/src/cli/cmd/tui/event.ts @@ -4,6 +4,7 @@ import z from "zod" export const TuiEvent = { PromptAppend: BusEvent.define("tui.prompt.append", z.object({ text: z.string() })), + McpRefresh: BusEvent.define("tui.mcp.refresh", z.object({})), CommandExecute: BusEvent.define( "tui.command.execute", z.object({ diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index aca0c663152..4ea0be15d83 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -269,6 +269,9 @@ export namespace MCP { s.clients[name] = result.mcpClient s.status[name] = result.status + // Notify TUI to refresh MCP status + Bus.publish(TuiEvent.McpRefresh, {}) + return { status: s.status, } @@ -488,6 +491,13 @@ export namespace MCP { result[key] = s.status[key] ?? { status: "disabled" } } + // Include dynamically registered MCPs not in config + for (const [key, status] of Object.entries(s.status)) { + if (!(key in result)) { + result[key] = status + } + } + return result } diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index a26cefb176f..7f247e38d37 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -18,6 +18,7 @@ import type { ConfigUpdateResponses, EventSubscribeResponses, EventTuiCommandExecute, + EventTuiMcpRefresh, EventTuiPromptAppend, EventTuiSessionSelect, EventTuiToastShow, @@ -2804,7 +2805,12 @@ export class Tui extends HeyApiClient { public publish( parameters?: { directory?: string - body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect + body?: + | EventTuiPromptAppend + | EventTuiMcpRefresh + | EventTuiCommandExecute + | EventTuiToastShow + | EventTuiSessionSelect }, options?: Options, ) { diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index fb3be8208ac..09502bc1f56 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -565,6 +565,13 @@ export type EventTuiPromptAppend = { } } +export type EventTuiMcpRefresh = { + type: "tui.mcp.refresh" + properties: { + [key: string]: unknown + } +} + export type EventTuiCommandExecute = { type: "tui.command.execute" properties: { @@ -792,6 +799,7 @@ export type Event = | EventFileEdited | EventTodoUpdated | EventTuiPromptAppend + | EventTuiMcpRefresh | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect @@ -4441,7 +4449,7 @@ export type TuiShowToastResponses = { export type TuiShowToastResponse = TuiShowToastResponses[keyof TuiShowToastResponses] export type TuiPublishData = { - body?: EventTuiPromptAppend | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect + body?: EventTuiPromptAppend | EventTuiMcpRefresh | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect path?: never query?: { directory?: string