diff --git a/src/output.ts b/src/output.ts index 69a6195..863f988 100644 --- a/src/output.ts +++ b/src/output.ts @@ -2,6 +2,7 @@ * Output formatting utilities */ +import { basename } from 'node:path'; import type { ToolInfo } from './client.js'; import type { ServerConfig } from './config.js'; import { isHttpServer } from './config.js'; @@ -97,6 +98,21 @@ export function formatSearchResults( return lines.join('\n'); } +/** + * Format stdio command details without leaking full argument values. + */ +function formatStdioCommand(command: string, args?: string[]): string { + const executable = basename(command); + const argCount = args?.length ?? 0; + + if (argCount === 0) { + return executable; + } + + const suffix = argCount === 1 ? 'argument' : 'arguments'; + return `${executable} (${argCount} hidden ${suffix})`; +} + /** * Format server details */ @@ -119,7 +135,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)} ${formatStdioCommand(config.command, config.args)}`, ); } diff --git a/tests/output.test.ts b/tests/output.test.ts index 518713f..098a800 100644 --- a/tests/output.test.ts +++ b/tests/output.test.ts @@ -2,14 +2,15 @@ * Unit tests for output formatting */ -import { describe, test, expect } from 'bun:test'; +import { describe, expect, test } from 'bun:test'; import { - formatServerList, + formatError, + formatJson, formatSearchResults, - formatToolSchema, + formatServerDetails, + formatServerList, formatToolResult, - formatJson, - formatError, + formatToolSchema, } from '../src/output'; // Disable colors for testing @@ -101,6 +102,36 @@ describe('output', () => { }); }); + describe('formatServerDetails', () => { + test('redacts stdio args in server info output', () => { + const output = formatServerDetails( + 'secret-server', + { + command: '/usr/bin/node', + args: ['server.js', '--api-key', 'super-secret-token'], + }, + [], + ); + + expect(output).toContain('Command: node (3 hidden arguments)'); + expect(output).not.toContain('super-secret-token'); + expect(output).not.toContain('--api-key'); + expect(output).not.toContain('server.js'); + }); + + test('shows plain executable when stdio server has no args', () => { + const output = formatServerDetails( + 'simple-server', + { + command: '/usr/local/bin/uvx', + }, + [], + ); + + expect(output).toContain('Command: uvx'); + }); + }); + describe('formatToolSchema', () => { test('formats tool with schema', () => { const tool = {