diff --git a/src/output.ts b/src/output.ts index 69a6195..707df0f 100644 --- a/src/output.ts +++ b/src/output.ts @@ -97,6 +97,19 @@ export function formatSearchResults( return lines.join('\n'); } +/** + * Format stdio command for safe display without leaking arguments. + */ +function formatSafeCommand(command: string, args?: string[]): string { + const argCount = args?.length ?? 0; + + if (argCount === 0) { + return command; + } + + return `${command} [${argCount} arg${argCount === 1 ? '' : 's'} hidden]`; +} + /** * Format server details */ @@ -119,7 +132,7 @@ export function formatServerDetails( } else { lines.push(`${color('Transport:', colors.bold)} stdio`); lines.push( - `${color('Command:', colors.bold)} ${config.command} ${(config.args || []).join(' ')}`, + `${color('Command:', colors.bold)} ${formatSafeCommand(config.command, config.args)}`, ); } diff --git a/tests/integration/cli.test.ts b/tests/integration/cli.test.ts index afb1e78..939eacb 100644 --- a/tests/integration/cli.test.ts +++ b/tests/integration/cli.test.ts @@ -156,6 +156,15 @@ describe('CLI Integration Tests', () => { expect(result.stdout).toContain('Tools'); }); + test('redacts stdio args from server details output', async () => { + const result = await runCli(['info', 'filesystem']); + + expect(result.exitCode).toBe(0); + expect(result.stdout).toContain('Command: npx [3 args hidden]'); + expect(result.stdout).not.toContain('@modelcontextprotocol/server-filesystem'); + expect(result.stdout).not.toContain(tempDir); + }); + test('errors on unknown server', async () => { const result = await runCli(['info', 'nonexistent_server']); diff --git a/tests/output.test.ts b/tests/output.test.ts index 518713f..722d2e9 100644 --- a/tests/output.test.ts +++ b/tests/output.test.ts @@ -6,6 +6,7 @@ import { describe, test, expect } from 'bun:test'; import { formatServerList, formatSearchResults, + formatServerDetails, formatToolSchema, formatToolResult, formatJson, @@ -101,6 +102,36 @@ describe('output', () => { }); }); + describe('formatServerDetails', () => { + test('hides stdio arguments in server details', () => { + const output = formatServerDetails( + 'github', + { + command: 'npx', + args: ['-y', '@modelcontextprotocol/server-github', 'ghp_secret123'], + }, + [] + ); + + expect(output).toContain('Command:'); + expect(output).toContain('npx [3 args hidden]'); + expect(output).not.toContain('@modelcontextprotocol/server-github'); + expect(output).not.toContain('ghp_secret123'); + }); + + test('shows bare command when no args are present', () => { + const output = formatServerDetails( + 'custom', + { + command: 'my-server', + }, + [] + ); + + expect(output).toContain('Command: my-server'); + }); + }); + describe('formatToolSchema', () => { test('formats tool with schema', () => { const tool = {