@evantahler/mcpx 0.18.2 → 0.18.5
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/package.json +63 -62
- package/src/cli.ts +46 -54
- package/src/client/browser.ts +15 -15
- package/src/client/debug-fetch.ts +53 -56
- package/src/client/elicitation.ts +279 -291
- package/src/client/http.ts +1 -1
- package/src/client/manager.ts +481 -514
- package/src/client/oauth.ts +272 -282
- package/src/client/sse.ts +1 -1
- package/src/client/stdio.ts +7 -7
- package/src/client/trace.ts +146 -152
- package/src/client/transport-options.ts +20 -20
- package/src/commands/add.ts +160 -165
- package/src/commands/allow.ts +141 -142
- package/src/commands/auth.ts +86 -90
- package/src/commands/check-update.ts +49 -53
- package/src/commands/deny.ts +114 -117
- package/src/commands/exec.ts +218 -222
- package/src/commands/index.ts +41 -41
- package/src/commands/info.ts +48 -50
- package/src/commands/list.ts +49 -49
- package/src/commands/ping.ts +47 -50
- package/src/commands/prompt.ts +40 -50
- package/src/commands/remove.ts +54 -56
- package/src/commands/resource.ts +31 -36
- package/src/commands/search.ts +35 -39
- package/src/commands/servers.ts +44 -48
- package/src/commands/skill.ts +89 -95
- package/src/commands/task.ts +50 -60
- package/src/commands/upgrade.ts +191 -208
- package/src/commands/with-command.ts +27 -29
- package/src/config/env.ts +26 -28
- package/src/config/loader.ts +99 -102
- package/src/config/schemas.ts +78 -87
- package/src/constants.ts +17 -17
- package/src/context.ts +51 -51
- package/src/lib/client-settings.ts +127 -140
- package/src/lib/input.ts +23 -26
- package/src/output/format-output.ts +12 -16
- package/src/output/format-table.ts +39 -42
- package/src/output/formatter.ts +790 -814
- package/src/output/logger.ts +140 -152
- package/src/sdk.ts +283 -291
- package/src/search/index.ts +50 -54
- package/src/search/indexer.ts +65 -65
- package/src/search/keyword.ts +54 -54
- package/src/search/semantic.ts +39 -39
- package/src/search/staleness.ts +3 -3
- package/src/search/types.ts +4 -4
- package/src/update/background.ts +51 -51
- package/src/update/cache.ts +21 -21
- package/src/update/checker.ts +81 -86
- package/src/validation/schema.ts +52 -58
package/src/commands/info.ts
CHANGED
|
@@ -1,58 +1,56 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
import type {
|
|
3
|
-
import { formatServerOverview, formatToolSchema
|
|
2
|
+
import type { Prompt, Resource, Tool } from "../config/schemas.ts";
|
|
3
|
+
import { formatError, formatServerOverview, formatToolSchema } from "../output/formatter.ts";
|
|
4
4
|
import { withCommand } from "./with-command.ts";
|
|
5
5
|
|
|
6
6
|
export function registerInfoCommand(program: Command) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
program
|
|
8
|
+
.command("info <server> [tool]")
|
|
9
|
+
.description("show server overview, or schema for a specific tool")
|
|
10
|
+
.action(
|
|
11
|
+
withCommand(
|
|
12
|
+
program,
|
|
13
|
+
{ spinnerText: "Connecting..." },
|
|
14
|
+
async ({ manager, formatOptions, spinner }, server: string, tool?: string) => {
|
|
15
|
+
const target = tool ? `${server}/${tool}` : server;
|
|
16
|
+
spinner.update(`Connecting to ${target}...`);
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const serverInfo = await manager.getServerInfo(server);
|
|
30
|
-
const caps = serverInfo.capabilities as Record<string, unknown> | undefined;
|
|
18
|
+
if (tool) {
|
|
19
|
+
const toolSchema = await manager.getToolSchema(server, tool);
|
|
20
|
+
spinner.stop();
|
|
21
|
+
if (!toolSchema) {
|
|
22
|
+
console.error(formatError(`Tool "${tool}" not found on server "${server}"`, formatOptions));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
console.log(formatToolSchema(server, toolSchema, formatOptions));
|
|
26
|
+
} else {
|
|
27
|
+
const serverInfo = await manager.getServerInfo(server);
|
|
28
|
+
const caps = serverInfo.capabilities as Record<string, unknown> | undefined;
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
const fetches: [Promise<Tool[]>, Promise<Resource[]>, Promise<Prompt[]>] = [
|
|
31
|
+
caps?.tools !== undefined ? manager.listTools(server) : Promise.resolve([]),
|
|
32
|
+
caps?.resources !== undefined ? manager.listResources(server) : Promise.resolve([]),
|
|
33
|
+
caps?.prompts !== undefined ? manager.listPrompts(server) : Promise.resolve([]),
|
|
34
|
+
];
|
|
35
|
+
const [tools, resources, prompts] = await Promise.all(fetches);
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
37
|
+
spinner.stop();
|
|
38
|
+
console.log(
|
|
39
|
+
formatServerOverview(
|
|
40
|
+
{
|
|
41
|
+
serverName: server,
|
|
42
|
+
version: serverInfo.version,
|
|
43
|
+
capabilities: caps,
|
|
44
|
+
instructions: serverInfo.instructions,
|
|
45
|
+
tools,
|
|
46
|
+
resourceCount: resources.length,
|
|
47
|
+
promptCount: prompts.length,
|
|
48
|
+
},
|
|
49
|
+
formatOptions,
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
),
|
|
55
|
+
);
|
|
58
56
|
}
|
package/src/commands/list.ts
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
import { formatUnifiedList } from "../output/formatter.ts";
|
|
3
2
|
import type { UnifiedItem } from "../output/formatter.ts";
|
|
3
|
+
import { formatUnifiedList } from "../output/formatter.ts";
|
|
4
4
|
import { withCommand } from "./with-command.ts";
|
|
5
5
|
|
|
6
6
|
export function registerListCommand(program: Command) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
program.action(
|
|
8
|
+
withCommand(
|
|
9
|
+
program,
|
|
10
|
+
{ spinnerText: "Connecting to servers...", errorLabel: "Failed to list servers" },
|
|
11
|
+
async ({ manager, formatOptions, spinner }) => {
|
|
12
|
+
const [toolsResult, resourcesResult, promptsResult] = await Promise.all([
|
|
13
|
+
manager.getAllTools(),
|
|
14
|
+
manager.getAllResources(),
|
|
15
|
+
manager.getAllPrompts(),
|
|
16
|
+
]);
|
|
17
|
+
spinner.stop();
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
19
|
+
const items: UnifiedItem[] = [
|
|
20
|
+
...toolsResult.tools.map((t) => ({
|
|
21
|
+
server: t.server,
|
|
22
|
+
type: "tool" as const,
|
|
23
|
+
name: t.tool.name,
|
|
24
|
+
description: t.tool.description,
|
|
25
|
+
})),
|
|
26
|
+
...resourcesResult.resources.map((r) => ({
|
|
27
|
+
server: r.server,
|
|
28
|
+
type: "resource" as const,
|
|
29
|
+
name: r.resource.uri,
|
|
30
|
+
description: r.resource.description,
|
|
31
|
+
})),
|
|
32
|
+
...promptsResult.prompts.map((p) => ({
|
|
33
|
+
server: p.server,
|
|
34
|
+
type: "prompt" as const,
|
|
35
|
+
name: p.prompt.name,
|
|
36
|
+
description: p.prompt.description,
|
|
37
|
+
})),
|
|
38
|
+
];
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
const typeOrder = { tool: 0, resource: 1, prompt: 2 };
|
|
41
|
+
items.sort((a, b) => {
|
|
42
|
+
if (a.server !== b.server) return a.server.localeCompare(b.server);
|
|
43
|
+
if (a.type !== b.type) return typeOrder[a.type] - typeOrder[b.type];
|
|
44
|
+
return a.name.localeCompare(b.name);
|
|
45
|
+
});
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
const errors = [...toolsResult.errors, ...resourcesResult.errors, ...promptsResult.errors];
|
|
48
|
+
if (errors.length > 0) {
|
|
49
|
+
for (const err of errors) {
|
|
50
|
+
console.error(`"${err.server}": ${err.message}`);
|
|
51
|
+
}
|
|
52
|
+
if (items.length > 0) console.log("");
|
|
53
|
+
}
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
console.log(formatUnifiedList(items, formatOptions));
|
|
56
|
+
},
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
59
|
}
|
package/src/commands/ping.ts
CHANGED
|
@@ -5,65 +5,62 @@ import { formatError } from "../output/formatter.ts";
|
|
|
5
5
|
import { logger } from "../output/logger.ts";
|
|
6
6
|
|
|
7
7
|
interface PingResult {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
server: string;
|
|
9
|
+
success: boolean;
|
|
10
|
+
latencyMs?: number;
|
|
11
|
+
error?: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function registerPingCommand(program: Command) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
program
|
|
16
|
+
.command("ping [servers...]")
|
|
17
|
+
.description("Check connectivity to MCP servers")
|
|
18
|
+
.action(async (servers: string[]) => {
|
|
19
|
+
const { manager, formatOptions } = await getContext(program);
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
const targetServers = servers.length > 0 ? servers : manager.getServerNames();
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
if (targetServers.length === 0) {
|
|
24
|
+
console.error(formatError("No servers configured", formatOptions));
|
|
25
|
+
await manager.close();
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
`Pinging ${targetServers.length} server(s)...`,
|
|
31
|
-
formatOptions,
|
|
32
|
-
);
|
|
29
|
+
const spinner = logger.startSpinner(`Pinging ${targetServers.length} server(s)...`, formatOptions);
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
const results: PingResult[] = [];
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
33
|
+
try {
|
|
34
|
+
await Promise.all(
|
|
35
|
+
targetServers.map(async (serverName) => {
|
|
36
|
+
const start = Date.now();
|
|
37
|
+
try {
|
|
38
|
+
await manager.getClient(serverName);
|
|
39
|
+
results.push({ server: serverName, success: true, latencyMs: Date.now() - start });
|
|
40
|
+
} catch (err) {
|
|
41
|
+
results.push({ server: serverName, success: false, error: String(err) });
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
);
|
|
48
45
|
|
|
49
|
-
|
|
46
|
+
spinner.stop();
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
48
|
+
if (formatOptions.json) {
|
|
49
|
+
console.log(JSON.stringify(results, null, 2));
|
|
50
|
+
} else {
|
|
51
|
+
for (const r of results) {
|
|
52
|
+
if (r.success) {
|
|
53
|
+
console.log(`${green("✔")} ${r.server} connected (${r.latencyMs}ms)`);
|
|
54
|
+
} else {
|
|
55
|
+
console.log(`${red("✖")} ${r.server} failed: ${r.error}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} finally {
|
|
60
|
+
await manager.close();
|
|
61
|
+
}
|
|
65
62
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
const anyFailed = results.some((r) => !r.success);
|
|
64
|
+
if (anyFailed) process.exit(1);
|
|
65
|
+
});
|
|
69
66
|
}
|
package/src/commands/prompt.ts
CHANGED
|
@@ -1,59 +1,49 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
import {
|
|
3
|
-
formatPromptList,
|
|
4
|
-
formatServerPrompts,
|
|
5
|
-
formatPromptMessages,
|
|
6
|
-
formatError,
|
|
7
|
-
} from "../output/formatter.ts";
|
|
8
2
|
import { parseJsonArgs, readStdin } from "../lib/input.ts";
|
|
3
|
+
import { formatError, formatPromptList, formatPromptMessages, formatServerPrompts } from "../output/formatter.ts";
|
|
9
4
|
import { withCommand } from "./with-command.ts";
|
|
10
5
|
|
|
11
6
|
export function registerPromptCommand(program: Command) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
argsStr?: string,
|
|
24
|
-
) => {
|
|
25
|
-
if (server) {
|
|
26
|
-
spinner.update(`Connecting to ${server}...`);
|
|
27
|
-
}
|
|
7
|
+
program
|
|
8
|
+
.command("prompt [server] [name] [args]")
|
|
9
|
+
.description("list prompts for a server, or get a specific prompt")
|
|
10
|
+
.action(
|
|
11
|
+
withCommand(
|
|
12
|
+
program,
|
|
13
|
+
{ spinnerText: "Connecting to servers..." },
|
|
14
|
+
async ({ manager, formatOptions, spinner }, server?: string, name?: string, argsStr?: string) => {
|
|
15
|
+
if (server) {
|
|
16
|
+
spinner.update(`Connecting to ${server}...`);
|
|
17
|
+
}
|
|
28
18
|
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
if (server && name) {
|
|
20
|
+
let args: Record<string, string> | undefined;
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
if (argsStr) {
|
|
23
|
+
args = parseJsonArgs(argsStr, { coerceToString: true }) as Record<string, string>;
|
|
24
|
+
} else if (!process.stdin.isTTY) {
|
|
25
|
+
const stdin = await readStdin();
|
|
26
|
+
if (stdin.trim()) {
|
|
27
|
+
args = parseJsonArgs(stdin, { coerceToString: true }) as Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
31
|
+
const result = await manager.getPrompt(server, name, args);
|
|
32
|
+
spinner.stop();
|
|
33
|
+
console.log(formatPromptMessages(server, name, result, formatOptions));
|
|
34
|
+
} else if (server) {
|
|
35
|
+
const prompts = await manager.listPrompts(server);
|
|
36
|
+
spinner.stop();
|
|
37
|
+
console.log(formatServerPrompts(server, prompts, formatOptions));
|
|
38
|
+
} else {
|
|
39
|
+
const { prompts, errors } = await manager.getAllPrompts();
|
|
40
|
+
spinner.stop();
|
|
41
|
+
console.log(formatPromptList(prompts, formatOptions));
|
|
42
|
+
for (const err of errors) {
|
|
43
|
+
console.error(formatError(`${err.server}: ${err.message}`, formatOptions));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
),
|
|
48
|
+
);
|
|
59
49
|
}
|
package/src/commands/remove.ts
CHANGED
|
@@ -1,67 +1,65 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
loadRawAuth,
|
|
4
|
+
loadRawServers,
|
|
5
|
+
loadSearchIndex,
|
|
6
|
+
saveAuth,
|
|
7
|
+
saveSearchIndex,
|
|
8
|
+
saveServers,
|
|
9
9
|
} from "../config/loader.ts";
|
|
10
10
|
|
|
11
11
|
export function registerRemoveCommand(program: Command) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
program
|
|
13
|
+
.command("remove <name>")
|
|
14
|
+
.description("remove an MCP server from your config")
|
|
15
|
+
.option("--keep-auth", "keep stored authentication credentials")
|
|
16
|
+
.option("--dry-run", "show what would be removed without changing files")
|
|
17
|
+
.action(async (name: string, options: { keepAuth?: boolean; dryRun?: boolean }) => {
|
|
18
|
+
const configFlag = program.opts().config;
|
|
19
|
+
const { configDir, servers } = await loadRawServers(configFlag);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
if (!servers.mcpServers[name]) {
|
|
22
|
+
console.error(`Unknown server: "${name}"`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
26
|
+
if (options.dryRun) {
|
|
27
|
+
console.log(`Would remove server "${name}" from ${configDir}/servers.json`);
|
|
28
|
+
if (!options.keepAuth) {
|
|
29
|
+
const auth = await loadRawAuth(configDir);
|
|
30
|
+
if (auth[name]) {
|
|
31
|
+
console.log(`Would remove auth for "${name}" from ${configDir}/auth.json`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const searchIndex = await loadSearchIndex(configDir);
|
|
35
|
+
const indexedCount = searchIndex.tools.filter((t) => t.server === name).length;
|
|
36
|
+
if (indexedCount > 0) {
|
|
37
|
+
console.log(`Would remove ${indexedCount} tool(s) for "${name}" from ${configDir}/search.json`);
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
delete servers.mcpServers[name];
|
|
43
|
+
await saveServers(configDir, servers);
|
|
44
|
+
console.log(`Removed server "${name}" from ${configDir}/servers.json`);
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
if (!options.keepAuth) {
|
|
47
|
+
const auth = await loadRawAuth(configDir);
|
|
48
|
+
if (auth[name]) {
|
|
49
|
+
delete auth[name];
|
|
50
|
+
await saveAuth(configDir, auth);
|
|
51
|
+
console.log(`Removed auth for "${name}" from ${configDir}/auth.json`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
56
54
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
// Remove tools for this server from the search index
|
|
56
|
+
const searchIndex = await loadSearchIndex(configDir);
|
|
57
|
+
const before = searchIndex.tools.length;
|
|
58
|
+
searchIndex.tools = searchIndex.tools.filter((t) => t.server !== name);
|
|
59
|
+
const removed = before - searchIndex.tools.length;
|
|
60
|
+
if (removed > 0) {
|
|
61
|
+
await saveSearchIndex(configDir, searchIndex);
|
|
62
|
+
console.log(`Removed ${removed} tool(s) for "${name}" from ${configDir}/search.json`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
67
65
|
}
|
package/src/commands/resource.ts
CHANGED
|
@@ -1,42 +1,37 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
import {
|
|
3
|
-
formatResourceList,
|
|
4
|
-
formatServerResources,
|
|
5
|
-
formatResourceContents,
|
|
6
|
-
formatError,
|
|
7
|
-
} from "../output/formatter.ts";
|
|
2
|
+
import { formatError, formatResourceContents, formatResourceList, formatServerResources } from "../output/formatter.ts";
|
|
8
3
|
import { withCommand } from "./with-command.ts";
|
|
9
4
|
|
|
10
5
|
export function registerResourceCommand(program: Command) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
program
|
|
7
|
+
.command("resource [server] [uri]")
|
|
8
|
+
.description("list resources for a server, or read a specific resource")
|
|
9
|
+
.action(
|
|
10
|
+
withCommand(
|
|
11
|
+
program,
|
|
12
|
+
{ spinnerText: "Connecting to servers..." },
|
|
13
|
+
async ({ manager, formatOptions, spinner }, server?: string, uri?: string) => {
|
|
14
|
+
if (server) {
|
|
15
|
+
spinner.update(`Connecting to ${server}...`);
|
|
16
|
+
}
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
18
|
+
if (server && uri) {
|
|
19
|
+
const result = await manager.readResource(server, uri);
|
|
20
|
+
spinner.stop();
|
|
21
|
+
console.log(formatResourceContents(server, uri, result, formatOptions));
|
|
22
|
+
} else if (server) {
|
|
23
|
+
const resources = await manager.listResources(server);
|
|
24
|
+
spinner.stop();
|
|
25
|
+
console.log(formatServerResources(server, resources, formatOptions));
|
|
26
|
+
} else {
|
|
27
|
+
const { resources, errors } = await manager.getAllResources();
|
|
28
|
+
spinner.stop();
|
|
29
|
+
console.log(formatResourceList(resources, formatOptions));
|
|
30
|
+
for (const err of errors) {
|
|
31
|
+
console.error(formatError(`${err.server}: ${err.message}`, formatOptions));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
),
|
|
36
|
+
);
|
|
42
37
|
}
|