@apify/mcpc 0.2.3 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -2
- package/README.md +87 -35
- package/dist/bridge/index.js +63 -5
- package/dist/bridge/index.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -0
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +7 -0
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/clean.d.ts.map +1 -1
- package/dist/cli/commands/clean.js +13 -2
- package/dist/cli/commands/clean.js.map +1 -1
- package/dist/cli/commands/grep.d.ts +4 -0
- package/dist/cli/commands/grep.d.ts.map +1 -1
- package/dist/cli/commands/grep.js +121 -11
- package/dist/cli/commands/grep.js.map +1 -1
- package/dist/cli/commands/prompts.d.ts.map +1 -1
- package/dist/cli/commands/prompts.js +7 -26
- package/dist/cli/commands/prompts.js.map +1 -1
- package/dist/cli/commands/resources.d.ts.map +1 -1
- package/dist/cli/commands/resources.js +9 -3
- package/dist/cli/commands/resources.js.map +1 -1
- package/dist/cli/commands/sessions.d.ts +26 -2
- package/dist/cli/commands/sessions.d.ts.map +1 -1
- package/dist/cli/commands/sessions.js +191 -16
- package/dist/cli/commands/sessions.js.map +1 -1
- package/dist/cli/commands/tasks.d.ts +1 -0
- package/dist/cli/commands/tasks.d.ts.map +1 -1
- package/dist/cli/commands/tasks.js +11 -0
- package/dist/cli/commands/tasks.js.map +1 -1
- package/dist/cli/commands/tools.d.ts +6 -1
- package/dist/cli/commands/tools.d.ts.map +1 -1
- package/dist/cli/commands/tools.js +43 -15
- package/dist/cli/commands/tools.js.map +1 -1
- package/dist/cli/commands/x402.d.ts.map +1 -1
- package/dist/cli/commands/x402.js +6 -2
- package/dist/cli/commands/x402.js.map +1 -1
- package/dist/cli/index.js +308 -91
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +5 -0
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +103 -16
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/parser.d.ts +4 -0
- package/dist/cli/parser.d.ts.map +1 -1
- package/dist/cli/parser.js +50 -16
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/shell.d.ts.map +1 -1
- package/dist/cli/shell.js +27 -4
- package/dist/cli/shell.js.map +1 -1
- package/dist/core/mcp-client.d.ts +1 -0
- package/dist/core/mcp-client.d.ts.map +1 -1
- package/dist/core/mcp-client.js +14 -0
- package/dist/core/mcp-client.js.map +1 -1
- package/dist/lib/auth/oauth-flow.d.ts +1 -0
- package/dist/lib/auth/oauth-flow.d.ts.map +1 -1
- package/dist/lib/auth/oauth-flow.js +60 -16
- package/dist/lib/auth/oauth-flow.js.map +1 -1
- package/dist/lib/auth/oauth-provider.d.ts +2 -0
- package/dist/lib/auth/oauth-provider.d.ts.map +1 -1
- package/dist/lib/auth/oauth-provider.js +4 -0
- package/dist/lib/auth/oauth-provider.js.map +1 -1
- package/dist/lib/bridge-client.d.ts +1 -0
- package/dist/lib/bridge-client.d.ts.map +1 -1
- package/dist/lib/bridge-client.js.map +1 -1
- package/dist/lib/bridge-manager.d.ts +4 -1
- package/dist/lib/bridge-manager.d.ts.map +1 -1
- package/dist/lib/bridge-manager.js +97 -27
- package/dist/lib/bridge-manager.js.map +1 -1
- package/dist/lib/cleanup.d.ts +5 -0
- package/dist/lib/cleanup.d.ts.map +1 -1
- package/dist/lib/cleanup.js +38 -1
- package/dist/lib/cleanup.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +5 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +15 -8
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/session-client.d.ts +1 -0
- package/dist/lib/session-client.d.ts.map +1 -1
- package/dist/lib/session-client.js +10 -4
- package/dist/lib/session-client.js.map +1 -1
- package/dist/lib/sessions.d.ts +1 -0
- package/dist/lib/sessions.d.ts.map +1 -1
- package/dist/lib/sessions.js +52 -4
- package/dist/lib/sessions.js.map +1 -1
- package/dist/lib/types.d.ts +5 -1
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/utils.d.ts +16 -3
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +125 -9
- package/dist/lib/utils.js.map +1 -1
- package/docs/TODOs.md +11 -0
- package/package.json +6 -6
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { initProxy } from '../lib/proxy.js';
|
|
3
|
-
import { Command } from 'commander';
|
|
3
|
+
import { Command, CommanderError, Help } from 'commander';
|
|
4
4
|
import { setVerbose, setJsonMode, closeFileLogger } from '../lib/index.js';
|
|
5
5
|
import { isMcpError, formatHumanError, ClientError } from '../lib/index.js';
|
|
6
6
|
import chalk from 'chalk';
|
|
@@ -16,7 +16,7 @@ import * as tasks from './commands/tasks.js';
|
|
|
16
16
|
import * as grepCmd from './commands/grep.js';
|
|
17
17
|
import { handleX402Command } from './commands/x402.js';
|
|
18
18
|
import { clean } from './commands/clean.js';
|
|
19
|
-
import { extractOptions, getVerboseFromEnv, getJsonFromEnv, validateOptions, validateArgValues, parseServerArg, hasSubcommand, optionTakesValue, KNOWN_COMMANDS, KNOWN_SESSION_COMMANDS, } from './parser.js';
|
|
19
|
+
import { extractOptions, getVerboseFromEnv, getJsonFromEnv, validateOptions, validateArgValues, parseServerArg, hasSubcommand, optionTakesValue, suggestCommand, KNOWN_COMMANDS, KNOWN_SESSION_COMMANDS, } from './parser.js';
|
|
20
20
|
import { createRequire } from 'module';
|
|
21
21
|
const { version: mcpcVersion } = createRequire(import.meta.url)('../../package.json');
|
|
22
22
|
{
|
|
@@ -64,8 +64,21 @@ function getOptionsFromCommand(command) {
|
|
|
64
64
|
}
|
|
65
65
|
if (opts.full)
|
|
66
66
|
options.full = opts.full;
|
|
67
|
+
if (opts.maxChars) {
|
|
68
|
+
const maxChars = parseInt(opts.maxChars, 10);
|
|
69
|
+
if (isNaN(maxChars) || maxChars <= 0) {
|
|
70
|
+
throw new Error(`Invalid --max-chars value: "${opts.maxChars}". Must be a positive number (characters).`);
|
|
71
|
+
}
|
|
72
|
+
options.maxChars = maxChars;
|
|
73
|
+
}
|
|
67
74
|
return options;
|
|
68
75
|
}
|
|
76
|
+
function jsonHelp(description, shape, schemaUrl) {
|
|
77
|
+
const line = shape ? ` ${description}:\n ${shape}` : ` ${description}`;
|
|
78
|
+
const link = schemaUrl ? `\n Schema: ${schemaUrl}` : '';
|
|
79
|
+
return `\n${chalk.bold('JSON output (--json):')}\n${line}${link}\n`;
|
|
80
|
+
}
|
|
81
|
+
const SCHEMA_BASE = 'https://modelcontextprotocol.io/specification/2025-11-25/schema';
|
|
69
82
|
async function main() {
|
|
70
83
|
const args = process.argv.slice(2);
|
|
71
84
|
const handleExit = () => {
|
|
@@ -90,16 +103,26 @@ async function main() {
|
|
|
90
103
|
return;
|
|
91
104
|
}
|
|
92
105
|
if (args.includes('--help') || args.includes('-h')) {
|
|
93
|
-
|
|
106
|
+
const hasSessionArg = args.some((a) => a.startsWith('@') && !a.startsWith('--'));
|
|
107
|
+
if (hasSessionArg) {
|
|
108
|
+
}
|
|
109
|
+
else if (args.includes('x402')) {
|
|
94
110
|
const x402Index = args.indexOf('x402');
|
|
95
111
|
const x402Args = args.slice(x402Index + 1);
|
|
96
112
|
await handleX402Command(x402Args);
|
|
97
113
|
await closeFileLogger();
|
|
98
114
|
return;
|
|
99
115
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
else {
|
|
117
|
+
const helpTarget = args.find((a) => a !== '--help' && a !== '-h' && !a.startsWith('-') && !a.startsWith('@'));
|
|
118
|
+
if (helpTarget && KNOWN_SESSION_COMMANDS.includes(helpTarget)) {
|
|
119
|
+
showSessionCommandHelp(helpTarget);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const program = createTopLevelProgram();
|
|
123
|
+
await program.parseAsync(process.argv);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
103
126
|
}
|
|
104
127
|
try {
|
|
105
128
|
validateOptions(args);
|
|
@@ -210,11 +233,20 @@ async function main() {
|
|
|
210
233
|
}
|
|
211
234
|
}
|
|
212
235
|
else {
|
|
236
|
+
const suggestion = suggestCommand(firstNonOption, allCommands);
|
|
213
237
|
if (outputMode === 'json') {
|
|
214
238
|
console.error(formatJsonError(new Error(`Unknown command: ${firstNonOption}`), 1));
|
|
215
239
|
}
|
|
216
240
|
else {
|
|
217
241
|
console.error(`Error: Unknown command: ${firstNonOption}`);
|
|
242
|
+
if (suggestion) {
|
|
243
|
+
if (KNOWN_SESSION_COMMANDS.includes(suggestion)) {
|
|
244
|
+
console.error(`\nDid you mean: mcpc <@session> ${suggestion}`);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
console.error(`\nDid you mean: mcpc ${suggestion}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
218
250
|
console.error(`Run "mcpc --help" for usage information.\n`);
|
|
219
251
|
}
|
|
220
252
|
}
|
|
@@ -232,6 +264,21 @@ function createTopLevelProgram() {
|
|
|
232
264
|
subcommandTerm: (cmd) => `${cmd.name()} ${cmd.usage()}`.replace(/^\[options\]\s*|\s*\[options\]/g, '').trim(),
|
|
233
265
|
styleTitle: (str) => chalk.bold(str),
|
|
234
266
|
styleSubcommandText: (str) => chalk.cyan(str),
|
|
267
|
+
formatHelp: (cmd, helper) => {
|
|
268
|
+
const output = Help.prototype.formatHelp.call(helper, cmd, helper);
|
|
269
|
+
const sections = output.split('\n\n');
|
|
270
|
+
const optIdx = sections.findIndex((s) => s.includes('Options:'));
|
|
271
|
+
const cmdIdx = sections.findIndex((s) => s.includes('Commands:'));
|
|
272
|
+
if (optIdx >= 0 && cmdIdx >= 0 && optIdx < cmdIdx) {
|
|
273
|
+
const tmp = sections[optIdx];
|
|
274
|
+
sections[optIdx] = sections[cmdIdx];
|
|
275
|
+
sections[cmdIdx] = tmp;
|
|
276
|
+
}
|
|
277
|
+
return (sections
|
|
278
|
+
.map((s) => s.trimEnd())
|
|
279
|
+
.filter((s) => s !== '')
|
|
280
|
+
.join('\n\n') + '\n');
|
|
281
|
+
},
|
|
235
282
|
});
|
|
236
283
|
const docsUrl = process.stdout.isTTY
|
|
237
284
|
? `https://github.com/apify/mcpc/tree/v${mcpcVersion}`
|
|
@@ -239,20 +286,19 @@ function createTopLevelProgram() {
|
|
|
239
286
|
program
|
|
240
287
|
.name('mcpc')
|
|
241
288
|
.description(`${rainbow('Universal')} command-line client for the Model Context Protocol (MCP).`)
|
|
242
|
-
.usage('[
|
|
243
|
-
.option('
|
|
289
|
+
.usage('[<@session>] [<command>] [options]')
|
|
290
|
+
.option('--json', 'Output in JSON format for scripting')
|
|
244
291
|
.option('--verbose', 'Enable debug logging')
|
|
245
292
|
.option('--profile <name>', 'OAuth profile for the server ("default" if not provided)')
|
|
246
|
-
.option('--schema <file>', 'Validate tool/prompt schema against expected schema')
|
|
247
|
-
.option('--schema-mode <mode>', 'Schema validation mode: strict, compatible (default), ignore')
|
|
248
293
|
.option('--timeout <seconds>', 'Request timeout in seconds (default: 300)')
|
|
294
|
+
.option('--max-chars <n>', 'Truncate output to n characters (ignored in --json mode)')
|
|
249
295
|
.option('--insecure', 'Skip TLS certificate verification (for self-signed certs)')
|
|
250
296
|
.version(mcpcVersion, '-v, --version', 'Output the version number')
|
|
251
297
|
.helpOption('-h, --help', 'Display help');
|
|
252
298
|
program.addHelpText('after', `
|
|
253
299
|
${chalk.bold('MCP session commands (after connecting):')}
|
|
254
|
-
<@session> Show MCP server info, capabilities, and tools
|
|
255
|
-
<@session> ${chalk.cyan('grep')} <pattern> Search tools
|
|
300
|
+
<@session> Show MCP server info, capabilities, and tools overview
|
|
301
|
+
<@session> ${chalk.cyan('grep')} <pattern> Search tools and instructions
|
|
256
302
|
<@session> ${chalk.cyan('tools-list')} List all server tools
|
|
257
303
|
<@session> ${chalk.cyan('tools-get')} <name> Get tool details and schema
|
|
258
304
|
<@session> ${chalk.cyan('tools-call')} <name> [arg:=val ... | <json> | <stdin]
|
|
@@ -265,6 +311,7 @@ ${chalk.bold('MCP session commands (after connecting):')}
|
|
|
265
311
|
<@session> ${chalk.cyan('resources-templates-list')}
|
|
266
312
|
<@session> ${chalk.cyan('tasks-list')}
|
|
267
313
|
<@session> ${chalk.cyan('tasks-get')} <taskId>
|
|
314
|
+
<@session> ${chalk.cyan('tasks-result')} <taskId>
|
|
268
315
|
<@session> ${chalk.cyan('tasks-cancel')} <taskId>
|
|
269
316
|
<@session> ${chalk.cyan('logging-set-level')} <level>
|
|
270
317
|
<@session> ${chalk.cyan('ping')}
|
|
@@ -274,8 +321,8 @@ Run "mcpc" without arguments to show active sessions and OAuth profiles.
|
|
|
274
321
|
Full docs: ${docsUrl}`);
|
|
275
322
|
program
|
|
276
323
|
.command('connect [server] [@session]')
|
|
277
|
-
.usage('<server>
|
|
278
|
-
.description('Connect to an MCP server and start a
|
|
324
|
+
.usage('<server> [@session]')
|
|
325
|
+
.description('Connect to an MCP server and start a named @session')
|
|
279
326
|
.option('-H, --header <header>', 'HTTP header (can be repeated)')
|
|
280
327
|
.option('--profile <name>', 'OAuth profile to use ("default" if skipped)')
|
|
281
328
|
.option('--no-profile', 'Skip OAuth profile (connect anonymously)')
|
|
@@ -286,14 +333,20 @@ Full docs: ${docsUrl}`);
|
|
|
286
333
|
${chalk.bold('Server formats:')}
|
|
287
334
|
mcp.apify.com Remote HTTP server (https:// added automatically)
|
|
288
335
|
~/.vscode/mcp.json:puppeteer Config file entry (file:entry)
|
|
289
|
-
|
|
336
|
+
~/.vscode/mcp.json Config file — connect all servers in the file
|
|
337
|
+
|
|
338
|
+
${chalk.bold('Session name:')}
|
|
339
|
+
If @session is omitted, a name is auto-generated from the server hostname
|
|
340
|
+
(e.g. mcp.apify.com → @apify) or config entry name. If a matching session
|
|
341
|
+
already exists (same server URL, OAuth profile, and HTTP header names), it
|
|
342
|
+
is reused (restarted if not live). Header values are not compared — they
|
|
343
|
+
are stored securely in OS keychain.
|
|
344
|
+
When connecting all servers from a config file, @session cannot be specified.
|
|
345
|
+
${jsonHelp('`InitializeResult` object extended with `toolNames` and `_mcpc` metadata', '`{ protocolVersion, capabilities, serverInfo, instructions?, toolNames?, _mcpc }`', `${SCHEMA_BASE}#initializeresult`)}`)
|
|
290
346
|
.action(async (server, sessionName, opts, command) => {
|
|
291
347
|
if (!server) {
|
|
292
348
|
throw new ClientError('Missing required argument: server\n\nExample: mcpc connect mcp.apify.com @myapp');
|
|
293
349
|
}
|
|
294
|
-
if (!sessionName) {
|
|
295
|
-
throw new ClientError('Missing required argument: @session\n\nExample: mcpc connect mcp.apify.com @myapp');
|
|
296
|
-
}
|
|
297
350
|
const globalOpts = getOptionsFromCommand(command);
|
|
298
351
|
const parsed = parseServerArg(server);
|
|
299
352
|
const headers = opts.header
|
|
@@ -305,6 +358,29 @@ ${chalk.bold('Server formats:')}
|
|
|
305
358
|
throw new ClientError(`Invalid server: "${server}"\n\n` +
|
|
306
359
|
`Expected a URL (e.g. mcp.apify.com) or a config file entry (e.g. ~/.vscode/mcp.json:filesystem)`);
|
|
307
360
|
}
|
|
361
|
+
if (parsed.type === 'config-file') {
|
|
362
|
+
if (sessionName) {
|
|
363
|
+
throw new ClientError(`Cannot specify @session name when connecting all servers from a config file.\n` +
|
|
364
|
+
`To connect a specific entry, use: mcpc connect ${server}:<entry> ${sessionName}`);
|
|
365
|
+
}
|
|
366
|
+
await sessions.connectAllFromConfig(parsed.file, {
|
|
367
|
+
...globalOpts,
|
|
368
|
+
...(headers && { headers }),
|
|
369
|
+
...(opts.proxy && { proxy: opts.proxy }),
|
|
370
|
+
...(opts.proxyBearerToken && { proxyBearerToken: opts.proxyBearerToken }),
|
|
371
|
+
...(opts.x402 && { x402: opts.x402 }),
|
|
372
|
+
...(globalOpts.insecure && { insecure: true }),
|
|
373
|
+
});
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (!sessionName) {
|
|
377
|
+
sessionName = await sessions.resolveSessionName(parsed, {
|
|
378
|
+
outputMode: globalOpts.outputMode,
|
|
379
|
+
...(globalOpts.profile && { profile: globalOpts.profile }),
|
|
380
|
+
...(headers && { headers }),
|
|
381
|
+
...(globalOpts.noProfile && { noProfile: globalOpts.noProfile }),
|
|
382
|
+
});
|
|
383
|
+
}
|
|
308
384
|
if (parsed.type === 'config') {
|
|
309
385
|
await sessions.connectSession(parsed.entry, sessionName, {
|
|
310
386
|
...globalOpts,
|
|
@@ -331,6 +407,7 @@ ${chalk.bold('Server formats:')}
|
|
|
331
407
|
.command('close [@session]')
|
|
332
408
|
.usage('<@session>')
|
|
333
409
|
.description('Close a session')
|
|
410
|
+
.addHelpText('after', jsonHelp('`{ sessionName, closed: true }`'))
|
|
334
411
|
.action(async (sessionName, _opts, command) => {
|
|
335
412
|
if (!sessionName) {
|
|
336
413
|
throw new ClientError('Missing required argument: @session\n\nExample: mcpc close @myapp');
|
|
@@ -362,9 +439,24 @@ ${chalk.bold('Server formats:')}
|
|
|
362
439
|
.usage('<server>')
|
|
363
440
|
.description('Interactively login to a server using OAuth and save profile')
|
|
364
441
|
.option('--profile <name>', 'Profile name (default: "default")')
|
|
365
|
-
.option('--scope <scopes>', 'OAuth scopes to request
|
|
366
|
-
.option('--client-id <id>', 'OAuth client ID (
|
|
367
|
-
.option('--client-secret <secret>', 'OAuth client secret (
|
|
442
|
+
.option('--scope <scopes>', 'OAuth scopes to request (e.g. --scope "read write")')
|
|
443
|
+
.option('--client-id <id>', 'Pre-registered OAuth client ID (skips CIMD and DCR)')
|
|
444
|
+
.option('--client-secret <secret>', 'Pre-registered OAuth client secret (requires --client-id)')
|
|
445
|
+
.option('--client-metadata-url <url>', 'HTTPS URL of an OAuth CIMD to use as the Client ID')
|
|
446
|
+
.addHelpText('after', `
|
|
447
|
+
${chalk.bold('OAuth client registration approaches:')}
|
|
448
|
+
|
|
449
|
+
1. Pre-registration: --client-id (and optionally --client-secret).
|
|
450
|
+
2. Client ID Metadata Documents (CIMD): --client-metadata-url <https-url>.
|
|
451
|
+
Used when the authorization server advertises
|
|
452
|
+
"client_id_metadata_document_supported: true".
|
|
453
|
+
3. Dynamic Client Registration (DCR): default fallback when the server
|
|
454
|
+
exposes a "registration_endpoint". No flags required.
|
|
455
|
+
|
|
456
|
+
See https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization
|
|
457
|
+
|
|
458
|
+
${jsonHelp('Interactive prompts are written to stderr, stdout contains a clean JSON object', '`{ profile, serverUrl, scopes }`')}
|
|
459
|
+
`)
|
|
368
460
|
.action(async (server, opts, command) => {
|
|
369
461
|
if (!server) {
|
|
370
462
|
throw new ClientError('Missing required argument: server\n\nExample: mcpc login mcp.apify.com');
|
|
@@ -374,14 +466,16 @@ ${chalk.bold('Server formats:')}
|
|
|
374
466
|
scope: opts.scope,
|
|
375
467
|
clientId: opts.clientId,
|
|
376
468
|
clientSecret: opts.clientSecret,
|
|
469
|
+
clientMetadataUrl: opts.clientMetadataUrl,
|
|
377
470
|
...getOptionsFromCommand(command),
|
|
378
471
|
});
|
|
379
472
|
});
|
|
380
473
|
program
|
|
381
474
|
.command('logout [server]')
|
|
382
475
|
.usage('<server>')
|
|
383
|
-
.description('Delete an
|
|
476
|
+
.description('Delete an OAuth profile for a server')
|
|
384
477
|
.option('--profile <name>', 'Profile name (default: "default")')
|
|
478
|
+
.addHelpText('after', jsonHelp('`{ profile, serverUrl, deleted: true, affectedSessions }`'))
|
|
385
479
|
.action(async (server, opts, command) => {
|
|
386
480
|
if (!server) {
|
|
387
481
|
throw new ClientError('Missing required argument: server\n\nExample: mcpc logout mcp.apify.com');
|
|
@@ -402,7 +496,7 @@ ${chalk.bold('Resources:')}
|
|
|
402
496
|
all Remove all of the above
|
|
403
497
|
|
|
404
498
|
Without arguments, performs safe cleanup of stale data only.
|
|
405
|
-
`)
|
|
499
|
+
${jsonHelp('`{ crashedBridges, expiredSessions, orphanedBridgeLogs, sessions, profiles, logs }`')}`)
|
|
406
500
|
.action(async (resources, _opts, command) => {
|
|
407
501
|
const globalOpts = getOptionsFromCommand(command);
|
|
408
502
|
const VALID_CLEAN_TYPES = ['sessions', 'profiles', 'logs', 'all'];
|
|
@@ -443,7 +537,7 @@ ${chalk.bold('Examples:')}
|
|
|
443
537
|
mcpc @apify grep "actor" Search within a single session
|
|
444
538
|
mcpc grep "file" --json JSON output for scripting
|
|
445
539
|
mcpc grep "actor" -m 5 Show at most 5 results
|
|
446
|
-
`)
|
|
540
|
+
${jsonHelp('`[{ sessionName, tools?: Tool[], resources?: Resource[], prompts?: Prompt[], instructions?: string[] }]`')}`)
|
|
447
541
|
.action(async (pattern, opts, command) => {
|
|
448
542
|
if (!pattern) {
|
|
449
543
|
throw new ClientError('Missing required argument: pattern\n\nUsage: mcpc grep <pattern>\n\nExample: mcpc grep "search"');
|
|
@@ -481,17 +575,12 @@ ${chalk.bold('Examples:')}
|
|
|
481
575
|
}
|
|
482
576
|
const topLevelCmd = program.commands.find((c) => c.name() === cmdName || c.aliases().includes(cmdName));
|
|
483
577
|
if (topLevelCmd) {
|
|
578
|
+
tuneCommandHelp(topLevelCmd);
|
|
484
579
|
topLevelCmd.outputHelp();
|
|
485
580
|
return;
|
|
486
581
|
}
|
|
487
|
-
|
|
488
|
-
dummyProgram.name('mcpc <@session>');
|
|
489
|
-
registerSessionCommands(dummyProgram, '@dummy');
|
|
490
|
-
const sessionCmd = dummyProgram.commands.find((c) => c.name() === cmdName || c.aliases().includes(cmdName));
|
|
491
|
-
if (sessionCmd) {
|
|
492
|
-
sessionCmd.outputHelp();
|
|
582
|
+
if (showSessionCommandHelp(cmdName))
|
|
493
583
|
return;
|
|
494
|
-
}
|
|
495
584
|
console.error(`Unknown command: ${cmdName}`);
|
|
496
585
|
console.error(`Run "mcpc --help" for usage information.`);
|
|
497
586
|
process.exit(1);
|
|
@@ -508,57 +597,150 @@ ${chalk.bold('Examples:')}
|
|
|
508
597
|
});
|
|
509
598
|
return program;
|
|
510
599
|
}
|
|
600
|
+
const NO_JSON_COMMANDS = new Set(['shell']);
|
|
601
|
+
function tuneCommandHelp(cmd) {
|
|
602
|
+
if (!NO_JSON_COMMANDS.has(cmd.name()) && !cmd.options.some((o) => o.long === '--json')) {
|
|
603
|
+
cmd.option('--json', 'Output in JSON format');
|
|
604
|
+
}
|
|
605
|
+
cmd.helpOption('-h, --help', 'Display help');
|
|
606
|
+
const helpOpt = cmd._getHelpOption?.();
|
|
607
|
+
if (helpOpt)
|
|
608
|
+
helpOpt.hidden = true;
|
|
609
|
+
}
|
|
610
|
+
function showSessionCommandHelp(cmdName) {
|
|
611
|
+
const dummyProgram = createSessionProgram();
|
|
612
|
+
registerSessionCommands(dummyProgram, '<@session>');
|
|
613
|
+
for (const cmd of dummyProgram.commands) {
|
|
614
|
+
tuneCommandHelp(cmd);
|
|
615
|
+
}
|
|
616
|
+
const sessionCmd = dummyProgram.commands.find((c) => c.name() === cmdName || c.aliases().includes(cmdName));
|
|
617
|
+
if (sessionCmd) {
|
|
618
|
+
sessionCmd.outputHelp();
|
|
619
|
+
return true;
|
|
620
|
+
}
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
511
623
|
function registerSessionCommands(program, session) {
|
|
512
624
|
program
|
|
513
|
-
.command('help')
|
|
514
|
-
.description('Show
|
|
515
|
-
.action(
|
|
516
|
-
|
|
625
|
+
.command('help', { hidden: true })
|
|
626
|
+
.description('Show available commands and options.')
|
|
627
|
+
.action((_options, command) => {
|
|
628
|
+
command.parent.outputHelp();
|
|
517
629
|
});
|
|
518
630
|
program
|
|
519
631
|
.command('shell')
|
|
520
|
-
.description('
|
|
632
|
+
.description('Launch interactive MCP shell.')
|
|
521
633
|
.action(async () => {
|
|
522
634
|
await sessions.openShell(session);
|
|
523
635
|
});
|
|
524
636
|
program
|
|
525
|
-
.command('close'
|
|
526
|
-
.description('Close
|
|
637
|
+
.command('close')
|
|
638
|
+
.description('Close MCP session.')
|
|
527
639
|
.action(async (_options, command) => {
|
|
528
640
|
await sessions.closeSession(session, getOptionsFromCommand(command));
|
|
529
641
|
});
|
|
530
642
|
program
|
|
531
643
|
.command('restart')
|
|
532
|
-
.description('Restart
|
|
644
|
+
.description('Restart MCP session (losing all state).')
|
|
533
645
|
.action(async (_options, command) => {
|
|
534
646
|
await sessions.restartSession(session, getOptionsFromCommand(command));
|
|
535
647
|
});
|
|
648
|
+
program
|
|
649
|
+
.command('grep <pattern>')
|
|
650
|
+
.usage('<pattern> [options]')
|
|
651
|
+
.description('Search MCP session objects.')
|
|
652
|
+
.option('--tools', 'Search tools')
|
|
653
|
+
.option('--resources', 'Search resources')
|
|
654
|
+
.option('--prompts', 'Search prompts')
|
|
655
|
+
.option('--instructions', 'Search server instructions')
|
|
656
|
+
.option('-E, --regex', 'Treat pattern as a regular expression')
|
|
657
|
+
.option('-s, --case-sensitive', 'Case-sensitive matching')
|
|
658
|
+
.option('-m, --max-results <n>', 'Limit the number of results')
|
|
659
|
+
.addHelpText('after', `
|
|
660
|
+
${chalk.bold('Type filters:')}
|
|
661
|
+
By default, tools and instructions are searched. Use --resources or --prompts
|
|
662
|
+
to search those instead. Combine flags to search multiple types.
|
|
663
|
+
|
|
664
|
+
${chalk.bold('Examples:')}
|
|
665
|
+
mcpc ${session} grep "search" Search tools and instructions
|
|
666
|
+
mcpc ${session} grep "search" --resources Search resources only
|
|
667
|
+
mcpc ${session} grep "search|find" -E Regex search
|
|
668
|
+
${jsonHelp('`{ tools?: Tool[], resources?: Resource[], prompts?: Prompt[], instructions?: string[] }`')}`)
|
|
669
|
+
.action(async (pattern, opts, command) => {
|
|
670
|
+
const globalOpts = getOptionsFromCommand(command);
|
|
671
|
+
const maxResults = opts.maxResults ? parseInt(opts.maxResults, 10) : undefined;
|
|
672
|
+
const exitCode = await grepCmd.grepSession(session, pattern, {
|
|
673
|
+
tools: opts.tools,
|
|
674
|
+
resources: opts.resources,
|
|
675
|
+
prompts: opts.prompts,
|
|
676
|
+
instructions: opts.instructions,
|
|
677
|
+
regex: opts.regex,
|
|
678
|
+
caseSensitive: opts.caseSensitive,
|
|
679
|
+
maxResults,
|
|
680
|
+
...globalOpts,
|
|
681
|
+
});
|
|
682
|
+
process.exit(exitCode);
|
|
683
|
+
});
|
|
536
684
|
program
|
|
537
685
|
.command('tools')
|
|
538
|
-
.description('List
|
|
539
|
-
.option('--full', 'Show full tool details including
|
|
686
|
+
.description('List MCP tools (shorthand for tools-list).')
|
|
687
|
+
.option('--full', 'Show full tool details including schema')
|
|
688
|
+
.addHelpText('after', jsonHelp('Array of `Tool` objects', '`[{ name, description?, inputSchema, annotations? }, ...]`', `${SCHEMA_BASE}#tool`))
|
|
540
689
|
.action(async (_options, command) => {
|
|
541
690
|
await tools.listTools(session, getOptionsFromCommand(command));
|
|
542
691
|
});
|
|
543
692
|
program
|
|
544
693
|
.command('tools-list')
|
|
545
|
-
.description('List
|
|
546
|
-
.option('--full', 'Show full tool details including
|
|
694
|
+
.description('List all MCP tools.')
|
|
695
|
+
.option('--full', 'Show full tool details including schema')
|
|
696
|
+
.addHelpText('after', jsonHelp('Array of `Tool` objects', '`[{ name, description?, inputSchema, annotations? }, ...]`', `${SCHEMA_BASE}#tool`))
|
|
547
697
|
.action(async (_options, command) => {
|
|
548
698
|
await tools.listTools(session, getOptionsFromCommand(command));
|
|
549
699
|
});
|
|
550
700
|
program
|
|
551
701
|
.command('tools-get <name>')
|
|
552
|
-
.description('Get
|
|
702
|
+
.description('Get details and schema for an MCP tool.')
|
|
703
|
+
.option('--schema <file>', 'Validate tool schema against expected schema')
|
|
704
|
+
.option('--schema-mode <mode>', 'Schema validation mode: strict, compatible (default), ignore')
|
|
705
|
+
.addHelpText('after', `
|
|
706
|
+
${chalk.bold('Schema validation:')}
|
|
707
|
+
--schema <file> Validate against expected schema (save with tools-get --json)
|
|
708
|
+
--schema-mode <mode> strict | compatible (default) | ignore
|
|
709
|
+
${jsonHelp('`Tool` object', '`{ name, description?, inputSchema, annotations? }`', `${SCHEMA_BASE}#tool`)}`)
|
|
553
710
|
.action(async (name, _options, command) => {
|
|
554
711
|
await tools.getTool(session, name, getOptionsFromCommand(command));
|
|
555
712
|
});
|
|
713
|
+
const toolsCallJsonHelp = jsonHelp('`CallToolResult` object', '`{ content: [{ type, text?, ... }], isError?, structuredContent?: { ... } }`', `${SCHEMA_BASE}#calltoolresult`);
|
|
556
714
|
program
|
|
557
715
|
.command('tools-call <name> [args...]')
|
|
558
|
-
.description('Call
|
|
559
|
-
.
|
|
716
|
+
.description('Call an MCP tool with arguments.')
|
|
717
|
+
.helpOption(false)
|
|
718
|
+
.option('--task', 'Use async task execution (experimental)')
|
|
560
719
|
.option('--detach', 'Start task and return immediately with task ID (implies --task)')
|
|
720
|
+
.option('--schema <file>', 'Validate tool schema against expected schema before calling')
|
|
721
|
+
.option('--schema-mode <mode>', 'Schema validation mode: strict, compatible (default), ignore')
|
|
722
|
+
.addHelpText('after', `
|
|
723
|
+
${chalk.bold('Arguments:')}
|
|
724
|
+
key:=value pairs mcpc ${session} tools-call search query:=hello limit:=10
|
|
725
|
+
Inline JSON mcpc ${session} tools-call search '{"query":"hello"}'
|
|
726
|
+
Stdin pipe echo '{"query":"hello"}' | mcpc ${session} tools-call search
|
|
727
|
+
|
|
728
|
+
Values are auto-parsed: strings, numbers, booleans, JSON objects/arrays.
|
|
729
|
+
To force a string, wrap in quotes: id:='"123"'
|
|
730
|
+
|
|
731
|
+
${chalk.bold('Schema validation:')}
|
|
732
|
+
--schema <file> Validate tool schema before calling (save with tools-get --json)
|
|
733
|
+
--schema-mode <mode> strict | compatible (default) | ignore
|
|
734
|
+
${toolsCallJsonHelp}`)
|
|
561
735
|
.action(async (name, args, options, command) => {
|
|
736
|
+
if (name === '--help' || name === '-h') {
|
|
737
|
+
command.help();
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
741
|
+
await tools.getTool(session, name, getOptionsFromCommand(command));
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
562
744
|
await tools.callTool(session, name, {
|
|
563
745
|
args,
|
|
564
746
|
task: options.task,
|
|
@@ -568,39 +750,52 @@ function registerSessionCommands(program, session) {
|
|
|
568
750
|
});
|
|
569
751
|
program
|
|
570
752
|
.command('tasks-list')
|
|
571
|
-
.description('List
|
|
753
|
+
.description('List all MCP tasks.')
|
|
754
|
+
.addHelpText('after', jsonHelp('`{ tasks: Task[] }`', '`{ tasks: [{ taskId, status, ttl, createdAt, lastUpdatedAt, statusMessage?, pollInterval? }] }`', `${SCHEMA_BASE}#task`))
|
|
572
755
|
.action(async (_options, command) => {
|
|
573
756
|
await tasks.listTasks(session, getOptionsFromCommand(command));
|
|
574
757
|
});
|
|
575
758
|
program
|
|
576
759
|
.command('tasks-get <taskId>')
|
|
577
|
-
.description('Get
|
|
760
|
+
.description('Get MCP task status.')
|
|
761
|
+
.addHelpText('after', jsonHelp('`Task` object', '`{ taskId, status, ttl, createdAt, lastUpdatedAt, statusMessage?, pollInterval? }`', `${SCHEMA_BASE}#task`))
|
|
578
762
|
.action(async (taskId, _options, command) => {
|
|
579
763
|
await tasks.getTask(session, taskId, getOptionsFromCommand(command));
|
|
580
764
|
});
|
|
765
|
+
program
|
|
766
|
+
.command('tasks-result <taskId>')
|
|
767
|
+
.description('Get MCP task final result (blocks until task reaches a terminal state).')
|
|
768
|
+
.addHelpText('after', toolsCallJsonHelp)
|
|
769
|
+
.action(async (taskId, _options, command) => {
|
|
770
|
+
await tasks.getTaskResult(session, taskId, getOptionsFromCommand(command));
|
|
771
|
+
});
|
|
581
772
|
program
|
|
582
773
|
.command('tasks-cancel <taskId>')
|
|
583
|
-
.description('Cancel
|
|
774
|
+
.description('Cancel an MCP task.')
|
|
775
|
+
.addHelpText('after', jsonHelp('`Task` object', '`{ taskId, status, ttl, createdAt, lastUpdatedAt, statusMessage?, pollInterval? }`', `${SCHEMA_BASE}#task`))
|
|
584
776
|
.action(async (taskId, _options, command) => {
|
|
585
777
|
await tasks.cancelTask(session, taskId, getOptionsFromCommand(command));
|
|
586
778
|
});
|
|
587
779
|
program
|
|
588
780
|
.command('resources')
|
|
589
|
-
.description('List
|
|
781
|
+
.description('List MCP resources (shorthand for resources-list).')
|
|
782
|
+
.addHelpText('after', jsonHelp('Array of `Resource` objects', '`[{ uri, name?, description?, mimeType? }, ...]`', `${SCHEMA_BASE}#resource`))
|
|
590
783
|
.action(async (_options, command) => {
|
|
591
784
|
await resources.listResources(session, getOptionsFromCommand(command));
|
|
592
785
|
});
|
|
593
786
|
program
|
|
594
787
|
.command('resources-list')
|
|
595
|
-
.description('List
|
|
788
|
+
.description('List all MCP resources.')
|
|
789
|
+
.addHelpText('after', jsonHelp('Array of `Resource` objects', '`[{ uri, name?, description?, mimeType? }, ...]`', `${SCHEMA_BASE}#resource`))
|
|
596
790
|
.action(async (_options, command) => {
|
|
597
791
|
await resources.listResources(session, getOptionsFromCommand(command));
|
|
598
792
|
});
|
|
599
793
|
program
|
|
600
794
|
.command('resources-read <uri>')
|
|
601
|
-
.description('
|
|
795
|
+
.description('Read an MCP resource by URI.')
|
|
602
796
|
.option('-o, --output <file>', 'Write resource to file')
|
|
603
797
|
.option('--max-size <bytes>', 'Maximum resource size in bytes')
|
|
798
|
+
.addHelpText('after', jsonHelp('`ReadResourceResult` object', '`{ contents: [{ uri, mimeType?, text? | blob? }] }`', `${SCHEMA_BASE}#readresourceresult`))
|
|
604
799
|
.action(async (uri, options, command) => {
|
|
605
800
|
await resources.getResource(session, uri, {
|
|
606
801
|
output: options.output,
|
|
@@ -610,37 +805,51 @@ function registerSessionCommands(program, session) {
|
|
|
610
805
|
});
|
|
611
806
|
program
|
|
612
807
|
.command('resources-subscribe <uri>')
|
|
613
|
-
.description('Subscribe to resource updates')
|
|
808
|
+
.description('Subscribe to MCP resource updates.')
|
|
809
|
+
.addHelpText('after', jsonHelp('`{ subscribed: true, uri: string }`'))
|
|
614
810
|
.action(async (uri, _options, command) => {
|
|
615
811
|
await resources.subscribeResource(session, uri, getOptionsFromCommand(command));
|
|
616
812
|
});
|
|
617
813
|
program
|
|
618
814
|
.command('resources-unsubscribe <uri>')
|
|
619
|
-
.description('Unsubscribe from resource updates')
|
|
815
|
+
.description('Unsubscribe from MCP resource updates.')
|
|
816
|
+
.addHelpText('after', jsonHelp('`{ unsubscribed: true, uri: string }`'))
|
|
620
817
|
.action(async (uri, _options, command) => {
|
|
621
818
|
await resources.unsubscribeResource(session, uri, getOptionsFromCommand(command));
|
|
622
819
|
});
|
|
623
820
|
program
|
|
624
821
|
.command('resources-templates-list')
|
|
625
|
-
.description('List
|
|
822
|
+
.description('List MCP resource templates.')
|
|
823
|
+
.addHelpText('after', jsonHelp('Array of `ResourceTemplate` objects', '`[{ uriTemplate, name?, description?, mimeType? }, ...]`', `${SCHEMA_BASE}#resourcetemplate`))
|
|
626
824
|
.action(async (_options, command) => {
|
|
627
825
|
await resources.listResourceTemplates(session, getOptionsFromCommand(command));
|
|
628
826
|
});
|
|
629
827
|
program
|
|
630
828
|
.command('prompts')
|
|
631
|
-
.description('List
|
|
829
|
+
.description('List MCP prompts (shorthand for prompts-list).')
|
|
830
|
+
.addHelpText('after', jsonHelp('Array of `Prompt` objects', '`[{ name, description?, arguments?: [{ name, required? }] }, ...]`', `${SCHEMA_BASE}#prompt`))
|
|
632
831
|
.action(async (_options, command) => {
|
|
633
832
|
await prompts.listPrompts(session, getOptionsFromCommand(command));
|
|
634
833
|
});
|
|
635
834
|
program
|
|
636
835
|
.command('prompts-list')
|
|
637
|
-
.description('List
|
|
836
|
+
.description('List all MCP prompts.')
|
|
837
|
+
.addHelpText('after', jsonHelp('Array of `Prompt` objects', '`[{ name, description?, arguments?: [{ name, required? }] }, ...]`', `${SCHEMA_BASE}#prompt`))
|
|
638
838
|
.action(async (_options, command) => {
|
|
639
839
|
await prompts.listPrompts(session, getOptionsFromCommand(command));
|
|
640
840
|
});
|
|
641
841
|
program
|
|
642
842
|
.command('prompts-get <name> [args...]')
|
|
643
|
-
.description('Get
|
|
843
|
+
.description('Get an MCP prompt with arguments.')
|
|
844
|
+
.addHelpText('after', `
|
|
845
|
+
${chalk.bold('Arguments:')}
|
|
846
|
+
key:=value pairs mcpc ${session} prompts-get summarize style:=brief lang:=en
|
|
847
|
+
Inline JSON mcpc ${session} prompts-get summarize '{"style":"brief"}'
|
|
848
|
+
Stdin pipe echo '{"style":"brief"}' | mcpc ${session} prompts-get summarize
|
|
849
|
+
|
|
850
|
+
Values are auto-parsed: strings, numbers, booleans, JSON objects/arrays.
|
|
851
|
+
To force a string, wrap in quotes: id:='"123"'
|
|
852
|
+
${jsonHelp('`GetPromptResult` object', '`{ description?, messages: [{ role, content: { type, text?, ... } }] }`', `${SCHEMA_BASE}#getpromptresult`)}`)
|
|
644
853
|
.action(async (name, args, _options, command) => {
|
|
645
854
|
await prompts.getPrompt(session, name, {
|
|
646
855
|
args,
|
|
@@ -649,63 +858,47 @@ function registerSessionCommands(program, session) {
|
|
|
649
858
|
});
|
|
650
859
|
program
|
|
651
860
|
.command('logging-set-level <level>')
|
|
652
|
-
.description('Set server logging level
|
|
861
|
+
.description('Set MCP server logging level.')
|
|
862
|
+
.addHelpText('after', jsonHelp('`{ level: string }`'))
|
|
653
863
|
.action(async (level, _options, command) => {
|
|
654
864
|
await logging.setLogLevel(session, level, getOptionsFromCommand(command));
|
|
655
865
|
});
|
|
656
866
|
program
|
|
657
867
|
.command('ping')
|
|
658
|
-
.description('Ping the MCP server
|
|
868
|
+
.description('Ping the MCP server.')
|
|
869
|
+
.addHelpText('after', jsonHelp('`{ success: true, durationMs: number }`'))
|
|
659
870
|
.action(async (_options, command) => {
|
|
660
871
|
await utilities.ping(session, getOptionsFromCommand(command));
|
|
661
872
|
});
|
|
662
|
-
program
|
|
663
|
-
.command('grep <pattern>')
|
|
664
|
-
.description('Search tools and instructions')
|
|
665
|
-
.option('--tools', 'Search tools')
|
|
666
|
-
.option('--resources', 'Search resources')
|
|
667
|
-
.option('--prompts', 'Search prompts')
|
|
668
|
-
.option('--instructions', 'Search server instructions')
|
|
669
|
-
.option('-E, --regex', 'Treat pattern as a regular expression')
|
|
670
|
-
.option('-s, --case-sensitive', 'Case-sensitive matching')
|
|
671
|
-
.option('-m, --max-results <n>', 'Limit the number of results')
|
|
672
|
-
.action(async (pattern, opts, command) => {
|
|
673
|
-
const globalOpts = getOptionsFromCommand(command);
|
|
674
|
-
const maxResults = opts.maxResults ? parseInt(opts.maxResults, 10) : undefined;
|
|
675
|
-
const exitCode = await grepCmd.grepSession(session, pattern, {
|
|
676
|
-
tools: opts.tools,
|
|
677
|
-
resources: opts.resources,
|
|
678
|
-
prompts: opts.prompts,
|
|
679
|
-
instructions: opts.instructions,
|
|
680
|
-
regex: opts.regex,
|
|
681
|
-
caseSensitive: opts.caseSensitive,
|
|
682
|
-
maxResults,
|
|
683
|
-
...globalOpts,
|
|
684
|
-
});
|
|
685
|
-
process.exit(exitCode);
|
|
686
|
-
});
|
|
687
873
|
}
|
|
688
874
|
function createSessionProgram() {
|
|
689
875
|
const program = new Command();
|
|
690
876
|
program.configureOutput({
|
|
691
|
-
outputError: (
|
|
877
|
+
outputError: () => { },
|
|
692
878
|
getOutHelpWidth: () => 100,
|
|
693
879
|
getErrHelpWidth: () => 100,
|
|
694
880
|
});
|
|
881
|
+
program.configureHelp({
|
|
882
|
+
subcommandTerm: (cmd) => `${cmd.name()} ${cmd.usage()}`.replace(/^\[options\]\s*|\s*\[options\]/g, '').trim(),
|
|
883
|
+
styleTitle: (str) => chalk.bold(str),
|
|
884
|
+
styleSubcommandText: (str) => chalk.cyan(str),
|
|
885
|
+
});
|
|
695
886
|
program
|
|
696
887
|
.name('mcpc <@session>')
|
|
888
|
+
.description('Execute MCP commands on a connected session.')
|
|
697
889
|
.helpOption('-h, --help', 'Display help')
|
|
698
|
-
.option('
|
|
890
|
+
.option('--json', 'Output in JSON format for scripting and code mode')
|
|
699
891
|
.option('--verbose', 'Enable debug logging')
|
|
700
892
|
.option('--profile <name>', 'OAuth profile override')
|
|
701
|
-
.option('--schema <file>', 'Validate tool/prompt schema against expected schema')
|
|
702
|
-
.option('--schema-mode <mode>', 'Schema validation mode: strict, compatible (default), ignore')
|
|
703
893
|
.option('--timeout <seconds>', 'Request timeout in seconds (default: 300)')
|
|
704
|
-
.option('--
|
|
894
|
+
.option('--max-chars <n>', 'Truncate output to n characters (ignored in --json mode)')
|
|
895
|
+
.option('--insecure', 'Skip TLS certificate verification (for self-signed certs)')
|
|
896
|
+
.addHelpText('after', `\nWhen no command is given, shows server info, capabilities, and tools.\n`);
|
|
705
897
|
return program;
|
|
706
898
|
}
|
|
707
899
|
async function handleSessionCommands(session, args) {
|
|
708
|
-
|
|
900
|
+
const argsSlice = args.slice(2);
|
|
901
|
+
if (!hasSubcommand(args) && !argsSlice.includes('--help') && !argsSlice.includes('-h')) {
|
|
709
902
|
const options = extractOptions(args);
|
|
710
903
|
if (options.verbose)
|
|
711
904
|
setVerbose(true);
|
|
@@ -719,13 +912,37 @@ async function handleSessionCommands(session, args) {
|
|
|
719
912
|
return;
|
|
720
913
|
}
|
|
721
914
|
const program = createSessionProgram();
|
|
915
|
+
program.exitOverride();
|
|
722
916
|
registerSessionCommands(program, session);
|
|
917
|
+
for (const cmd of program.commands) {
|
|
918
|
+
tuneCommandHelp(cmd);
|
|
919
|
+
}
|
|
723
920
|
try {
|
|
724
921
|
await program.parseAsync(args);
|
|
725
922
|
}
|
|
726
923
|
catch (error) {
|
|
727
924
|
const opts = program.opts();
|
|
728
925
|
const outputMode = opts.json ? 'json' : 'human';
|
|
926
|
+
if (error instanceof CommanderError && error.code === 'commander.unknownCommand') {
|
|
927
|
+
const unknownCmd = args.find((a, i) => i >= 2 && !a.startsWith('-') && !KNOWN_SESSION_COMMANDS.includes(a));
|
|
928
|
+
if (unknownCmd) {
|
|
929
|
+
const suggestion = suggestCommand(unknownCmd, KNOWN_SESSION_COMMANDS);
|
|
930
|
+
if (outputMode === 'json') {
|
|
931
|
+
console.error(formatJsonError(new Error(`Unknown command: ${unknownCmd}`), 1));
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
console.error(`Error: Unknown command: ${unknownCmd}`);
|
|
935
|
+
if (suggestion) {
|
|
936
|
+
console.error(`\nDid you mean: mcpc ${session} ${suggestion}`);
|
|
937
|
+
}
|
|
938
|
+
console.error(`Run "mcpc ${session} --help" for available commands.\n`);
|
|
939
|
+
}
|
|
940
|
+
process.exit(1);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
if (error instanceof CommanderError && error.code === 'commander.helpDisplayed') {
|
|
944
|
+
process.exit(0);
|
|
945
|
+
}
|
|
729
946
|
if (isMcpError(error)) {
|
|
730
947
|
if (outputMode === 'json') {
|
|
731
948
|
console.error(formatJsonError(error, error.code));
|