diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 3b296a927aa..5758aa9afed 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -345,6 +345,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 9466ae54f2d..6b5a49a6c14 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 e48a42a8b34..25cda11c2bf 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -320,6 +320,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, } @@ -548,6 +551,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 2bb2edcd175..8b2a7b2b51b 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -21,6 +21,7 @@ import type { ConfigUpdateResponses, EventSubscribeResponses, EventTuiCommandExecute, + EventTuiMcpRefresh, EventTuiPromptAppend, EventTuiSessionSelect, EventTuiToastShow, @@ -3490,7 +3491,12 @@ export class Tui extends HeyApiClient { parameters?: { directory?: string workspace?: 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 a47b18db219..49e72c6762a 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -723,6 +723,13 @@ export type EventTuiPromptAppend = { } } +export type EventTuiMcpRefresh = { + type: "tui.mcp.refresh" + properties: { + [key: string]: unknown + } +} + export type EventTuiCommandExecute = { type: "tui.command.execute" properties: { @@ -983,6 +990,7 @@ export type Event = | EventFileWatcherUpdated | EventTodoUpdated | EventTuiPromptAppend + | EventTuiMcpRefresh | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect @@ -4684,7 +4692,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