diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index eb8ed2d9bbad..534636f3fe15 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -318,6 +318,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 9466ae54f2d0..6b5a49a6c14f 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 29e958fe3572..6cf24c6b4ea2 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -283,6 +283,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, } @@ -505,6 +508,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 b757b7535075..1948f5430773 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, @@ -2880,7 +2881,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 8555e84384ff..bca3f99ae654 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -671,6 +671,13 @@ export type EventTuiPromptAppend = { } } +export type EventTuiMcpRefresh = { + type: "tui.mcp.refresh" + properties: { + [key: string]: unknown + } +} + export type EventTuiCommandExecute = { type: "tui.command.execute" properties: { @@ -908,6 +915,7 @@ export type Event = | EventFileWatcherUpdated | EventTodoUpdated | EventTuiPromptAppend + | EventTuiMcpRefresh | EventTuiCommandExecute | EventTuiToastShow | EventTuiSessionSelect @@ -4679,7 +4687,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