@apify/mcpc 0.1.11 → 0.2.0-beta.1
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 +76 -2
- package/CONTRIBUTING.md +21 -0
- package/README.md +232 -201
- package/dist/bridge/index.js +240 -43
- package/dist/bridge/index.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +2 -0
- package/dist/cli/commands/auth.d.ts.map +1 -1
- package/dist/cli/commands/auth.js +11 -1
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/logging.d.ts.map +1 -1
- package/dist/cli/commands/logging.js +1 -4
- package/dist/cli/commands/logging.js.map +1 -1
- package/dist/cli/commands/sessions.d.ts +3 -1
- package/dist/cli/commands/sessions.d.ts.map +1 -1
- package/dist/cli/commands/sessions.js +179 -141
- package/dist/cli/commands/sessions.js.map +1 -1
- package/dist/cli/commands/tasks.d.ts +5 -0
- package/dist/cli/commands/tasks.d.ts.map +1 -0
- package/dist/cli/commands/tasks.js +53 -0
- package/dist/cli/commands/tasks.js.map +1 -0
- package/dist/cli/commands/tools.d.ts +2 -0
- package/dist/cli/commands/tools.d.ts.map +1 -1
- package/dist/cli/commands/tools.js +158 -12
- 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 +20 -6
- package/dist/cli/commands/x402.js.map +1 -1
- package/dist/cli/helpers.d.ts +2 -6
- package/dist/cli/helpers.d.ts.map +1 -1
- package/dist/cli/helpers.js +27 -185
- package/dist/cli/helpers.js.map +1 -1
- package/dist/cli/index.js +437 -204
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +7 -3
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +135 -16
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/parser.d.ts +11 -8
- package/dist/cli/parser.d.ts.map +1 -1
- package/dist/cli/parser.js +89 -65
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/shell.d.ts.map +1 -1
- package/dist/cli/shell.js +30 -3
- package/dist/cli/shell.js.map +1 -1
- package/dist/core/mcp-client.d.ts +17 -3
- package/dist/core/mcp-client.d.ts.map +1 -1
- package/dist/core/mcp-client.js +236 -3
- package/dist/core/mcp-client.js.map +1 -1
- package/dist/core/transports.d.ts.map +1 -1
- package/dist/core/transports.js +3 -0
- package/dist/core/transports.js.map +1 -1
- package/dist/lib/auth/keychain.d.ts.map +1 -1
- package/dist/lib/auth/keychain.js +40 -15
- package/dist/lib/auth/keychain.js.map +1 -1
- package/dist/lib/auth/oauth-flow.d.ts +4 -1
- package/dist/lib/auth/oauth-flow.d.ts.map +1 -1
- package/dist/lib/auth/oauth-flow.js +108 -16
- package/dist/lib/auth/oauth-flow.js.map +1 -1
- package/dist/lib/auth/oauth-provider.d.ts +5 -0
- package/dist/lib/auth/oauth-provider.d.ts.map +1 -1
- package/dist/lib/auth/oauth-provider.js +16 -1
- package/dist/lib/auth/oauth-provider.js.map +1 -1
- package/dist/lib/auth/oauth-utils.d.ts.map +1 -1
- package/dist/lib/auth/oauth-utils.js +3 -2
- package/dist/lib/auth/oauth-utils.js.map +1 -1
- package/dist/lib/bridge-client.d.ts +1 -1
- package/dist/lib/bridge-client.d.ts.map +1 -1
- package/dist/lib/bridge-client.js +18 -4
- package/dist/lib/bridge-client.js.map +1 -1
- package/dist/lib/bridge-manager.d.ts +1 -0
- package/dist/lib/bridge-manager.d.ts.map +1 -1
- package/dist/lib/bridge-manager.js +39 -17
- package/dist/lib/bridge-manager.js.map +1 -1
- package/dist/lib/errors.js +2 -2
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/file-lock.d.ts.map +1 -1
- package/dist/lib/file-lock.js +4 -2
- package/dist/lib/file-lock.js.map +1 -1
- package/dist/lib/proxy.d.ts +6 -0
- package/dist/lib/proxy.d.ts.map +1 -0
- package/dist/lib/proxy.js +13 -0
- package/dist/lib/proxy.js.map +1 -0
- package/dist/lib/session-client.d.ts +16 -3
- package/dist/lib/session-client.d.ts.map +1 -1
- package/dist/lib/session-client.js +121 -15
- package/dist/lib/session-client.js.map +1 -1
- package/dist/lib/sessions.d.ts.map +1 -1
- package/dist/lib/sessions.js +9 -4
- package/dist/lib/sessions.js.map +1 -1
- package/dist/lib/types.d.ts +37 -6
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/utils.d.ts +0 -2
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +1 -19
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/x402/fetch-middleware.d.ts.map +1 -1
- package/dist/lib/x402/fetch-middleware.js +41 -8
- package/dist/lib/x402/fetch-middleware.js.map +1 -1
- package/docs/TODOs.md +87 -26
- package/package.json +2 -2
- package/renovate.json +2 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { initProxy } from '../lib/proxy.js';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { setVerbose, setJsonMode, closeFileLogger } from '../lib/index.js';
|
|
5
|
-
import { isMcpError, formatHumanError,
|
|
5
|
+
import { isMcpError, formatHumanError, ClientError } from '../lib/index.js';
|
|
6
|
+
import chalk from 'chalk';
|
|
6
7
|
import { formatJson, formatJsonError, rainbow } from './output.js';
|
|
7
8
|
import * as tools from './commands/tools.js';
|
|
8
9
|
import * as resources from './commands/resources.js';
|
|
@@ -11,12 +12,16 @@ import * as sessions from './commands/sessions.js';
|
|
|
11
12
|
import * as logging from './commands/logging.js';
|
|
12
13
|
import * as utilities from './commands/utilities.js';
|
|
13
14
|
import * as auth from './commands/auth.js';
|
|
15
|
+
import * as tasks from './commands/tasks.js';
|
|
14
16
|
import { handleX402Command } from './commands/x402.js';
|
|
15
17
|
import { clean } from './commands/clean.js';
|
|
16
|
-
import {
|
|
18
|
+
import { extractOptions, getVerboseFromEnv, getJsonFromEnv, validateOptions, validateArgValues, parseServerArg, hasSubcommand, optionTakesValue, KNOWN_COMMANDS, KNOWN_SESSION_COMMANDS, } from './parser.js';
|
|
17
19
|
import { createRequire } from 'module';
|
|
18
20
|
const { version: mcpcVersion } = createRequire(import.meta.url)('../../package.json');
|
|
19
|
-
|
|
21
|
+
{
|
|
22
|
+
const insecure = process.argv.includes('--insecure');
|
|
23
|
+
initProxy({ insecure });
|
|
24
|
+
}
|
|
20
25
|
function getOptionsFromCommand(command) {
|
|
21
26
|
const opts = command.optsWithGlobals ? command.optsWithGlobals() : command.opts();
|
|
22
27
|
const verbose = opts.verbose || getVerboseFromEnv();
|
|
@@ -28,25 +33,31 @@ function getOptionsFromCommand(command) {
|
|
|
28
33
|
const options = {
|
|
29
34
|
outputMode: (json ? 'json' : 'human'),
|
|
30
35
|
};
|
|
31
|
-
if (opts.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
if (opts.timeout) {
|
|
37
|
+
const timeout = parseInt(opts.timeout, 10);
|
|
38
|
+
if (isNaN(timeout) || timeout <= 0) {
|
|
39
|
+
throw new Error(`Invalid --timeout value: "${opts.timeout}". Must be a positive number (seconds).`);
|
|
40
|
+
}
|
|
41
|
+
options.timeout = timeout;
|
|
42
|
+
}
|
|
43
|
+
if (opts.profile === false) {
|
|
44
|
+
options.noProfile = true;
|
|
35
45
|
}
|
|
36
|
-
if (opts.
|
|
37
|
-
options.timeout = parseInt(opts.timeout, 10);
|
|
38
|
-
if (opts.profile)
|
|
46
|
+
else if (opts.profile) {
|
|
39
47
|
options.profile = opts.profile;
|
|
48
|
+
}
|
|
40
49
|
if (verbose)
|
|
41
50
|
options.verbose = verbose;
|
|
42
51
|
if (opts.x402)
|
|
43
52
|
options.x402 = true;
|
|
53
|
+
if (opts.insecure)
|
|
54
|
+
options.insecure = true;
|
|
44
55
|
if (opts.schema)
|
|
45
56
|
options.schema = opts.schema;
|
|
46
57
|
if (opts.schemaMode) {
|
|
47
58
|
const mode = opts.schemaMode;
|
|
48
59
|
if (mode !== 'strict' && mode !== 'compatible' && mode !== 'ignore') {
|
|
49
|
-
throw new Error(`Invalid schema
|
|
60
|
+
throw new Error(`Invalid --schema-mode value: "${mode}". Valid modes are: strict, compatible, ignore`);
|
|
50
61
|
}
|
|
51
62
|
options.schemaMode = mode;
|
|
52
63
|
}
|
|
@@ -78,7 +89,14 @@ async function main() {
|
|
|
78
89
|
return;
|
|
79
90
|
}
|
|
80
91
|
if (args.includes('--help') || args.includes('-h')) {
|
|
81
|
-
|
|
92
|
+
if (args.includes('x402')) {
|
|
93
|
+
const x402Index = args.indexOf('x402');
|
|
94
|
+
const x402Args = args.slice(x402Index + 1);
|
|
95
|
+
await handleX402Command(x402Args);
|
|
96
|
+
await closeFileLogger();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const program = createTopLevelProgram();
|
|
82
100
|
await program.parseAsync(process.argv);
|
|
83
101
|
return;
|
|
84
102
|
}
|
|
@@ -87,37 +105,26 @@ async function main() {
|
|
|
87
105
|
validateArgValues(args);
|
|
88
106
|
}
|
|
89
107
|
catch (error) {
|
|
90
|
-
console.error(formatHumanError(error, false));
|
|
108
|
+
console.error(chalk.red(formatHumanError(error, false)));
|
|
91
109
|
process.exit(1);
|
|
92
110
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
console.error(formatHumanError(error, false));
|
|
107
|
-
process.exit(1);
|
|
111
|
+
let firstNonOption;
|
|
112
|
+
let firstNonOptionIndex = -1;
|
|
113
|
+
for (let i = 0; i < args.length; i++) {
|
|
114
|
+
const arg = args[i];
|
|
115
|
+
if (!arg)
|
|
116
|
+
continue;
|
|
117
|
+
if (arg.startsWith('-')) {
|
|
118
|
+
if (optionTakesValue(arg) && !arg.includes('=') && i + 1 < args.length) {
|
|
119
|
+
i++;
|
|
120
|
+
}
|
|
121
|
+
continue;
|
|
108
122
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
profiles: cleanTypes.includes('profiles'),
|
|
113
|
-
logs: cleanTypes.includes('logs'),
|
|
114
|
-
all: cleanTypes.includes('all'),
|
|
115
|
-
});
|
|
116
|
-
await closeFileLogger();
|
|
117
|
-
return;
|
|
123
|
+
firstNonOption = arg;
|
|
124
|
+
firstNonOptionIndex = i;
|
|
125
|
+
break;
|
|
118
126
|
}
|
|
119
|
-
|
|
120
|
-
if (!targetInfo) {
|
|
127
|
+
if (!firstNonOption) {
|
|
121
128
|
const { json } = extractOptions(args);
|
|
122
129
|
if (json)
|
|
123
130
|
setJsonMode(true);
|
|
@@ -128,240 +135,420 @@ async function main() {
|
|
|
128
135
|
await closeFileLogger();
|
|
129
136
|
return;
|
|
130
137
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
138
|
+
if (firstNonOption.startsWith('@')) {
|
|
139
|
+
const session = firstNonOption;
|
|
140
|
+
const modifiedArgs = [
|
|
141
|
+
...process.argv.slice(0, 2),
|
|
142
|
+
...args.slice(0, firstNonOptionIndex),
|
|
143
|
+
...args.slice(firstNonOptionIndex + 1),
|
|
144
|
+
];
|
|
145
|
+
try {
|
|
146
|
+
await handleSessionCommands(session, modifiedArgs);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (isMcpError(error)) {
|
|
150
|
+
const opts = extractOptions(args);
|
|
151
|
+
const outputMode = opts.json ? 'json' : 'human';
|
|
152
|
+
if (outputMode === 'json') {
|
|
153
|
+
console.error(formatJsonError(error, error.code));
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
console.error(chalk.red(formatHumanError(error, opts.verbose)));
|
|
157
|
+
}
|
|
158
|
+
process.exit(error.code);
|
|
152
159
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
await closeFileLogger();
|
|
164
|
+
}
|
|
165
|
+
await flushStdout();
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
if (KNOWN_COMMANDS.includes(firstNonOption)) {
|
|
169
|
+
if (firstNonOption === 'x402') {
|
|
170
|
+
const x402Args = args.slice(firstNonOptionIndex + 1);
|
|
171
|
+
await handleX402Command(x402Args);
|
|
172
|
+
await closeFileLogger();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const program = createTopLevelProgram();
|
|
177
|
+
await program.parseAsync(process.argv);
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
if (isMcpError(error)) {
|
|
181
|
+
const opts = extractOptions(args);
|
|
182
|
+
const outputMode = opts.json ? 'json' : 'human';
|
|
183
|
+
if (outputMode === 'json') {
|
|
184
|
+
console.error(formatJsonError(error, error.code));
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.error(chalk.red(formatHumanError(error, opts.verbose)));
|
|
159
188
|
}
|
|
189
|
+
process.exit(error.code);
|
|
160
190
|
}
|
|
161
|
-
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
await closeFileLogger();
|
|
162
195
|
}
|
|
163
|
-
|
|
196
|
+
return;
|
|
164
197
|
}
|
|
165
|
-
|
|
166
|
-
|
|
198
|
+
const opts = extractOptions(args);
|
|
199
|
+
const outputMode = opts.json ? 'json' : 'human';
|
|
200
|
+
const allCommands = [...KNOWN_COMMANDS, ...KNOWN_SESSION_COMMANDS];
|
|
201
|
+
if (allCommands.includes(firstNonOption)) {
|
|
202
|
+
if (outputMode === 'json') {
|
|
203
|
+
console.error(formatJsonError(new Error(`Missing session target for command: ${firstNonOption}`), 1));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.error(`Error: Missing session target for command: ${firstNonOption}`);
|
|
207
|
+
console.error(`\nDid you mean: mcpc <@session> ${firstNonOption}`);
|
|
208
|
+
console.error(`Run "mcpc --help" for usage information.\n`);
|
|
209
|
+
}
|
|
167
210
|
}
|
|
168
|
-
|
|
169
|
-
if (
|
|
170
|
-
|
|
211
|
+
else {
|
|
212
|
+
if (outputMode === 'json') {
|
|
213
|
+
console.error(formatJsonError(new Error(`Unknown command: ${firstNonOption}`), 1));
|
|
171
214
|
}
|
|
172
215
|
else {
|
|
173
|
-
|
|
174
|
-
|
|
216
|
+
console.error(`Error: Unknown command: ${firstNonOption}`);
|
|
217
|
+
console.error(`Run "mcpc --help" for usage information.\n`);
|
|
175
218
|
}
|
|
176
|
-
}
|
|
177
|
-
|
|
219
|
+
}
|
|
220
|
+
await closeFileLogger();
|
|
221
|
+
process.exit(1);
|
|
178
222
|
}
|
|
179
|
-
function
|
|
223
|
+
function createTopLevelProgram() {
|
|
180
224
|
const program = new Command();
|
|
181
225
|
program.configureOutput({
|
|
182
226
|
outputError: (str, write) => write(str),
|
|
183
227
|
getOutHelpWidth: () => 100,
|
|
184
228
|
getErrHelpWidth: () => 100,
|
|
185
229
|
});
|
|
230
|
+
program.configureHelp({
|
|
231
|
+
subcommandTerm: (cmd) => `${cmd.name()} ${cmd.usage()}`.replace(/^\[options\]\s*|\s*\[options\]/g, '').trim(),
|
|
232
|
+
styleTitle: (str) => chalk.bold(str),
|
|
233
|
+
styleSubcommandText: (str) => chalk.cyan(str),
|
|
234
|
+
});
|
|
235
|
+
const docsUrl = process.stdout.isTTY
|
|
236
|
+
? `https://github.com/apify/mcpc/tree/v${mcpcVersion}`
|
|
237
|
+
: `https://raw.githubusercontent.com/apify/mcpc/v${mcpcVersion}/README.md`;
|
|
186
238
|
program
|
|
187
239
|
.name('mcpc')
|
|
188
240
|
.description(`${rainbow('Universal')} command-line client for the Model Context Protocol (MCP).`)
|
|
189
|
-
.usage('[options]
|
|
190
|
-
.helpOption('-h, --help', 'Display general help')
|
|
241
|
+
.usage('[options] [<@session>] [<command>]')
|
|
191
242
|
.option('-j, --json', 'Output in JSON format for scripting')
|
|
192
|
-
.option('-c, --config <file>', 'Path to MCP config JSON file (e.g. ".vscode/mcp.json")')
|
|
193
|
-
.option('-H, --header <header>', 'HTTP header for remote MCP server (can be repeated)')
|
|
194
|
-
.version(mcpcVersion, '-v, --version', 'Output the version number')
|
|
195
243
|
.option('--verbose', 'Enable debug logging')
|
|
196
244
|
.option('--profile <name>', 'OAuth profile for the server ("default" if not provided)')
|
|
197
245
|
.option('--schema <file>', 'Validate tool/prompt schema against expected schema')
|
|
198
246
|
.option('--schema-mode <mode>', 'Schema validation mode: strict, compatible (default), ignore')
|
|
199
247
|
.option('--timeout <seconds>', 'Request timeout in seconds (default: 300)')
|
|
200
|
-
.option('--
|
|
201
|
-
.
|
|
202
|
-
.
|
|
203
|
-
.option('--clean[=types]', 'Clean up mcpc data (types: sessions, logs, profiles, all)');
|
|
204
|
-
const docsUrl = process.stdout.isTTY
|
|
205
|
-
? `https://github.com/apify/mcpc/tree/v${mcpcVersion}`
|
|
206
|
-
: `https://raw.githubusercontent.com/apify/mcpc/v${mcpcVersion}/README.md`;
|
|
248
|
+
.option('--insecure', 'Skip TLS certificate verification (for self-signed certs)')
|
|
249
|
+
.version(mcpcVersion, '-v, --version', 'Output the version number')
|
|
250
|
+
.helpOption('-h, --help', 'Display help');
|
|
207
251
|
program.addHelpText('after', `
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
252
|
+
${chalk.bold('MCP session commands (after connecting):')}
|
|
253
|
+
<@session> Show MCP server info and capabilities
|
|
254
|
+
<@session> ${chalk.cyan('tools-list')} List MCP tools
|
|
255
|
+
<@session> ${chalk.cyan('tools-get')} <name>
|
|
256
|
+
<@session> ${chalk.cyan('tools-call')} <name> [arg:=val ... | <json> | <stdin]
|
|
257
|
+
<@session> ${chalk.cyan('prompts-list')}
|
|
258
|
+
<@session> ${chalk.cyan('prompts-get')} <name> [arg:=val ... | <json> | <stdin]
|
|
259
|
+
<@session> ${chalk.cyan('resources-list')}
|
|
260
|
+
<@session> ${chalk.cyan('resources-read')} <uri>
|
|
261
|
+
<@session> ${chalk.cyan('resources-subscribe')} <uri>
|
|
262
|
+
<@session> ${chalk.cyan('resources-unsubscribe')} <uri>
|
|
263
|
+
<@session> ${chalk.cyan('resources-templates-list')}
|
|
264
|
+
<@session> ${chalk.cyan('tasks-list')}
|
|
265
|
+
<@session> ${chalk.cyan('tasks-get')} <taskId>
|
|
266
|
+
<@session> ${chalk.cyan('tasks-cancel')} <taskId>
|
|
267
|
+
<@session> ${chalk.cyan('logging-set-level')} <level>
|
|
268
|
+
<@session> ${chalk.cyan('ping')}
|
|
212
269
|
|
|
213
|
-
|
|
214
|
-
login Create OAuth profile with credentials for remote server
|
|
215
|
-
logout Remove OAuth profile for remote server
|
|
216
|
-
connect @<session> Connect to server and create named persistent session
|
|
217
|
-
restart Kill and restart a session
|
|
218
|
-
close Close a session
|
|
219
|
-
|
|
220
|
-
MCP server commands:
|
|
221
|
-
help Show server info ("help" can be omitted)
|
|
222
|
-
shell Open interactive shell
|
|
223
|
-
tools-list [--full] Send "tools/list" MCP request...
|
|
224
|
-
tools-get <tool-name>
|
|
225
|
-
tools-call <tool-name> [arg1:=val1 arg2:=val2 ... | <args-json> | <stdin]
|
|
226
|
-
prompts-list
|
|
227
|
-
prompts-get <prompt-name> [arg1:=val1 arg2:=val2 ... | <args-json> | <stdin]
|
|
228
|
-
resources
|
|
229
|
-
resources-list
|
|
230
|
-
resources-read <uri>
|
|
231
|
-
resources-subscribe <uri>
|
|
232
|
-
resources-unsubscribe <uri>
|
|
233
|
-
resources-templates-list
|
|
234
|
-
logging-set-level <level>
|
|
235
|
-
ping
|
|
236
|
-
|
|
237
|
-
x402 payment commands (no target needed):
|
|
238
|
-
x402 init Create a new x402 wallet
|
|
239
|
-
x402 import <key> Import wallet from private key
|
|
240
|
-
x402 info Show wallet info
|
|
241
|
-
x402 sign -r <base64> Sign payment from PAYMENT-REQUIRED header
|
|
242
|
-
x402 remove Remove the wallet
|
|
243
|
-
|
|
244
|
-
Run "mcpc" without <target> to show available sessions and profiles.
|
|
270
|
+
Run "mcpc" without arguments to show active sessions and OAuth profiles.
|
|
245
271
|
|
|
246
272
|
Full docs: ${docsUrl}`);
|
|
273
|
+
program
|
|
274
|
+
.command('connect [server] [@session]')
|
|
275
|
+
.usage('<server> <@session>')
|
|
276
|
+
.description('Connect to an MCP server and start a new named @session')
|
|
277
|
+
.option('-H, --header <header>', 'HTTP header (can be repeated)')
|
|
278
|
+
.option('--profile <name>', 'OAuth profile to use ("default" if skipped)')
|
|
279
|
+
.option('--no-profile', 'Skip OAuth profile (connect anonymously)')
|
|
280
|
+
.option('--proxy <[host:]port>', 'Start proxy MCP server for session')
|
|
281
|
+
.option('--proxy-bearer-token <token>', 'Require authentication for access to proxy server')
|
|
282
|
+
.option('--x402', 'Enable x402 auto-payment using the configured wallet')
|
|
283
|
+
.addHelpText('after', `
|
|
284
|
+
${chalk.bold('Server formats:')}
|
|
285
|
+
mcp.apify.com Remote HTTP server (https:// added automatically)
|
|
286
|
+
~/.vscode/mcp.json:puppeteer Config file entry (file:entry)
|
|
287
|
+
`)
|
|
288
|
+
.action(async (server, sessionName, opts, command) => {
|
|
289
|
+
if (!server) {
|
|
290
|
+
throw new ClientError('Missing required argument: server\n\nExample: mcpc connect mcp.apify.com @myapp');
|
|
291
|
+
}
|
|
292
|
+
if (!sessionName) {
|
|
293
|
+
throw new ClientError('Missing required argument: @session\n\nExample: mcpc connect mcp.apify.com @myapp');
|
|
294
|
+
}
|
|
295
|
+
const globalOpts = getOptionsFromCommand(command);
|
|
296
|
+
const parsed = parseServerArg(server);
|
|
297
|
+
const headers = opts.header
|
|
298
|
+
? Array.isArray(opts.header)
|
|
299
|
+
? opts.header
|
|
300
|
+
: [opts.header]
|
|
301
|
+
: undefined;
|
|
302
|
+
if (!parsed) {
|
|
303
|
+
throw new ClientError(`Invalid server: "${server}"\n\n` +
|
|
304
|
+
`Expected a URL (e.g. mcp.apify.com) or a config file entry (e.g. ~/.vscode/mcp.json:filesystem)`);
|
|
305
|
+
}
|
|
306
|
+
if (parsed.type === 'config') {
|
|
307
|
+
await sessions.connectSession(parsed.entry, sessionName, {
|
|
308
|
+
...globalOpts,
|
|
309
|
+
...(headers && { headers }),
|
|
310
|
+
config: parsed.file,
|
|
311
|
+
proxy: opts.proxy,
|
|
312
|
+
proxyBearerToken: opts.proxyBearerToken,
|
|
313
|
+
x402: opts.x402,
|
|
314
|
+
...(globalOpts.insecure && { insecure: true }),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
await sessions.connectSession(server, sessionName, {
|
|
319
|
+
...globalOpts,
|
|
320
|
+
...(headers && { headers }),
|
|
321
|
+
proxy: opts.proxy,
|
|
322
|
+
proxyBearerToken: opts.proxyBearerToken,
|
|
323
|
+
x402: opts.x402,
|
|
324
|
+
...(globalOpts.insecure && { insecure: true }),
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
program
|
|
329
|
+
.command('close [@session]')
|
|
330
|
+
.usage('<@session>')
|
|
331
|
+
.description('Close a session')
|
|
332
|
+
.action(async (sessionName, _opts, command) => {
|
|
333
|
+
if (!sessionName) {
|
|
334
|
+
throw new ClientError('Missing required argument: @session\n\nExample: mcpc close @myapp');
|
|
335
|
+
}
|
|
336
|
+
await sessions.closeSession(sessionName, getOptionsFromCommand(command));
|
|
337
|
+
});
|
|
338
|
+
program
|
|
339
|
+
.command('restart [@session]')
|
|
340
|
+
.usage('<@session>')
|
|
341
|
+
.description('Restart a session (losing all state)')
|
|
342
|
+
.action(async (sessionName, _opts, command) => {
|
|
343
|
+
if (!sessionName) {
|
|
344
|
+
throw new ClientError('Missing required argument: @session\n\nExample: mcpc restart @myapp');
|
|
345
|
+
}
|
|
346
|
+
await sessions.restartSession(sessionName, getOptionsFromCommand(command));
|
|
347
|
+
});
|
|
348
|
+
program
|
|
349
|
+
.command('shell [@session]')
|
|
350
|
+
.usage('<@session>')
|
|
351
|
+
.description('Open interactive shell for a session')
|
|
352
|
+
.action(async (sessionName) => {
|
|
353
|
+
if (!sessionName) {
|
|
354
|
+
throw new ClientError('Missing required argument: @session\n\nExample: mcpc shell @myapp');
|
|
355
|
+
}
|
|
356
|
+
await sessions.openShell(sessionName);
|
|
357
|
+
});
|
|
358
|
+
program
|
|
359
|
+
.command('login [server]')
|
|
360
|
+
.usage('<server>')
|
|
361
|
+
.description('Interactively login to a server using OAuth and save profile')
|
|
362
|
+
.option('--profile <name>', 'Profile name (default: "default")')
|
|
363
|
+
.option('--scope <scopes>', 'OAuth scopes to request, quoted and space-separated (e.g. --scope "read write")')
|
|
364
|
+
.option('--client-id <id>', 'OAuth client ID (for servers without dynamic client registration)')
|
|
365
|
+
.option('--client-secret <secret>', 'OAuth client secret (for servers without dynamic client registration)')
|
|
366
|
+
.action(async (server, opts, command) => {
|
|
367
|
+
if (!server) {
|
|
368
|
+
throw new ClientError('Missing required argument: server\n\nExample: mcpc login mcp.apify.com');
|
|
369
|
+
}
|
|
370
|
+
await auth.login(server, {
|
|
371
|
+
profile: opts.profile,
|
|
372
|
+
scope: opts.scope,
|
|
373
|
+
clientId: opts.clientId,
|
|
374
|
+
clientSecret: opts.clientSecret,
|
|
375
|
+
...getOptionsFromCommand(command),
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
program
|
|
379
|
+
.command('logout [server]')
|
|
380
|
+
.usage('<server>')
|
|
381
|
+
.description('Delete an authentication profile for a server')
|
|
382
|
+
.option('--profile <name>', 'Profile name (default: "default")')
|
|
383
|
+
.action(async (server, opts, command) => {
|
|
384
|
+
if (!server) {
|
|
385
|
+
throw new ClientError('Missing required argument: server\n\nExample: mcpc logout mcp.apify.com');
|
|
386
|
+
}
|
|
387
|
+
await auth.logout(server, {
|
|
388
|
+
profile: opts.profile,
|
|
389
|
+
...getOptionsFromCommand(command),
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
program
|
|
393
|
+
.command('clean [resources...]')
|
|
394
|
+
.description('Clean up mcpc data (sessions, profiles, logs, all)')
|
|
395
|
+
.addHelpText('after', `
|
|
396
|
+
${chalk.bold('Resources:')}
|
|
397
|
+
sessions Remove stale/crashed session records
|
|
398
|
+
profiles Remove authentication profiles
|
|
399
|
+
logs Remove bridge log files
|
|
400
|
+
all Remove all of the above
|
|
401
|
+
|
|
402
|
+
Without arguments, performs safe cleanup of stale data only.
|
|
403
|
+
`)
|
|
404
|
+
.action(async (resources, _opts, command) => {
|
|
405
|
+
const globalOpts = getOptionsFromCommand(command);
|
|
406
|
+
const VALID_CLEAN_TYPES = ['sessions', 'profiles', 'logs', 'all'];
|
|
407
|
+
for (const r of resources) {
|
|
408
|
+
if (!VALID_CLEAN_TYPES.includes(r)) {
|
|
409
|
+
throw new ClientError(`Invalid clean resource: "${r}". Valid resources are: ${VALID_CLEAN_TYPES.join(', ')}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
await clean({
|
|
413
|
+
outputMode: globalOpts.outputMode,
|
|
414
|
+
sessions: resources.includes('sessions'),
|
|
415
|
+
profiles: resources.includes('profiles'),
|
|
416
|
+
logs: resources.includes('logs'),
|
|
417
|
+
all: resources.includes('all'),
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
program
|
|
421
|
+
.command('x402 [subcommand] [args...]')
|
|
422
|
+
.description('Configure an x402 payment wallet (EXPERIMENTAL)')
|
|
423
|
+
.action(() => { });
|
|
424
|
+
program
|
|
425
|
+
.command('help [command] [subcommand]')
|
|
426
|
+
.description('Show help for a specific command')
|
|
427
|
+
.action(async (cmdName, subcommand) => {
|
|
428
|
+
if (!cmdName) {
|
|
429
|
+
program.outputHelp();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
if (cmdName === 'x402') {
|
|
433
|
+
const helpArgs = subcommand ? [subcommand, '--help'] : ['--help'];
|
|
434
|
+
await handleX402Command(helpArgs);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const topLevelCmd = program.commands.find((c) => c.name() === cmdName || c.aliases().includes(cmdName));
|
|
438
|
+
if (topLevelCmd) {
|
|
439
|
+
topLevelCmd.outputHelp();
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const dummyProgram = new Command();
|
|
443
|
+
registerSessionCommands(dummyProgram, '@dummy');
|
|
444
|
+
const sessionCmd = dummyProgram.commands.find((c) => c.name() === cmdName || c.aliases().includes(cmdName));
|
|
445
|
+
if (sessionCmd) {
|
|
446
|
+
sessionCmd.outputHelp();
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
console.error(`Unknown command: ${cmdName}`);
|
|
450
|
+
console.error(`Run "mcpc --help" for usage information.`);
|
|
451
|
+
process.exit(1);
|
|
452
|
+
});
|
|
453
|
+
program.action(async () => {
|
|
454
|
+
const opts = program.opts();
|
|
455
|
+
const json = opts.json || getJsonFromEnv();
|
|
456
|
+
if (json)
|
|
457
|
+
setJsonMode(true);
|
|
458
|
+
await sessions.listSessionsAndAuthProfiles({ outputMode: json ? 'json' : 'human' });
|
|
459
|
+
if (!json) {
|
|
460
|
+
console.log('\nRun "mcpc --help" for usage information.\n');
|
|
461
|
+
}
|
|
462
|
+
});
|
|
247
463
|
return program;
|
|
248
464
|
}
|
|
249
|
-
|
|
250
|
-
const program = createProgram();
|
|
251
|
-
program.argument('<target>', 'Target (session @name, MCP config entry, or server URL)');
|
|
252
|
-
if (!hasCommandAfterTarget(args)) {
|
|
253
|
-
const options = extractOptions(args);
|
|
254
|
-
if (options.verbose)
|
|
255
|
-
setVerbose(true);
|
|
256
|
-
if (options.json)
|
|
257
|
-
setJsonMode(true);
|
|
258
|
-
await sessions.showServerDetails(target, {
|
|
259
|
-
outputMode: options.json ? 'json' : 'human',
|
|
260
|
-
...(options.verbose && { verbose: true }),
|
|
261
|
-
...(options.config && { config: options.config }),
|
|
262
|
-
...(options.headers && { headers: options.headers }),
|
|
263
|
-
...(options.timeout !== undefined && { timeout: options.timeout }),
|
|
264
|
-
});
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
465
|
+
function registerSessionCommands(program, session) {
|
|
267
466
|
program
|
|
268
467
|
.command('help')
|
|
269
468
|
.description('Show server instructions and available capabilities')
|
|
270
469
|
.action(async (_options, command) => {
|
|
271
|
-
await sessions.showHelp(
|
|
470
|
+
await sessions.showHelp(session, getOptionsFromCommand(command));
|
|
272
471
|
});
|
|
273
472
|
program
|
|
274
473
|
.command('shell')
|
|
275
|
-
.description('Interactive shell for the
|
|
474
|
+
.description('Interactive shell for the session')
|
|
276
475
|
.action(async () => {
|
|
277
|
-
await sessions.openShell(
|
|
476
|
+
await sessions.openShell(session);
|
|
278
477
|
});
|
|
279
478
|
program
|
|
280
|
-
.command('close')
|
|
479
|
+
.command('close', { hidden: true })
|
|
281
480
|
.description('Close the session')
|
|
282
481
|
.action(async (_options, command) => {
|
|
283
|
-
await sessions.closeSession(
|
|
482
|
+
await sessions.closeSession(session, getOptionsFromCommand(command));
|
|
284
483
|
});
|
|
285
484
|
program
|
|
286
485
|
.command('restart')
|
|
287
486
|
.description('Restart the session (stop and start the bridge)')
|
|
288
487
|
.action(async (_options, command) => {
|
|
289
|
-
await sessions.restartSession(
|
|
290
|
-
});
|
|
291
|
-
program
|
|
292
|
-
.command('connect <name>')
|
|
293
|
-
.description('Create or reconnect a named session to an MCP server')
|
|
294
|
-
.action(async (name, _options, command) => {
|
|
295
|
-
const opts = command.optsWithGlobals();
|
|
296
|
-
await sessions.connectSession(name, target, {
|
|
297
|
-
...getOptionsFromCommand(command),
|
|
298
|
-
proxy: opts.proxy,
|
|
299
|
-
proxyBearerToken: opts.proxyBearerToken,
|
|
300
|
-
x402: opts.x402,
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
program
|
|
304
|
-
.command('login')
|
|
305
|
-
.description('Login to a server using OAuth and save authentication profile')
|
|
306
|
-
.option('--profile <name>', 'Profile name (default: default)')
|
|
307
|
-
.option('--scope <scope>', 'OAuth scope(s) to request')
|
|
308
|
-
.action(async (options, command) => {
|
|
309
|
-
await auth.login(target, {
|
|
310
|
-
profile: options.profile,
|
|
311
|
-
scope: options.scope,
|
|
312
|
-
...getOptionsFromCommand(command),
|
|
313
|
-
});
|
|
314
|
-
});
|
|
315
|
-
program
|
|
316
|
-
.command('logout')
|
|
317
|
-
.description('Delete an authentication profile')
|
|
318
|
-
.option('--profile <name>', 'Profile name (default: default)')
|
|
319
|
-
.action(async (options, command) => {
|
|
320
|
-
await auth.logout(target, {
|
|
321
|
-
profile: options.profile,
|
|
322
|
-
...getOptionsFromCommand(command),
|
|
323
|
-
});
|
|
488
|
+
await sessions.restartSession(session, getOptionsFromCommand(command));
|
|
324
489
|
});
|
|
325
490
|
program
|
|
326
491
|
.command('tools')
|
|
327
492
|
.description('List available tools (shorthand for tools-list)')
|
|
328
493
|
.option('--full', 'Show full tool details including complete input schema')
|
|
329
494
|
.action(async (_options, command) => {
|
|
330
|
-
await tools.listTools(
|
|
495
|
+
await tools.listTools(session, getOptionsFromCommand(command));
|
|
331
496
|
});
|
|
332
497
|
program
|
|
333
498
|
.command('tools-list')
|
|
334
499
|
.description('List available tools')
|
|
335
500
|
.option('--full', 'Show full tool details including complete input schema')
|
|
336
501
|
.action(async (_options, command) => {
|
|
337
|
-
await tools.listTools(
|
|
502
|
+
await tools.listTools(session, getOptionsFromCommand(command));
|
|
338
503
|
});
|
|
339
504
|
program
|
|
340
505
|
.command('tools-get <name>')
|
|
341
506
|
.description('Get information about a specific tool')
|
|
342
507
|
.action(async (name, _options, command) => {
|
|
343
|
-
await tools.getTool(
|
|
508
|
+
await tools.getTool(session, name, getOptionsFromCommand(command));
|
|
344
509
|
});
|
|
345
510
|
program
|
|
346
511
|
.command('tools-call <name> [args...]')
|
|
347
512
|
.description('Call a tool with arguments (key:=value pairs or JSON)')
|
|
348
|
-
.
|
|
349
|
-
|
|
513
|
+
.option('--task', 'Use task execution (experimental)')
|
|
514
|
+
.option('--detach', 'Start task and return immediately with task ID (implies --task)')
|
|
515
|
+
.action(async (name, args, options, command) => {
|
|
516
|
+
await tools.callTool(session, name, {
|
|
350
517
|
args,
|
|
518
|
+
task: options.task,
|
|
519
|
+
detach: options.detach,
|
|
351
520
|
...getOptionsFromCommand(command),
|
|
352
521
|
});
|
|
353
522
|
});
|
|
523
|
+
program
|
|
524
|
+
.command('tasks-list')
|
|
525
|
+
.description('List active tasks')
|
|
526
|
+
.action(async (_options, command) => {
|
|
527
|
+
await tasks.listTasks(session, getOptionsFromCommand(command));
|
|
528
|
+
});
|
|
529
|
+
program
|
|
530
|
+
.command('tasks-get <taskId>')
|
|
531
|
+
.description('Get status of a specific task')
|
|
532
|
+
.action(async (taskId, _options, command) => {
|
|
533
|
+
await tasks.getTask(session, taskId, getOptionsFromCommand(command));
|
|
534
|
+
});
|
|
535
|
+
program
|
|
536
|
+
.command('tasks-cancel <taskId>')
|
|
537
|
+
.description('Cancel a running task')
|
|
538
|
+
.action(async (taskId, _options, command) => {
|
|
539
|
+
await tasks.cancelTask(session, taskId, getOptionsFromCommand(command));
|
|
540
|
+
});
|
|
354
541
|
program
|
|
355
542
|
.command('resources')
|
|
356
543
|
.description('List available resources (shorthand for resources-list)')
|
|
357
544
|
.action(async (_options, command) => {
|
|
358
|
-
await resources.listResources(
|
|
545
|
+
await resources.listResources(session, getOptionsFromCommand(command));
|
|
359
546
|
});
|
|
360
547
|
program
|
|
361
548
|
.command('resources-list')
|
|
362
549
|
.description('List available resources')
|
|
363
550
|
.action(async (_options, command) => {
|
|
364
|
-
await resources.listResources(
|
|
551
|
+
await resources.listResources(session, getOptionsFromCommand(command));
|
|
365
552
|
});
|
|
366
553
|
program
|
|
367
554
|
.command('resources-read <uri>')
|
|
@@ -369,9 +556,8 @@ async function handleCommands(target, args) {
|
|
|
369
556
|
.option('-o, --output <file>', 'Write resource to file')
|
|
370
557
|
.option('--max-size <bytes>', 'Maximum resource size in bytes')
|
|
371
558
|
.action(async (uri, options, command) => {
|
|
372
|
-
await resources.getResource(
|
|
559
|
+
await resources.getResource(session, uri, {
|
|
373
560
|
output: options.output,
|
|
374
|
-
raw: options.raw,
|
|
375
561
|
maxSize: options.maxSize,
|
|
376
562
|
...getOptionsFromCommand(command),
|
|
377
563
|
});
|
|
@@ -380,37 +566,37 @@ async function handleCommands(target, args) {
|
|
|
380
566
|
.command('resources-subscribe <uri>')
|
|
381
567
|
.description('Subscribe to resource updates')
|
|
382
568
|
.action(async (uri, _options, command) => {
|
|
383
|
-
await resources.subscribeResource(
|
|
569
|
+
await resources.subscribeResource(session, uri, getOptionsFromCommand(command));
|
|
384
570
|
});
|
|
385
571
|
program
|
|
386
572
|
.command('resources-unsubscribe <uri>')
|
|
387
573
|
.description('Unsubscribe from resource updates')
|
|
388
574
|
.action(async (uri, _options, command) => {
|
|
389
|
-
await resources.unsubscribeResource(
|
|
575
|
+
await resources.unsubscribeResource(session, uri, getOptionsFromCommand(command));
|
|
390
576
|
});
|
|
391
577
|
program
|
|
392
578
|
.command('resources-templates-list')
|
|
393
579
|
.description('List available resource templates')
|
|
394
580
|
.action(async (_options, command) => {
|
|
395
|
-
await resources.listResourceTemplates(
|
|
581
|
+
await resources.listResourceTemplates(session, getOptionsFromCommand(command));
|
|
396
582
|
});
|
|
397
583
|
program
|
|
398
584
|
.command('prompts')
|
|
399
585
|
.description('List available prompts (shorthand for prompts-list)')
|
|
400
586
|
.action(async (_options, command) => {
|
|
401
|
-
await prompts.listPrompts(
|
|
587
|
+
await prompts.listPrompts(session, getOptionsFromCommand(command));
|
|
402
588
|
});
|
|
403
589
|
program
|
|
404
590
|
.command('prompts-list')
|
|
405
591
|
.description('List available prompts')
|
|
406
592
|
.action(async (_options, command) => {
|
|
407
|
-
await prompts.listPrompts(
|
|
593
|
+
await prompts.listPrompts(session, getOptionsFromCommand(command));
|
|
408
594
|
});
|
|
409
595
|
program
|
|
410
596
|
.command('prompts-get <name> [args...]')
|
|
411
597
|
.description('Get a prompt by name with arguments (key:=value pairs or JSON)')
|
|
412
598
|
.action(async (name, args, _options, command) => {
|
|
413
|
-
await prompts.getPrompt(
|
|
599
|
+
await prompts.getPrompt(session, name, {
|
|
414
600
|
args,
|
|
415
601
|
...getOptionsFromCommand(command),
|
|
416
602
|
});
|
|
@@ -419,14 +605,50 @@ async function handleCommands(target, args) {
|
|
|
419
605
|
.command('logging-set-level <level>')
|
|
420
606
|
.description('Set server logging level (debug, info, notice, warning, error, critical, alert, emergency)')
|
|
421
607
|
.action(async (level, _options, command) => {
|
|
422
|
-
await logging.setLogLevel(
|
|
608
|
+
await logging.setLogLevel(session, level, getOptionsFromCommand(command));
|
|
423
609
|
});
|
|
424
610
|
program
|
|
425
611
|
.command('ping')
|
|
426
612
|
.description('Ping the MCP server to check if it is alive')
|
|
427
613
|
.action(async (_options, command) => {
|
|
428
|
-
await utilities.ping(
|
|
614
|
+
await utilities.ping(session, getOptionsFromCommand(command));
|
|
429
615
|
});
|
|
616
|
+
}
|
|
617
|
+
function createSessionProgram() {
|
|
618
|
+
const program = new Command();
|
|
619
|
+
program.configureOutput({
|
|
620
|
+
outputError: (str, write) => write(str),
|
|
621
|
+
getOutHelpWidth: () => 100,
|
|
622
|
+
getErrHelpWidth: () => 100,
|
|
623
|
+
});
|
|
624
|
+
program
|
|
625
|
+
.name('mcpc <@session>')
|
|
626
|
+
.helpOption('-h, --help', 'Display help')
|
|
627
|
+
.option('-j, --json', 'Output in JSON format for scripting and code mode')
|
|
628
|
+
.option('--verbose', 'Enable debug logging')
|
|
629
|
+
.option('--profile <name>', 'OAuth profile override')
|
|
630
|
+
.option('--schema <file>', 'Validate tool/prompt schema against expected schema')
|
|
631
|
+
.option('--schema-mode <mode>', 'Schema validation mode: strict, compatible (default), ignore')
|
|
632
|
+
.option('--timeout <seconds>', 'Request timeout in seconds (default: 300)')
|
|
633
|
+
.option('--insecure', 'Skip TLS certificate verification (for self-signed certs)');
|
|
634
|
+
return program;
|
|
635
|
+
}
|
|
636
|
+
async function handleSessionCommands(session, args) {
|
|
637
|
+
if (!hasSubcommand(args)) {
|
|
638
|
+
const options = extractOptions(args);
|
|
639
|
+
if (options.verbose)
|
|
640
|
+
setVerbose(true);
|
|
641
|
+
if (options.json)
|
|
642
|
+
setJsonMode(true);
|
|
643
|
+
await sessions.showServerDetails(session, {
|
|
644
|
+
outputMode: options.json ? 'json' : 'human',
|
|
645
|
+
...(options.verbose && { verbose: true }),
|
|
646
|
+
...(options.timeout !== undefined && { timeout: options.timeout }),
|
|
647
|
+
});
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
const program = createSessionProgram();
|
|
651
|
+
registerSessionCommands(program, session);
|
|
430
652
|
try {
|
|
431
653
|
await program.parseAsync(args);
|
|
432
654
|
}
|
|
@@ -438,16 +660,27 @@ async function handleCommands(target, args) {
|
|
|
438
660
|
console.error(formatJsonError(error, error.code));
|
|
439
661
|
}
|
|
440
662
|
else {
|
|
441
|
-
console.error(formatHumanError(error, opts.verbose));
|
|
663
|
+
console.error(chalk.red(formatHumanError(error, opts.verbose)));
|
|
442
664
|
}
|
|
443
665
|
process.exit(error.code);
|
|
444
666
|
}
|
|
445
667
|
console.error(outputMode === 'json'
|
|
446
668
|
? formatJsonError(error, 1)
|
|
447
|
-
: formatHumanError(error, opts.verbose));
|
|
669
|
+
: chalk.red(formatHumanError(error, opts.verbose)));
|
|
448
670
|
process.exit(1);
|
|
449
671
|
}
|
|
450
672
|
}
|
|
673
|
+
async function flushStdout() {
|
|
674
|
+
await new Promise((resolve) => {
|
|
675
|
+
if (process.stdout.writableFinished) {
|
|
676
|
+
resolve();
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
process.stdout.once('finish', resolve);
|
|
680
|
+
process.stdout.end();
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
}
|
|
451
684
|
main().catch(async (error) => {
|
|
452
685
|
console.error('Fatal error:', error);
|
|
453
686
|
await closeFileLogger();
|