Skip to content

Commit ef1a4d5

Browse files
committed
Add --json output docs to help text and tools-call example to tools-get
Document the JSON output shape (MCP object types) in --help for all commands that support --json, so AI agents know what to expect when scripting. tools-get now shows an example tools-call command with placeholder arguments derived from the tool's schema (required params first, filling optional up to 3). https://claude.ai/code/session_01JCmVVCvBbxPUrxy3BcgjCc
1 parent 8fd3fc8 commit ef1a4d5

5 files changed

Lines changed: 265 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- `--json` output documentation in `--help` for all commands, describing the MCP object shape returned
13+
- `tools-get` now shows an example `tools-call` command with placeholder arguments based on the tool's schema
14+
1015
## [0.2.4] - 2026-04-07
1116

1217
### Security

src/cli/commands/tools.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
import ora from 'ora';
66
import chalk from 'chalk';
7-
import { formatOutput, formatToolDetail, formatSuccess, formatWarning } from '../output.js';
7+
import {
8+
formatOutput,
9+
formatToolDetail,
10+
formatToolCallExample,
11+
formatSuccess,
12+
formatWarning,
13+
} from '../output.js';
814
import { ClientError } from '../../lib/errors.js';
915
import type { CommandOptions, TaskUpdate } from '../../lib/types.js';
1016
import { withMcpClient } from '../helpers.js';
@@ -85,6 +91,10 @@ export async function getTool(
8591

8692
if (options.outputMode === 'human') {
8793
console.log(formatToolDetail(tool));
94+
const example = formatToolCallExample(tool, target);
95+
if (example) {
96+
console.log('\n' + example + '\n');
97+
}
8898
} else {
8999
console.log(formatOutput(tool, 'json'));
90100
}

src/cli/index.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ Full docs: ${docsUrl}`
402402
${chalk.bold('Server formats:')}
403403
mcp.apify.com Remote HTTP server (https:// added automatically)
404404
~/.vscode/mcp.json:puppeteer Config file entry (file:entry)
405+
406+
${chalk.bold('JSON output (--json):')}\n MCP InitializeResult: { protocolVersion, capabilities, serverInfo, instructions?, tools? }
405407
`
406408
)
407409
.action(async (server, sessionName, opts, command) => {
@@ -460,6 +462,10 @@ ${chalk.bold('Server formats:')}
460462
.command('close [@session]')
461463
.usage('<@session>')
462464
.description('Close a session')
465+
.addHelpText(
466+
'after',
467+
`\n${chalk.bold('JSON output (--json):')}\n { sessionName, closed: true }\n`
468+
)
463469
.action(async (sessionName, _opts, command) => {
464470
if (!sessionName) {
465471
throw new ClientError('Missing required argument: @session\n\nExample: mcpc close @myapp');
@@ -508,6 +514,10 @@ ${chalk.bold('Server formats:')}
508514
'--client-secret <secret>',
509515
'OAuth client secret (for servers without dynamic client registration)'
510516
)
517+
.addHelpText(
518+
'after',
519+
`\n${chalk.bold('JSON output (--json):')}\n { profile, serverUrl, scopes }\n`
520+
)
511521
.action(async (server, opts, command) => {
512522
if (!server) {
513523
throw new ClientError(
@@ -529,6 +539,10 @@ ${chalk.bold('Server formats:')}
529539
.usage('<server>')
530540
.description('Delete an OAuth profile for a server')
531541
.option('--profile <name>', 'Profile name (default: "default")')
542+
.addHelpText(
543+
'after',
544+
`\n${chalk.bold('JSON output (--json):')}\n { profile, serverUrl, deleted: true, affectedSessions }\n`
545+
)
532546
.action(async (server, opts, command) => {
533547
if (!server) {
534548
throw new ClientError(
@@ -555,6 +569,9 @@ ${chalk.bold('Resources:')}
555569
all Remove all of the above
556570
557571
Without arguments, performs safe cleanup of stale data only.
572+
573+
${chalk.bold('JSON output (--json):')}
574+
{ crashedBridges, expiredSessions, orphanedBridgeLogs, sessions, profiles, logs }
558575
`
559576
)
560577
.action(async (resources: string[], _opts, command) => {
@@ -606,6 +623,9 @@ ${chalk.bold('Examples:')}
606623
mcpc @apify grep "actor" Search within a single session
607624
mcpc grep "file" --json JSON output for scripting
608625
mcpc grep "actor" -m 5 Show at most 5 results
626+
627+
${chalk.bold('JSON output (--json):')}
628+
[{ sessionName, tools?: Tool[], resources?: Resource[], prompts?: Prompt[], instructions?: string[] }]
609629
`
610630
)
611631
.action(async (pattern, opts, command) => {
@@ -703,6 +723,10 @@ function registerSessionCommands(program: Command, session: string): void {
703723
program
704724
.command('help')
705725
.description('Show server instructions and available capabilities')
726+
.addHelpText(
727+
'after',
728+
`\n${chalk.bold('JSON output (--json):')}\n MCP InitializeResult: { protocolVersion, capabilities, serverInfo, instructions?, tools? }\n`
729+
)
706730
.action(async (_options, command) => {
707731
await sessions.showHelp(session, getOptionsFromCommand(command));
708732
});
@@ -736,6 +760,10 @@ function registerSessionCommands(program: Command, session: string): void {
736760
.command('tools')
737761
.description('List available tools (shorthand for tools-list)')
738762
.option('--full', 'Show full tool details including complete input schema')
763+
.addHelpText(
764+
'after',
765+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP Tool objects: [{ name, description?, inputSchema, annotations? }, ...]\n`
766+
)
739767
.action(async (_options, command) => {
740768
await tools.listTools(session, getOptionsFromCommand(command));
741769
});
@@ -744,13 +772,21 @@ function registerSessionCommands(program: Command, session: string): void {
744772
.command('tools-list')
745773
.description('List available tools')
746774
.option('--full', 'Show full tool details including complete input schema')
775+
.addHelpText(
776+
'after',
777+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP Tool objects: [{ name, description?, inputSchema, annotations? }, ...]\n`
778+
)
747779
.action(async (_options, command) => {
748780
await tools.listTools(session, getOptionsFromCommand(command));
749781
});
750782

751783
program
752784
.command('tools-get <name>')
753785
.description('Get information about a specific tool')
786+
.addHelpText(
787+
'after',
788+
`\n${chalk.bold('JSON output (--json):')}\n MCP Tool object: { name, description?, inputSchema, annotations? }\n`
789+
)
754790
.action(async (name, _options, command) => {
755791
await tools.getTool(session, name, getOptionsFromCommand(command));
756792
});
@@ -760,6 +796,10 @@ function registerSessionCommands(program: Command, session: string): void {
760796
.description('Call a tool with arguments (key:=value pairs or JSON)')
761797
.option('--task', 'Use task execution (experimental)')
762798
.option('--detach', 'Start task and return immediately with task ID (implies --task)')
799+
.addHelpText(
800+
'after',
801+
`\n${chalk.bold('JSON output (--json):')}\n MCP CallToolResult: { content: [{ type, text?, ... }], isError?, structuredContent? }\n`
802+
)
763803
.action(async (name, args, options, command) => {
764804
await tools.callTool(session, name, {
765805
args,
@@ -773,20 +813,32 @@ function registerSessionCommands(program: Command, session: string): void {
773813
program
774814
.command('tasks-list')
775815
.description('List active tasks')
816+
.addHelpText(
817+
'after',
818+
`\n${chalk.bold('JSON output (--json):')}\n { tasks: [{ taskId, status, statusMessage?, createdAt?, lastUpdatedAt? }, ...] }\n`
819+
)
776820
.action(async (_options, command) => {
777821
await tasks.listTasks(session, getOptionsFromCommand(command));
778822
});
779823

780824
program
781825
.command('tasks-get <taskId>')
782826
.description('Get status of a specific task')
827+
.addHelpText(
828+
'after',
829+
`\n${chalk.bold('JSON output (--json):')}\n MCP Task object: { taskId, status, statusMessage?, createdAt?, lastUpdatedAt? }\n`
830+
)
783831
.action(async (taskId, _options, command) => {
784832
await tasks.getTask(session, taskId, getOptionsFromCommand(command));
785833
});
786834

787835
program
788836
.command('tasks-cancel <taskId>')
789837
.description('Cancel a running task')
838+
.addHelpText(
839+
'after',
840+
`\n${chalk.bold('JSON output (--json):')}\n MCP Task object: { taskId, status, statusMessage? }\n`
841+
)
790842
.action(async (taskId, _options, command) => {
791843
await tasks.cancelTask(session, taskId, getOptionsFromCommand(command));
792844
});
@@ -795,13 +847,21 @@ function registerSessionCommands(program: Command, session: string): void {
795847
program
796848
.command('resources')
797849
.description('List available resources (shorthand for resources-list)')
850+
.addHelpText(
851+
'after',
852+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP Resource objects: [{ uri, name?, description?, mimeType? }, ...]\n`
853+
)
798854
.action(async (_options, command) => {
799855
await resources.listResources(session, getOptionsFromCommand(command));
800856
});
801857

802858
program
803859
.command('resources-list')
804860
.description('List available resources')
861+
.addHelpText(
862+
'after',
863+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP Resource objects: [{ uri, name?, description?, mimeType? }, ...]\n`
864+
)
805865
.action(async (_options, command) => {
806866
await resources.listResources(session, getOptionsFromCommand(command));
807867
});
@@ -811,6 +871,10 @@ function registerSessionCommands(program: Command, session: string): void {
811871
.description('Get a resource by URI')
812872
.option('-o, --output <file>', 'Write resource to file')
813873
.option('--max-size <bytes>', 'Maximum resource size in bytes')
874+
.addHelpText(
875+
'after',
876+
`\n${chalk.bold('JSON output (--json):')}\n MCP ReadResourceResult: { contents: [{ uri, mimeType?, text? | blob? }] }\n`
877+
)
814878
.action(async (uri, options, command) => {
815879
await resources.getResource(session, uri, {
816880
output: options.output,
@@ -822,20 +886,32 @@ function registerSessionCommands(program: Command, session: string): void {
822886
program
823887
.command('resources-subscribe <uri>')
824888
.description('Subscribe to resource updates')
889+
.addHelpText(
890+
'after',
891+
`\n${chalk.bold('JSON output (--json):')}\n { subscribed: true, uri: string }\n`
892+
)
825893
.action(async (uri, _options, command) => {
826894
await resources.subscribeResource(session, uri, getOptionsFromCommand(command));
827895
});
828896

829897
program
830898
.command('resources-unsubscribe <uri>')
831899
.description('Unsubscribe from resource updates')
900+
.addHelpText(
901+
'after',
902+
`\n${chalk.bold('JSON output (--json):')}\n { unsubscribed: true, uri: string }\n`
903+
)
832904
.action(async (uri, _options, command) => {
833905
await resources.unsubscribeResource(session, uri, getOptionsFromCommand(command));
834906
});
835907

836908
program
837909
.command('resources-templates-list')
838910
.description('List available resource templates')
911+
.addHelpText(
912+
'after',
913+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP ResourceTemplate objects: [{ uriTemplate, name?, description?, mimeType? }, ...]\n`
914+
)
839915
.action(async (_options, command) => {
840916
await resources.listResourceTemplates(session, getOptionsFromCommand(command));
841917
});
@@ -844,20 +920,32 @@ function registerSessionCommands(program: Command, session: string): void {
844920
program
845921
.command('prompts')
846922
.description('List available prompts (shorthand for prompts-list)')
923+
.addHelpText(
924+
'after',
925+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP Prompt objects: [{ name, description?, arguments?: [{ name, description?, required? }] }, ...]\n`
926+
)
847927
.action(async (_options, command) => {
848928
await prompts.listPrompts(session, getOptionsFromCommand(command));
849929
});
850930

851931
program
852932
.command('prompts-list')
853933
.description('List available prompts')
934+
.addHelpText(
935+
'after',
936+
`\n${chalk.bold('JSON output (--json):')}\n Array of MCP Prompt objects: [{ name, description?, arguments?: [{ name, description?, required? }] }, ...]\n`
937+
)
854938
.action(async (_options, command) => {
855939
await prompts.listPrompts(session, getOptionsFromCommand(command));
856940
});
857941

858942
program
859943
.command('prompts-get <name> [args...]')
860944
.description('Get a prompt by name with arguments (key:=value pairs or JSON)')
945+
.addHelpText(
946+
'after',
947+
`\n${chalk.bold('JSON output (--json):')}\n MCP GetPromptResult: { description?, messages: [{ role, content: { type, text?, ... } }] }\n`
948+
)
861949
.action(async (name, args, _options, command) => {
862950
await prompts.getPrompt(session, name, {
863951
args,
@@ -871,6 +959,7 @@ function registerSessionCommands(program: Command, session: string): void {
871959
.description(
872960
'Set server logging level (debug, info, notice, warning, error, critical, alert, emergency)'
873961
)
962+
.addHelpText('after', `\n${chalk.bold('JSON output (--json):')}\n { level: string }\n`)
874963
.action(async (level, _options, command) => {
875964
await logging.setLogLevel(session, level, getOptionsFromCommand(command));
876965
});
@@ -879,6 +968,10 @@ function registerSessionCommands(program: Command, session: string): void {
879968
program
880969
.command('ping')
881970
.description('Ping the MCP server to check if it is alive')
971+
.addHelpText(
972+
'after',
973+
`\n${chalk.bold('JSON output (--json):')}\n { success: true, durationMs: number }\n`
974+
)
882975
.action(async (_options, command) => {
883976
await utilities.ping(session, getOptionsFromCommand(command));
884977
});

src/cli/output.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,79 @@ export function formatToolDetail(tool: Tool): string {
568568
return lines.join('\n');
569569
}
570570

571+
/**
572+
* Generate an example placeholder value for a JSON Schema property.
573+
* Uses the default value if available, otherwise a reasonable placeholder.
574+
*/
575+
function exampleValue(propSchema: Record<string, unknown>): string {
576+
// Use default value if available
577+
if (propSchema.default !== undefined) {
578+
return JSON.stringify(propSchema.default);
579+
}
580+
581+
// Use first enum value if available
582+
if (propSchema.enum && Array.isArray(propSchema.enum) && propSchema.enum.length > 0) {
583+
return JSON.stringify(propSchema.enum[0]);
584+
}
585+
586+
const schemaType = propSchema.type;
587+
588+
if (schemaType === 'string') return '"something"';
589+
if (schemaType === 'number') return '1';
590+
if (schemaType === 'integer') {
591+
// Respect minimum if set
592+
const min = propSchema.minimum as number | undefined;
593+
return String(min ?? 1);
594+
}
595+
if (schemaType === 'boolean') return 'true';
596+
597+
// Union types like ['string', 'null']
598+
if (Array.isArray(schemaType)) {
599+
const nonNull = schemaType.filter((t) => t !== 'null');
600+
if (nonNull.includes('string')) return '"something"';
601+
if (nonNull.includes('number') || nonNull.includes('integer')) return '1';
602+
if (nonNull.includes('boolean')) return 'true';
603+
}
604+
605+
return '"something"';
606+
}
607+
608+
/**
609+
* Format a tools-call usage example for a tool, showing how to invoke it.
610+
* Shows required params first, then fills with optional params up to 3 total.
611+
*/
612+
export function formatToolCallExample(tool: Tool, sessionName?: string): string | null {
613+
const schema = tool.inputSchema as Record<string, unknown> | undefined;
614+
const properties = schema?.properties as Record<string, Record<string, unknown>> | undefined;
615+
616+
if (!properties || Object.keys(properties).length === 0) {
617+
// Tool takes no arguments — still show the simple call
618+
const session = sessionName || '<@session>';
619+
return `${chalk.bold('Example:')}\n mcpc ${session} tools-call ${tool.name}`;
620+
}
621+
622+
const requiredNames = (schema?.required as string[]) || [];
623+
const allNames = Object.keys(properties);
624+
const requiredInOrder = allNames.filter((n) => requiredNames.includes(n));
625+
const optionalInOrder = allNames.filter((n) => !requiredNames.includes(n));
626+
627+
// Pick params: all required, then fill optional up to 3 total
628+
const MAX_EXAMPLE_PARAMS = 3;
629+
const params: string[] = [...requiredInOrder];
630+
if (params.length < MAX_EXAMPLE_PARAMS) {
631+
const remaining = MAX_EXAMPLE_PARAMS - params.length;
632+
params.push(...optionalInOrder.slice(0, remaining));
633+
}
634+
635+
const session = sessionName || '<@session>';
636+
const argParts = params.map((name) => {
637+
const val = exampleValue(properties[name] ?? {});
638+
return `${name}:=${val}`;
639+
});
640+
641+
return `${chalk.bold('Example:')}\n mcpc ${session} tools-call ${tool.name} ${argParts.join(' ')}`;
642+
}
643+
571644
/**
572645
* Format a list of resources with Markdown-like display
573646
*/

0 commit comments

Comments
 (0)