@evantahler/mcpx 0.20.0 → 0.20.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/package.json +1 -1
- package/src/cli.ts +2 -1
- package/src/client/browser.ts +4 -3
- package/src/client/elicitation.ts +16 -15
- package/src/config/loader.ts +2 -1
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -21,6 +21,7 @@ import { registerServersCommand } from "./commands/servers.ts";
|
|
|
21
21
|
import { registerSkillCommand } from "./commands/skill.ts";
|
|
22
22
|
import { registerTaskCommand } from "./commands/task.ts";
|
|
23
23
|
import { registerUpgradeCommand } from "./commands/upgrade.ts";
|
|
24
|
+
import { logger } from "./output/logger.ts";
|
|
24
25
|
import { maybeCheckForUpdate } from "./update/background.ts";
|
|
25
26
|
|
|
26
27
|
program
|
|
@@ -96,5 +97,5 @@ program.parse();
|
|
|
96
97
|
// Print update notice after command output completes
|
|
97
98
|
process.on("beforeExit", async () => {
|
|
98
99
|
const notice = await updateNotice;
|
|
99
|
-
if (notice)
|
|
100
|
+
if (notice) logger.writeRaw(notice);
|
|
100
101
|
});
|
package/src/client/browser.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
+
import { logger } from "../output/logger.ts";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Open a URL in the default browser (macOS/Windows/Linux).
|
|
@@ -12,11 +13,11 @@ export function openBrowser(url: string): Promise<void> {
|
|
|
12
13
|
try {
|
|
13
14
|
const parsed = new URL(url);
|
|
14
15
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
15
|
-
|
|
16
|
+
logger.error(`Refusing to open non-HTTP URL: ${url}`);
|
|
16
17
|
return Promise.resolve();
|
|
17
18
|
}
|
|
18
19
|
} catch {
|
|
19
|
-
|
|
20
|
+
logger.error(`Invalid URL: ${url}`);
|
|
20
21
|
return Promise.resolve();
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -37,7 +38,7 @@ export function openBrowser(url: string): Promise<void> {
|
|
|
37
38
|
return new Promise((resolve) => {
|
|
38
39
|
execFile(cmd, args, (err) => {
|
|
39
40
|
if (err) {
|
|
40
|
-
|
|
41
|
+
logger.warn(`Could not open browser. Please visit:\n ${url}`);
|
|
41
42
|
}
|
|
42
43
|
resolve();
|
|
43
44
|
});
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
PrimitiveSchemaDefinition,
|
|
8
8
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
9
|
import ansis from "ansis";
|
|
10
|
+
import { logger } from "../output/logger.ts";
|
|
10
11
|
import { validateElicitationResponse } from "../validation/schema.ts";
|
|
11
12
|
import { openBrowser } from "./browser.ts";
|
|
12
13
|
|
|
@@ -74,7 +75,7 @@ async function handleFormInteractive(params: ElicitRequestFormParams): Promise<E
|
|
|
74
75
|
const question = (prompt: string): Promise<string> => new Promise((resolve) => rl.question(prompt, resolve));
|
|
75
76
|
|
|
76
77
|
try {
|
|
77
|
-
|
|
78
|
+
logger.writeRaw(`\n${ansis.bold("Server requests input:")} ${params.message}\n`);
|
|
78
79
|
|
|
79
80
|
const schema = params.requestedSchema;
|
|
80
81
|
const properties = schema.properties ?? {};
|
|
@@ -86,7 +87,7 @@ async function handleFormInteractive(params: ElicitRequestFormParams): Promise<E
|
|
|
86
87
|
const value = await promptField(key, fieldSchema, isRequired, question);
|
|
87
88
|
if (value === undefined) {
|
|
88
89
|
if (isRequired) {
|
|
89
|
-
|
|
90
|
+
logger.writeRaw(ansis.yellow("Cancelled.\n"));
|
|
90
91
|
return { action: "cancel" };
|
|
91
92
|
}
|
|
92
93
|
continue;
|
|
@@ -98,7 +99,7 @@ async function handleFormInteractive(params: ElicitRequestFormParams): Promise<E
|
|
|
98
99
|
const validation = validateElicitationResponse(schema as unknown as Record<string, unknown>, content);
|
|
99
100
|
if (!validation.valid) {
|
|
100
101
|
const msgs = validation.errors.map((e) => ` ${e.path}: ${e.message}`).join("\n");
|
|
101
|
-
|
|
102
|
+
logger.writeRaw(ansis.red(`Validation failed:\n${msgs}\n`));
|
|
102
103
|
return { action: "cancel" };
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -121,7 +122,7 @@ async function promptField(
|
|
|
121
122
|
|
|
122
123
|
// Show description if present
|
|
123
124
|
if (desc) {
|
|
124
|
-
|
|
125
|
+
logger.writeRaw(ansis.dim(` ${desc}\n`));
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
// Enum (single-select)
|
|
@@ -178,7 +179,7 @@ async function promptNumber(
|
|
|
178
179
|
if (!answer) return undefined;
|
|
179
180
|
const num = Number(answer);
|
|
180
181
|
if (Number.isNaN(num)) {
|
|
181
|
-
|
|
182
|
+
logger.writeRaw(ansis.red(` Invalid number: ${answer}\n`));
|
|
182
183
|
return undefined;
|
|
183
184
|
}
|
|
184
185
|
return num;
|
|
@@ -206,10 +207,10 @@ async function promptEnum(
|
|
|
206
207
|
): Promise<string | undefined> {
|
|
207
208
|
const values = (schema as { enum: string[] }).enum;
|
|
208
209
|
const def = (schema as { default?: string }).default;
|
|
209
|
-
|
|
210
|
+
logger.writeRaw(` ${marker}${label}:\n`);
|
|
210
211
|
values.forEach((v, i) => {
|
|
211
212
|
const defMark = v === def ? ansis.dim(" (default)") : "";
|
|
212
|
-
|
|
213
|
+
logger.writeRaw(` [${i + 1}] ${v}${defMark}\n`);
|
|
213
214
|
});
|
|
214
215
|
const answer = await question(" > ");
|
|
215
216
|
if (!answer && def !== undefined) return def;
|
|
@@ -228,10 +229,10 @@ async function promptOneOfEnum(
|
|
|
228
229
|
): Promise<string | undefined> {
|
|
229
230
|
const options = (schema as { oneOf: { const: string; title: string }[] }).oneOf;
|
|
230
231
|
const def = (schema as { default?: string }).default;
|
|
231
|
-
|
|
232
|
+
logger.writeRaw(` ${marker}${label}:\n`);
|
|
232
233
|
options.forEach((opt, i) => {
|
|
233
234
|
const defMark = opt.const === def ? ansis.dim(" (default)") : "";
|
|
234
|
-
|
|
235
|
+
logger.writeRaw(` [${i + 1}] ${opt.title} (${opt.const})${defMark}\n`);
|
|
235
236
|
});
|
|
236
237
|
const answer = await question(" > ");
|
|
237
238
|
if (!answer && def !== undefined) return def;
|
|
@@ -264,10 +265,10 @@ async function promptMultiSelect(
|
|
|
264
265
|
return undefined;
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
|
|
268
|
+
logger.writeRaw(` ${marker}${label} (select multiple, comma-separated):\n`);
|
|
268
269
|
values.forEach((v, i) => {
|
|
269
270
|
const display = titles ? `${titles[i]} (${v})` : v;
|
|
270
|
-
|
|
271
|
+
logger.writeRaw(` [${i + 1}] ${display}\n`);
|
|
271
272
|
});
|
|
272
273
|
const answer = await question(" > ");
|
|
273
274
|
if (!answer && def !== undefined) return def;
|
|
@@ -324,10 +325,10 @@ async function handleUrlInteractive(params: ElicitRequestURLParams): Promise<Eli
|
|
|
324
325
|
}
|
|
325
326
|
})();
|
|
326
327
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
logger.writeRaw(`\n${ansis.bold("Server requests URL interaction:")}\n`);
|
|
329
|
+
logger.writeRaw(` ${params.message}\n`);
|
|
330
|
+
logger.writeRaw(` ${ansis.yellow("Domain:")} ${domain}\n`);
|
|
331
|
+
logger.writeRaw(` ${ansis.yellow("URL:")} ${params.url}\n`);
|
|
331
332
|
|
|
332
333
|
const answer = await question(` Open in browser? [y/n]: `);
|
|
333
334
|
if (["y", "yes"].includes(answer.toLowerCase())) {
|
package/src/config/loader.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { chmod } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { DEFAULT_CONFIG_DIR, ENV } from "../constants.ts";
|
|
4
|
+
import { logger } from "../output/logger.ts";
|
|
4
5
|
import { interpolateEnv } from "./env.ts";
|
|
5
6
|
import {
|
|
6
7
|
type AuthFile,
|
|
@@ -64,7 +65,7 @@ export async function loadConfig(options: LoadConfigOptions = {}): Promise<Confi
|
|
|
64
65
|
const cwd = process.cwd();
|
|
65
66
|
if (await hasServersFile(cwd)) {
|
|
66
67
|
configDir = cwd;
|
|
67
|
-
|
|
68
|
+
logger.info(`Note: using servers.json from current directory (${cwd})`);
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
|