diff --git a/.changeset/mcp-welcome-summary.md b/.changeset/mcp-welcome-summary.md new file mode 100644 index 00000000..79829e5e --- /dev/null +++ b/.changeset/mcp-welcome-summary.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Show MCP server summary in the welcome panel and add configuration hints in the /mcp command output. diff --git a/apps/kimi-code/src/tui/components/chrome/welcome.ts b/apps/kimi-code/src/tui/components/chrome/welcome.ts index 899139e2..4228c568 100644 --- a/apps/kimi-code/src/tui/components/chrome/welcome.ts +++ b/apps/kimi-code/src/tui/components/chrome/welcome.ts @@ -67,6 +67,10 @@ export class WelcomeComponent implements Component { labelStyle('Version: ') + this.state.version, ]; + if (this.state.mcpServersSummary) { + infoLines.push(labelStyle('MCP: ') + this.state.mcpServersSummary); + } + const contentLines: string[] = [...renderedHeaderLines, '', ...infoLines]; const lines: string[] = [ diff --git a/apps/kimi-code/src/tui/components/messages/mcp-status-panel.ts b/apps/kimi-code/src/tui/components/messages/mcp-status-panel.ts index 9b7905eb..6aee0066 100644 --- a/apps/kimi-code/src/tui/components/messages/mcp-status-panel.ts +++ b/apps/kimi-code/src/tui/components/messages/mcp-status-panel.ts @@ -138,6 +138,7 @@ export function buildMcpStatusReportLines(options: McpStatusReportOptions): stri lines.push(''); lines.push(` ${value(buildSummary(servers))}`); + lines.push(` ${muted('Configure with')} ${value('/mcp-config')}`); return lines; } diff --git a/apps/kimi-code/src/tui/controllers/session-event-handler.ts b/apps/kimi-code/src/tui/controllers/session-event-handler.ts index 27b13a13..5d2e22ac 100644 --- a/apps/kimi-code/src/tui/controllers/session-event-handler.ts +++ b/apps/kimi-code/src/tui/controllers/session-event-handler.ts @@ -104,6 +104,7 @@ export class SessionEventHandler { renderedSkillActivationIds: Set = new Set(); renderedMcpServerStatusKeys: Map = new Map(); mcpServerStatusSpinners: Map = new Map(); + mcpServers: Map = new Map(); resetRuntimeState(): void { this.backgroundAgentMetadata.clear(); @@ -112,6 +113,7 @@ export class SessionEventHandler { this.subagentInfo.clear(); this.renderedSkillActivationIds.clear(); this.renderedMcpServerStatusKeys.clear(); + this.mcpServers.clear(); this.stopAllMcpServerStatusSpinners(); } @@ -155,6 +157,10 @@ export class SessionEventHandler { this.renderMcpServerStatus(server); } + this.mcpServers.clear(); + for (const server of servers) { + this.mcpServers.set(server.name, server); + } const hidden: McpServerStatusSnapshot[] = []; for (const server of servers) { if (visibleNames.has(server.name)) continue; @@ -162,12 +168,8 @@ export class SessionEventHandler { this.renderedMcpServerStatusKeys.set(server.name, mcpServerStatusKey(server)); hidden.push(server); } - if (hidden.length > 0) { - host.showStatus( - formatMcpStartupStatusSummary(hidden, visible.length), - host.state.theme.colors.textMuted, - ); - } + const summary = formatMcpStartupStatusSummary(servers); + host.setAppState({ mcpServersSummary: summary || null }); } handleEvent(event: Event, sendQueued: (item: QueuedMessage) => void): void { @@ -582,6 +584,9 @@ export class SessionEventHandler { const key = mcpServerStatusKey(server); if (this.renderedMcpServerStatusKeys.get(server.name) === key) return; this.renderedMcpServerStatusKeys.set(server.name, key); + this.mcpServers.set(server.name, server); + const summary = formatMcpStartupStatusSummary([...this.mcpServers.values()]); + this.host.setAppState({ mcpServersSummary: summary || null }); const colors = state.theme.colors; switch (server.status) { diff --git a/apps/kimi-code/src/tui/kimi-tui.ts b/apps/kimi-code/src/tui/kimi-tui.ts index c3b3ae41..38846e90 100644 --- a/apps/kimi-code/src/tui/kimi-tui.ts +++ b/apps/kimi-code/src/tui/kimi-tui.ts @@ -173,6 +173,7 @@ function createInitialAppState(input: KimiTUIStartupInput): AppState { availableModels: {}, availableProviders: {}, sessionTitle: null, + mcpServersSummary: null, }; } @@ -1081,6 +1082,7 @@ export class KimiTUI { this.state.footer.setBackgroundCounts({ bashTasks: 0, agentTasks: 0 }); this.streamingUI.setTodoList([]); this.streamingUI.setTurnId(undefined); + this.setAppState({ mcpServersSummary: null }); this.streamingUI.setStep(0); this.streamingUI.resetLiveText(); this.updateQueueDisplay(); diff --git a/apps/kimi-code/src/tui/types.ts b/apps/kimi-code/src/tui/types.ts index 5a1a8ee4..69bb6092 100644 --- a/apps/kimi-code/src/tui/types.ts +++ b/apps/kimi-code/src/tui/types.ts @@ -32,6 +32,7 @@ export interface AppState { availableModels: Record; availableProviders: Record; sessionTitle: string | null; + mcpServersSummary: string | null; } export interface ToolCallBlockData { diff --git a/apps/kimi-code/src/tui/utils/mcp-server-status.ts b/apps/kimi-code/src/tui/utils/mcp-server-status.ts index 09fda398..53e46948 100644 --- a/apps/kimi-code/src/tui/utils/mcp-server-status.ts +++ b/apps/kimi-code/src/tui/utils/mcp-server-status.ts @@ -29,15 +29,14 @@ export function selectMcpStartupStatusRows( } export function formatMcpStartupStatusSummary( - hidden: readonly McpServerStatusSnapshot[], - visibleCount: number, + servers: readonly McpServerStatusSnapshot[], ): string { let failed = 0; let needsAuth = 0; let connecting = 0; let connected = 0; let disabled = 0; - for (const server of hidden) { + for (const server of servers) { switch (server.status) { case 'failed': failed++; @@ -63,9 +62,7 @@ export function formatMcpStartupStatusSummary( if (connecting > 0) parts.push(`${connecting} connecting`); if (connected > 0) parts.push(`${connected} connected`); if (disabled > 0) parts.push(`${disabled} disabled`); - const detail = parts.join(', '); - if (visibleCount === 0) return `MCP servers: ${detail}`; - return `MCP servers: ${hidden.length} more (${detail})`; + return parts.join(', '); } export function mcpServerStatusKey(server: McpServerStatusSnapshot): string { diff --git a/apps/kimi-code/test/tui/components/chrome/footer.test.ts b/apps/kimi-code/test/tui/components/chrome/footer.test.ts index ea9c8935..fcfc9a44 100644 --- a/apps/kimi-code/test/tui/components/chrome/footer.test.ts +++ b/apps/kimi-code/test/tui/components/chrome/footer.test.ts @@ -52,6 +52,7 @@ const appState: AppState = { notifications: { enabled: true, condition: 'unfocused' }, availableModels: {}, availableProviders: {}, + mcpServersSummary: null, }; describe('FooterComponent', () => { diff --git a/apps/kimi-code/test/tui/components/chrome/welcome.test.ts b/apps/kimi-code/test/tui/components/chrome/welcome.test.ts index 418d5667..773e39a0 100644 --- a/apps/kimi-code/test/tui/components/chrome/welcome.test.ts +++ b/apps/kimi-code/test/tui/components/chrome/welcome.test.ts @@ -29,6 +29,7 @@ const appState: AppState = { notifications: { enabled: true, condition: 'unfocused' }, availableModels: {}, availableProviders: {}, + mcpServersSummary: null, }; function truecolorCodes(text: string): Set { diff --git a/apps/kimi-code/test/tui/create-tui-state.test.ts b/apps/kimi-code/test/tui/create-tui-state.test.ts index f82d93fe..3ca65a9a 100644 --- a/apps/kimi-code/test/tui/create-tui-state.test.ts +++ b/apps/kimi-code/test/tui/create-tui-state.test.ts @@ -26,6 +26,7 @@ function fakeInitialAppState(): AppState { availableModels: {}, availableProviders: {}, sessionTitle: null, + mcpServersSummary: null, }; }