From 05750836b8ff00fcb612f472824c2281c9ea9d5f Mon Sep 17 00:00:00 2001 From: Luca Martial Date: Tue, 19 May 2026 00:39:02 +0200 Subject: [PATCH] feat(cli): clarify MCP start output --- .../cli/src/commands/mcp-commands.test.ts | 38 ++++++++++++++++++- packages/cli/src/commands/mcp-commands.ts | 17 ++++++--- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/mcp-commands.test.ts b/packages/cli/src/commands/mcp-commands.test.ts index 9a54f22a..29235bce 100644 --- a/packages/cli/src/commands/mcp-commands.test.ts +++ b/packages/cli/src/commands/mcp-commands.test.ts @@ -79,7 +79,43 @@ describe('registerMcpCommands', () => { expect(startDaemon).toHaveBeenCalledTimes(1); expect(context.io.stdout.write).toHaveBeenCalledWith( - 'KTX MCP daemon already running: http://127.0.0.1:7878/mcp\n', + [ + 'KTX MCP daemon already running: http://127.0.0.1:7878/mcp', + '', + 'KTX is ready for configured agents.', + 'Open your agent for this KTX project and ask a data question, for example:', + ' "Use KTX to show me the available tables and metrics."', + '', + ].join('\n'), + ); + }); + + it('prints a friendly next step after starting the daemon', async () => { + const program = new Command().exitOverride().option('--project-dir '); + const startDaemon = vi.fn().mockResolvedValue({ + status: 'started', + url: 'http://127.0.0.1:7878/mcp', + state: { + schemaVersion: 1, + pid: 4242, + host: '127.0.0.1', + port: 7878, + tokenAuth: false, + projectDir: '/tmp/ktx-started', + startedAt: '2026-05-14T00:00:00.000Z', + logPath: '/tmp/ktx-started/.ktx/logs/mcp.log', + }, + }); + const context = makeContext({ deps: { mcp: { startDaemon } } }); + registerMcpCommands(program, context); + + await program.parseAsync(['--project-dir', '/tmp/ktx-started', 'mcp', 'start'], { from: 'user' }); + + expect(context.io.stdout.write).toHaveBeenCalledWith( + expect.stringContaining('KTX MCP daemon started: http://127.0.0.1:7878/mcp\n\nKTX is ready for configured agents.'), + ); + expect(context.io.stdout.write).toHaveBeenCalledWith( + expect.stringContaining('"Use KTX to show me the available tables and metrics."'), ); }); diff --git a/packages/cli/src/commands/mcp-commands.ts b/packages/cli/src/commands/mcp-commands.ts index 9e583ce4..be7044a7 100644 --- a/packages/cli/src/commands/mcp-commands.ts +++ b/packages/cli/src/commands/mcp-commands.ts @@ -25,6 +25,17 @@ function binPath(): string { return fileURLToPath(new URL('../bin.js', import.meta.url)); } +function formatMcpStartResultMessage(input: { status: 'started' | 'already-running'; url: string }): string { + return [ + input.status === 'started' ? `KTX MCP daemon started: ${input.url}` : `KTX MCP daemon already running: ${input.url}`, + '', + 'KTX is ready for configured agents.', + 'Open your agent for this KTX project and ask a data question, for example:', + ' "Use KTX to show me the available tables and metrics."', + '', + ].join('\n'); +} + export function registerMcpCommands(program: Command, context: KtxCliCommandContext): void { const mcp = program.command('mcp').description('Run the KTX MCP HTTP server'); @@ -82,11 +93,7 @@ export function registerMcpCommands(program: Command, context: KtxCliCommandCont allowedOrigins: options.allowedOrigin, binPath: binPath(), }); - context.io.stdout.write( - result.status === 'started' - ? `KTX MCP daemon started: ${result.url}\n` - : `KTX MCP daemon already running: ${result.url}\n`, - ); + context.io.stdout.write(formatMcpStartResultMessage({ status: result.status, url: result.url })); }); mcp