@protoboxai/cli 1.0.0
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/README.md +78 -0
- package/bin/protobox.js +8 -0
- package/dist/cli.js +60 -0
- package/dist/commands/auth.js +294 -0
- package/dist/commands/chat.js +203 -0
- package/dist/commands/config.js +237 -0
- package/dist/commands/health.js +59 -0
- package/dist/commands/index.js +25 -0
- package/dist/commands/knowledge.js +539 -0
- package/dist/commands/mcp.js +589 -0
- package/dist/commands/prompts.js +295 -0
- package/dist/commands/tools.js +632 -0
- package/dist/commands/toolsets.js +464 -0
- package/dist/commands/workspaces.js +170 -0
- package/dist/index.js +6 -0
- package/dist/utils/config-store.js +209 -0
- package/dist/utils/output.js +221 -0
- package/dist/utils/sdk-factory.js +46 -0
- package/package.json +62 -0
|
@@ -0,0 +1,589 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
5
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
6
|
+
import { configStore } from "../utils/config-store.js";
|
|
7
|
+
import { createSdk } from "../utils/sdk-factory.js";
|
|
8
|
+
import {
|
|
9
|
+
printSuccess,
|
|
10
|
+
printError,
|
|
11
|
+
printInfo,
|
|
12
|
+
printLabel,
|
|
13
|
+
printBlank,
|
|
14
|
+
printSimpleTable,
|
|
15
|
+
isJsonOutput,
|
|
16
|
+
printJson
|
|
17
|
+
} from "../utils/output.js";
|
|
18
|
+
function createMcpCommand() {
|
|
19
|
+
const mcp = new Command("mcp").description("MCP server configuration and status").addHelpText(
|
|
20
|
+
"after",
|
|
21
|
+
`
|
|
22
|
+
What is MCP?
|
|
23
|
+
Model Context Protocol (MCP) lets AI agents (Claude, Cursor, etc.) use your
|
|
24
|
+
Chanl tools, knowledge base, and prompts. The MCP server bridges your workspace
|
|
25
|
+
with AI clients.
|
|
26
|
+
|
|
27
|
+
Quick Start:
|
|
28
|
+
$ chanl mcp # Check server status
|
|
29
|
+
$ chanl mcp test # Run protocol test
|
|
30
|
+
$ chanl mcp config # Get config for your AI client
|
|
31
|
+
|
|
32
|
+
Connecting AI Clients:
|
|
33
|
+
1. Run 'chanl mcp config --format claude' to get Claude Desktop config
|
|
34
|
+
2. Add the JSON to Claude Desktop's settings
|
|
35
|
+
3. Your Chanl tools will appear in Claude!`
|
|
36
|
+
).action(handleMcpDefault);
|
|
37
|
+
mcp.command("info").description("Show MCP server URL, status, and resource counts").addHelpText(
|
|
38
|
+
"after",
|
|
39
|
+
`
|
|
40
|
+
Example:
|
|
41
|
+
$ chanl mcp info # Show server details
|
|
42
|
+
$ chanl mcp info --json # Output as JSON`
|
|
43
|
+
).action(handleMcpInfo);
|
|
44
|
+
mcp.command("status").description("Health check the MCP server").addHelpText(
|
|
45
|
+
"after",
|
|
46
|
+
`
|
|
47
|
+
Example:
|
|
48
|
+
$ chanl mcp status # Quick health check`
|
|
49
|
+
).action(handleMcpStatus);
|
|
50
|
+
mcp.command("test").description("Run MCP protocol test with real MCP client").addHelpText(
|
|
51
|
+
"after",
|
|
52
|
+
`
|
|
53
|
+
Tests the full MCP protocol handshake:
|
|
54
|
+
1. Connect to MCP server
|
|
55
|
+
2. List available tools
|
|
56
|
+
3. List resources (knowledge base)
|
|
57
|
+
4. List prompts
|
|
58
|
+
|
|
59
|
+
Example:
|
|
60
|
+
$ chanl mcp test # Run all protocol tests
|
|
61
|
+
$ chanl mcp test --json # Output results as JSON`
|
|
62
|
+
).action(handleMcpTest);
|
|
63
|
+
mcp.command("config").description("Output MCP configuration for AI clients").option("-f, --format <format>", "Format: claude, cursor, generic", "generic").addHelpText(
|
|
64
|
+
"after",
|
|
65
|
+
`
|
|
66
|
+
Generates configuration JSON for connecting AI clients to your MCP server.
|
|
67
|
+
|
|
68
|
+
Supported formats:
|
|
69
|
+
claude - Claude Desktop (claude_desktop_config.json)
|
|
70
|
+
cursor - Cursor IDE settings
|
|
71
|
+
generic - Generic MCP client format
|
|
72
|
+
|
|
73
|
+
Examples:
|
|
74
|
+
$ chanl mcp config # Generic format
|
|
75
|
+
$ chanl mcp config --format claude # Claude Desktop format
|
|
76
|
+
$ chanl mcp config --format cursor # Cursor IDE format
|
|
77
|
+
$ chanl mcp config --format claude > config.json # Save to file
|
|
78
|
+
|
|
79
|
+
Setup Claude Desktop:
|
|
80
|
+
1. Run: chanl mcp config --format claude
|
|
81
|
+
2. Copy the JSON output
|
|
82
|
+
3. Paste into ~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
83
|
+
).action(handleMcpConfig);
|
|
84
|
+
mcp.command("tools <agent-id>").description("List MCP tools available for an agent").addHelpText(
|
|
85
|
+
"after",
|
|
86
|
+
`
|
|
87
|
+
Example:
|
|
88
|
+
$ chanl mcp tools agent_123 # List tools for agent
|
|
89
|
+
$ chanl mcp tools agent_123 --json # Output as JSON`
|
|
90
|
+
).action(handleMcpTools);
|
|
91
|
+
mcp.command("call <agent-id> <tool-name> [args]").description("Call an MCP tool by name").addHelpText(
|
|
92
|
+
"after",
|
|
93
|
+
`
|
|
94
|
+
Example:
|
|
95
|
+
$ chanl mcp call agent_123 get_weather '{"city":"London"}'
|
|
96
|
+
$ chanl mcp call agent_123 ping
|
|
97
|
+
$ chanl mcp call agent_123 get_weather '{"city":"London"}' --json`
|
|
98
|
+
).action(handleMcpCall);
|
|
99
|
+
mcp.command("inspect <agent-id> <tool-name>").description("Show schema and details for a specific MCP tool").addHelpText(
|
|
100
|
+
"after",
|
|
101
|
+
`
|
|
102
|
+
Example:
|
|
103
|
+
$ chanl mcp inspect agent_123 get_weather
|
|
104
|
+
$ chanl mcp inspect agent_123 get_weather --json`
|
|
105
|
+
).action(handleMcpInspect);
|
|
106
|
+
mcp.command("install").description("Generate MCP config snippet for editors (Cursor, VSCode, Claude)").option("-f, --format <format>", "Format: claude, cursor, vscode, generic", "generic").addHelpText(
|
|
107
|
+
"after",
|
|
108
|
+
`
|
|
109
|
+
Generates a ready-to-use MCP configuration using your stored API key and workspace.
|
|
110
|
+
No server call needed \u2014 works offline.
|
|
111
|
+
|
|
112
|
+
Supported formats:
|
|
113
|
+
claude - Claude Desktop / Claude Code
|
|
114
|
+
cursor - Cursor IDE
|
|
115
|
+
vscode - Visual Studio Code
|
|
116
|
+
generic - Generic MCP client (default)
|
|
117
|
+
|
|
118
|
+
Examples:
|
|
119
|
+
$ chanl mcp install # Generic format
|
|
120
|
+
$ chanl mcp install --format claude # Claude Desktop format
|
|
121
|
+
$ chanl mcp install --format cursor # Cursor IDE format
|
|
122
|
+
$ chanl mcp install --format vscode # VSCode format
|
|
123
|
+
$ chanl mcp install --format claude > mcp.json # Save to file`
|
|
124
|
+
).action(handleMcpInstall);
|
|
125
|
+
return mcp;
|
|
126
|
+
}
|
|
127
|
+
async function handleMcpInfo() {
|
|
128
|
+
const sdk = createSdk();
|
|
129
|
+
if (!sdk) return;
|
|
130
|
+
const spinner = ora("Fetching MCP configuration...").start();
|
|
131
|
+
try {
|
|
132
|
+
const response = await sdk.mcp.getConfig();
|
|
133
|
+
spinner.stop();
|
|
134
|
+
if (!response.success || !response.data) {
|
|
135
|
+
printError("Failed to fetch MCP configuration", response.message);
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const config = response.data;
|
|
140
|
+
if (isJsonOutput()) {
|
|
141
|
+
printJson(config);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
printBlank();
|
|
145
|
+
printSimpleTable(
|
|
146
|
+
["Property", "Value"],
|
|
147
|
+
[
|
|
148
|
+
["Server URL", config.serverUrl],
|
|
149
|
+
["Environment", config.environment],
|
|
150
|
+
["Status", config.status === "active" ? chalk.green("active") : chalk.red("disabled")],
|
|
151
|
+
["Tools", config.toolCount.toString()],
|
|
152
|
+
["Resources", config.resourceCount.toString()],
|
|
153
|
+
["Prompts", config.promptCount.toString()],
|
|
154
|
+
...config.toolsetName ? [["Toolset", config.toolsetName]] : []
|
|
155
|
+
]
|
|
156
|
+
);
|
|
157
|
+
printBlank();
|
|
158
|
+
} catch (error) {
|
|
159
|
+
spinner.fail("Failed to fetch MCP configuration");
|
|
160
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
161
|
+
printError("Error", message);
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async function handleMcpStatus() {
|
|
166
|
+
const sdk = createSdk();
|
|
167
|
+
if (!sdk) return;
|
|
168
|
+
const spinner = ora("Checking MCP server health...").start();
|
|
169
|
+
try {
|
|
170
|
+
const response = await sdk.mcp.getStatus();
|
|
171
|
+
spinner.stop();
|
|
172
|
+
if (!response.success || !response.data) {
|
|
173
|
+
printError("Failed to check MCP status", response.message);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const status = response.data;
|
|
178
|
+
if (isJsonOutput()) {
|
|
179
|
+
printJson(status);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
printBlank();
|
|
183
|
+
if (status.healthy) {
|
|
184
|
+
printSuccess("MCP server is healthy");
|
|
185
|
+
printLabel("Message", status.message);
|
|
186
|
+
if (status.responseTimeMs) {
|
|
187
|
+
printLabel("Response Time", status.responseTimeMs + "ms");
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
printError("MCP server is unhealthy", status.message);
|
|
191
|
+
if (status.error) {
|
|
192
|
+
printLabel("Error", status.error);
|
|
193
|
+
}
|
|
194
|
+
process.exitCode = 1;
|
|
195
|
+
}
|
|
196
|
+
printBlank();
|
|
197
|
+
} catch (error) {
|
|
198
|
+
spinner.fail("Failed to check MCP status");
|
|
199
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
200
|
+
printError("Error", message);
|
|
201
|
+
process.exitCode = 1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async function handleMcpConfig(options) {
|
|
205
|
+
const sdk = createSdk();
|
|
206
|
+
if (!sdk) return;
|
|
207
|
+
const spinner = ora("Fetching MCP configuration...").start();
|
|
208
|
+
try {
|
|
209
|
+
const response = await sdk.mcp.getConfig();
|
|
210
|
+
spinner.stop();
|
|
211
|
+
if (!response.success || !response.data) {
|
|
212
|
+
printError("Failed to fetch MCP configuration", response.message);
|
|
213
|
+
process.exitCode = 1;
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const config = response.data;
|
|
217
|
+
const format = options.format.toLowerCase();
|
|
218
|
+
let output;
|
|
219
|
+
switch (format) {
|
|
220
|
+
case "claude":
|
|
221
|
+
output = config.agentConfigs.claude;
|
|
222
|
+
break;
|
|
223
|
+
case "cursor":
|
|
224
|
+
output = config.agentConfigs.cursor;
|
|
225
|
+
break;
|
|
226
|
+
case "generic":
|
|
227
|
+
default:
|
|
228
|
+
output = config.agentConfigs.generic;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
printJson(output);
|
|
232
|
+
if (!isJsonOutput()) {
|
|
233
|
+
printBlank();
|
|
234
|
+
printInfo(`Configuration for ${format} format. Copy and paste into your ${format === "claude" ? "Claude Desktop" : format === "cursor" ? "Cursor IDE" : "MCP client"} configuration.`);
|
|
235
|
+
printInfo(`Replace \${CHANL_MCP_API_KEY} with your actual MCP API key.`);
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
spinner.fail("Failed to fetch MCP configuration");
|
|
239
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
240
|
+
printError("Error", message);
|
|
241
|
+
process.exitCode = 1;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async function handleMcpDefault() {
|
|
245
|
+
const sdk = createSdk();
|
|
246
|
+
if (!sdk) return;
|
|
247
|
+
const spinner = ora("Checking MCP server...").start();
|
|
248
|
+
try {
|
|
249
|
+
const [configResponse, statusResponse] = await Promise.all([
|
|
250
|
+
sdk.mcp.getConfig(),
|
|
251
|
+
sdk.mcp.getStatus()
|
|
252
|
+
]);
|
|
253
|
+
spinner.stop();
|
|
254
|
+
if (!configResponse.success || !configResponse.data) {
|
|
255
|
+
printError("Failed to fetch MCP configuration", configResponse.message);
|
|
256
|
+
process.exitCode = 1;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const config = configResponse.data;
|
|
260
|
+
const status = statusResponse.data;
|
|
261
|
+
if (isJsonOutput()) {
|
|
262
|
+
printJson({ config, status });
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const statusIcon = status?.healthy ? chalk.green("\u2713") : chalk.red("\u2717");
|
|
266
|
+
const statusText = status?.healthy ? "Connected" : "Unhealthy";
|
|
267
|
+
const latency = status?.responseTimeMs ? ` (${status.responseTimeMs}ms)` : "";
|
|
268
|
+
printBlank();
|
|
269
|
+
console.log(chalk.bold("MCP Server"));
|
|
270
|
+
console.log(chalk.dim("\u2500".repeat(40)));
|
|
271
|
+
printLabel("Server URL", config.serverUrl ?? "Not configured");
|
|
272
|
+
printLabel("Status", `${statusIcon} ${statusText}${latency}`);
|
|
273
|
+
printLabel("Tools", `${config.toolCount ?? 0} enabled`);
|
|
274
|
+
printLabel("Resources", (config.resourceCount ?? 0).toString());
|
|
275
|
+
printLabel("Prompts", (config.promptCount ?? 0).toString());
|
|
276
|
+
console.log(chalk.dim("\u2500".repeat(40)));
|
|
277
|
+
printBlank();
|
|
278
|
+
if (!status?.healthy) {
|
|
279
|
+
printInfo("Run 'chanl mcp test' for detailed diagnostics");
|
|
280
|
+
process.exitCode = 1;
|
|
281
|
+
}
|
|
282
|
+
} catch (error) {
|
|
283
|
+
spinner.fail("Failed to check MCP server");
|
|
284
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
285
|
+
printError("Error", message);
|
|
286
|
+
process.exitCode = 1;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function handleMcpTools(agentId) {
|
|
290
|
+
const sdk = createSdk();
|
|
291
|
+
if (!sdk) return;
|
|
292
|
+
const spinner = ora("Fetching MCP tools...").start();
|
|
293
|
+
try {
|
|
294
|
+
const response = await sdk.mcp.listTools(agentId);
|
|
295
|
+
spinner.stop();
|
|
296
|
+
if (!response.success || !response.data) {
|
|
297
|
+
printError("Failed to fetch MCP tools", response.message);
|
|
298
|
+
process.exitCode = 1;
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const tools = response.data.tools;
|
|
302
|
+
if (isJsonOutput()) {
|
|
303
|
+
printJson({ tools });
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
if (tools.length === 0) {
|
|
307
|
+
printBlank();
|
|
308
|
+
printInfo("No MCP tools available for this agent");
|
|
309
|
+
printBlank();
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
printBlank();
|
|
313
|
+
printSimpleTable(
|
|
314
|
+
["Name", "Description"],
|
|
315
|
+
tools.map((t) => [
|
|
316
|
+
t.name,
|
|
317
|
+
t.description || chalk.dim("No description")
|
|
318
|
+
])
|
|
319
|
+
);
|
|
320
|
+
printBlank();
|
|
321
|
+
printInfo(`Total: ${tools.length} tool${tools.length === 1 ? "" : "s"}`);
|
|
322
|
+
printBlank();
|
|
323
|
+
} catch (error) {
|
|
324
|
+
spinner.fail("Failed to fetch MCP tools");
|
|
325
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
326
|
+
printError("Error", message);
|
|
327
|
+
process.exitCode = 1;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
async function handleMcpCall(agentId, toolName, argsJson) {
|
|
331
|
+
const sdk = createSdk();
|
|
332
|
+
if (!sdk) return;
|
|
333
|
+
let args;
|
|
334
|
+
if (argsJson) {
|
|
335
|
+
try {
|
|
336
|
+
args = JSON.parse(argsJson);
|
|
337
|
+
} catch {
|
|
338
|
+
printError("Invalid JSON arguments", `Could not parse: ${argsJson}`);
|
|
339
|
+
process.exitCode = 1;
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const spinner = ora(`Calling tool '${toolName}'...`).start();
|
|
344
|
+
try {
|
|
345
|
+
const response = await sdk.mcp.callTool(agentId, toolName, args);
|
|
346
|
+
spinner.stop();
|
|
347
|
+
if (!response.success || !response.data) {
|
|
348
|
+
printError("Failed to call tool", response.message);
|
|
349
|
+
process.exitCode = 1;
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const result = response.data;
|
|
353
|
+
if (isJsonOutput()) {
|
|
354
|
+
printJson(result);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (result.isError) {
|
|
358
|
+
for (const item of result.content) {
|
|
359
|
+
if (item.text) {
|
|
360
|
+
printError("Tool returned an error", item.text);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
process.exitCode = 1;
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
printBlank();
|
|
367
|
+
for (const item of result.content) {
|
|
368
|
+
if (item.text) {
|
|
369
|
+
console.log(item.text);
|
|
370
|
+
} else {
|
|
371
|
+
printJson(item);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
printBlank();
|
|
375
|
+
} catch (error) {
|
|
376
|
+
spinner.fail("Failed to call tool");
|
|
377
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
378
|
+
printError("Error", message);
|
|
379
|
+
process.exitCode = 1;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async function handleMcpInspect(agentId, toolName) {
|
|
383
|
+
const sdk = createSdk();
|
|
384
|
+
if (!sdk) return;
|
|
385
|
+
const spinner = ora(`Fetching tool '${toolName}'...`).start();
|
|
386
|
+
try {
|
|
387
|
+
const response = await sdk.mcp.getTool(agentId, toolName);
|
|
388
|
+
spinner.stop();
|
|
389
|
+
if (!response.success || !response.data) {
|
|
390
|
+
printError("Failed to fetch tool details", response.message);
|
|
391
|
+
process.exitCode = 1;
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
const tool = response.data;
|
|
395
|
+
if (isJsonOutput()) {
|
|
396
|
+
printJson(tool);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
printBlank();
|
|
400
|
+
console.log(chalk.bold(tool.name));
|
|
401
|
+
console.log(chalk.dim("\u2500".repeat(40)));
|
|
402
|
+
if (tool.description) {
|
|
403
|
+
printLabel("Description", tool.description);
|
|
404
|
+
}
|
|
405
|
+
printBlank();
|
|
406
|
+
console.log(chalk.bold("Input Schema"));
|
|
407
|
+
console.log(chalk.dim("\u2500".repeat(40)));
|
|
408
|
+
const schema = tool.inputSchema;
|
|
409
|
+
const properties = schema["properties"];
|
|
410
|
+
const required = schema["required"] || [];
|
|
411
|
+
if (properties) {
|
|
412
|
+
const rows = [];
|
|
413
|
+
for (const [name, prop] of Object.entries(properties)) {
|
|
414
|
+
const isRequired = required.includes(name);
|
|
415
|
+
const typeStr = String(prop["type"] || "any");
|
|
416
|
+
const desc = String(prop["description"] || "");
|
|
417
|
+
const reqStr = isRequired ? chalk.red("*") : " ";
|
|
418
|
+
rows.push([`${reqStr} ${name}`, typeStr, desc]);
|
|
419
|
+
}
|
|
420
|
+
printSimpleTable(["Parameter", "Type", "Description"], rows);
|
|
421
|
+
} else {
|
|
422
|
+
printInfo("No parameters defined");
|
|
423
|
+
}
|
|
424
|
+
printBlank();
|
|
425
|
+
} catch (error) {
|
|
426
|
+
spinner.fail("Failed to fetch tool details");
|
|
427
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
428
|
+
printError("Error", message);
|
|
429
|
+
process.exitCode = 1;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async function handleMcpInstall(options) {
|
|
433
|
+
const apiKey = configStore.getApiKey();
|
|
434
|
+
if (!apiKey) {
|
|
435
|
+
printError("Not authenticated", "Run 'chanl login' to authenticate first");
|
|
436
|
+
process.exitCode = 1;
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const baseUrl = configStore.getBaseUrl() || "https://api.chanl.ai";
|
|
440
|
+
const mcpUrl = baseUrl.replace(/\/$/, "") + "/mcp";
|
|
441
|
+
const format = options.format.toLowerCase();
|
|
442
|
+
const serverConfig = {
|
|
443
|
+
url: mcpUrl,
|
|
444
|
+
headers: { "X-API-Key": apiKey },
|
|
445
|
+
transport: "streamable-http"
|
|
446
|
+
};
|
|
447
|
+
let output;
|
|
448
|
+
switch (format) {
|
|
449
|
+
case "claude":
|
|
450
|
+
output = {
|
|
451
|
+
mcpServers: {
|
|
452
|
+
chanl: serverConfig
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
break;
|
|
456
|
+
case "cursor":
|
|
457
|
+
output = {
|
|
458
|
+
mcpServers: {
|
|
459
|
+
chanl: serverConfig
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
break;
|
|
463
|
+
case "vscode":
|
|
464
|
+
output = {
|
|
465
|
+
mcpServers: {
|
|
466
|
+
chanl: serverConfig
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
break;
|
|
470
|
+
case "generic":
|
|
471
|
+
default:
|
|
472
|
+
output = {
|
|
473
|
+
mcpServers: {
|
|
474
|
+
chanl: serverConfig
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
printJson(output);
|
|
480
|
+
if (!isJsonOutput()) {
|
|
481
|
+
printBlank();
|
|
482
|
+
const targetName = format === "claude" ? "Claude Desktop / Claude Code" : format === "cursor" ? "Cursor IDE" : format === "vscode" ? "Visual Studio Code" : "your MCP client";
|
|
483
|
+
printInfo(`Copy the JSON above into your ${targetName} configuration.`);
|
|
484
|
+
printBlank();
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async function handleMcpTest() {
|
|
488
|
+
const sdk = createSdk();
|
|
489
|
+
if (!sdk) return;
|
|
490
|
+
const spinner = ora("Fetching MCP configuration...").start();
|
|
491
|
+
let config;
|
|
492
|
+
try {
|
|
493
|
+
const configResponse = await sdk.mcp.getConfig();
|
|
494
|
+
if (!configResponse.success || !configResponse.data) {
|
|
495
|
+
spinner.fail("Failed to fetch MCP configuration");
|
|
496
|
+
printError("Error", configResponse.message || "Unknown error");
|
|
497
|
+
process.exitCode = 1;
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
config = configResponse.data;
|
|
501
|
+
} catch (error) {
|
|
502
|
+
spinner.fail("Failed to fetch MCP configuration");
|
|
503
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
504
|
+
printError("Error", message);
|
|
505
|
+
process.exitCode = 1;
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
spinner.text = "Running MCP protocol test...";
|
|
509
|
+
const apiKey = process.env.MCP_API_KEY || configStore.getApiKey();
|
|
510
|
+
if (!apiKey) {
|
|
511
|
+
spinner.fail("No API key available");
|
|
512
|
+
printError("Error", "API key required for MCP test. Set MCP_API_KEY env var for local dev.");
|
|
513
|
+
process.exitCode = 1;
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const results = [];
|
|
517
|
+
try {
|
|
518
|
+
const transport = new StreamableHTTPClientTransport(new URL(config.serverUrl), {
|
|
519
|
+
requestInit: {
|
|
520
|
+
headers: { "X-API-Key": apiKey }
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
const client = new Client(
|
|
524
|
+
{ name: "chanl-cli", version: "1.0.0" },
|
|
525
|
+
{ capabilities: {} }
|
|
526
|
+
);
|
|
527
|
+
spinner.text = "Connecting to MCP server...";
|
|
528
|
+
const connectStart = Date.now();
|
|
529
|
+
await client.connect(transport);
|
|
530
|
+
const connectTime = Date.now() - connectStart;
|
|
531
|
+
results.push({ test: "Connection", passed: true, detail: `${connectTime}ms` });
|
|
532
|
+
spinner.text = "Testing tools/list...";
|
|
533
|
+
try {
|
|
534
|
+
const tools = await client.listTools();
|
|
535
|
+
results.push({ test: "tools/list", passed: true, detail: `${tools.tools.length} tools` });
|
|
536
|
+
} catch (err) {
|
|
537
|
+
results.push({ test: "tools/list", passed: false, detail: err instanceof Error ? err.message : "Failed" });
|
|
538
|
+
}
|
|
539
|
+
spinner.text = "Testing resources/list...";
|
|
540
|
+
try {
|
|
541
|
+
const resources = await client.listResources();
|
|
542
|
+
results.push({ test: "resources/list", passed: true, detail: `${resources.resources.length} resources` });
|
|
543
|
+
} catch (err) {
|
|
544
|
+
results.push({ test: "resources/list", passed: true, detail: "N/A (no knowledge base)" });
|
|
545
|
+
}
|
|
546
|
+
spinner.text = "Testing prompts/list...";
|
|
547
|
+
try {
|
|
548
|
+
const prompts = await client.listPrompts();
|
|
549
|
+
results.push({ test: "prompts/list", passed: true, detail: `${prompts.prompts.length} prompts` });
|
|
550
|
+
} catch (err) {
|
|
551
|
+
results.push({ test: "prompts/list", passed: true, detail: "N/A" });
|
|
552
|
+
}
|
|
553
|
+
await client.close();
|
|
554
|
+
spinner.stop();
|
|
555
|
+
if (isJsonOutput()) {
|
|
556
|
+
printJson({ serverUrl: config.serverUrl, results });
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
printBlank();
|
|
560
|
+
console.log(chalk.bold("\u{1F9EA} MCP Protocol Test"));
|
|
561
|
+
console.log(chalk.dim("\u2500".repeat(50)));
|
|
562
|
+
printLabel("Server", config.serverUrl);
|
|
563
|
+
console.log(chalk.dim("\u2500".repeat(50)));
|
|
564
|
+
let allPassed = true;
|
|
565
|
+
for (const result of results) {
|
|
566
|
+
const icon = result.passed ? chalk.green("\u2713") : chalk.red("\u2717");
|
|
567
|
+
console.log(`${icon} ${result.test}: ${result.detail}`);
|
|
568
|
+
if (!result.passed) allPassed = false;
|
|
569
|
+
}
|
|
570
|
+
console.log(chalk.dim("\u2500".repeat(50)));
|
|
571
|
+
if (allPassed) {
|
|
572
|
+
printSuccess("All tests passed");
|
|
573
|
+
} else {
|
|
574
|
+
printError("Some tests failed", "Check the results above");
|
|
575
|
+
process.exitCode = 1;
|
|
576
|
+
}
|
|
577
|
+
printBlank();
|
|
578
|
+
} catch (error) {
|
|
579
|
+
spinner.fail("MCP protocol test failed");
|
|
580
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
581
|
+
printError("Connection failed", message);
|
|
582
|
+
printInfo("Make sure the MCP server is running and accessible");
|
|
583
|
+
process.exitCode = 1;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
export {
|
|
587
|
+
createMcpCommand
|
|
588
|
+
};
|
|
589
|
+
//# sourceMappingURL=mcp.js.map
|