@evantahler/mcpx 0.18.3 → 0.18.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/package.json +63 -63
  2. package/src/cli.ts +46 -54
  3. package/src/client/browser.ts +36 -15
  4. package/src/client/debug-fetch.ts +64 -56
  5. package/src/client/elicitation.ts +279 -291
  6. package/src/client/http.ts +1 -1
  7. package/src/client/manager.ts +481 -514
  8. package/src/client/oauth.ts +272 -282
  9. package/src/client/sse.ts +1 -1
  10. package/src/client/stdio.ts +7 -7
  11. package/src/client/trace.ts +146 -152
  12. package/src/client/transport-options.ts +20 -20
  13. package/src/commands/add.ts +160 -165
  14. package/src/commands/allow.ts +141 -142
  15. package/src/commands/auth.ts +86 -90
  16. package/src/commands/check-update.ts +49 -53
  17. package/src/commands/deny.ts +114 -117
  18. package/src/commands/exec.ts +218 -222
  19. package/src/commands/index.ts +41 -41
  20. package/src/commands/info.ts +48 -50
  21. package/src/commands/list.ts +49 -49
  22. package/src/commands/ping.ts +47 -50
  23. package/src/commands/prompt.ts +40 -50
  24. package/src/commands/remove.ts +54 -56
  25. package/src/commands/resource.ts +31 -36
  26. package/src/commands/search.ts +35 -39
  27. package/src/commands/servers.ts +44 -48
  28. package/src/commands/skill.ts +89 -95
  29. package/src/commands/task.ts +50 -60
  30. package/src/commands/upgrade.ts +191 -208
  31. package/src/commands/with-command.ts +27 -29
  32. package/src/config/env.ts +26 -28
  33. package/src/config/loader.ts +103 -103
  34. package/src/config/schemas.ts +78 -87
  35. package/src/constants.ts +17 -17
  36. package/src/context.ts +51 -51
  37. package/src/lib/client-settings.ts +127 -140
  38. package/src/lib/input.ts +23 -26
  39. package/src/output/format-output.ts +12 -16
  40. package/src/output/format-table.ts +39 -42
  41. package/src/output/formatter.ts +794 -815
  42. package/src/output/logger.ts +140 -152
  43. package/src/sdk.ts +283 -291
  44. package/src/search/index.ts +50 -54
  45. package/src/search/indexer.ts +65 -65
  46. package/src/search/keyword.ts +54 -54
  47. package/src/search/semantic.ts +39 -39
  48. package/src/search/staleness.ts +3 -3
  49. package/src/search/types.ts +4 -4
  50. package/src/update/background.ts +51 -51
  51. package/src/update/cache.ts +21 -21
  52. package/src/update/checker.ts +81 -86
  53. package/src/validation/schema.ts +53 -58
@@ -1,172 +1,160 @@
1
+ import { dim, red, yellow } from "ansis";
1
2
  import { createSpinner } from "nanospinner";
2
- import { dim, yellow, red } from "ansis";
3
3
  import type { FormatOptions } from "./formatter.ts";
4
4
 
5
5
  /** MCP log levels ordered by severity (RFC 5424) */
6
- const LOG_LEVELS = [
7
- "debug",
8
- "info",
9
- "notice",
10
- "warning",
11
- "error",
12
- "critical",
13
- "alert",
14
- "emergency",
15
- ] as const;
6
+ const LOG_LEVELS = ["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"] as const;
16
7
 
17
8
  type LogLevel = (typeof LOG_LEVELS)[number];
18
9
 
19
10
  function logLevelIndex(level: string): number {
20
- const idx = LOG_LEVELS.indexOf(level as LogLevel);
21
- return idx === -1 ? 0 : idx;
11
+ const idx = LOG_LEVELS.indexOf(level as LogLevel);
12
+ return idx === -1 ? 0 : idx;
22
13
  }
23
14
 
24
15
  function colorForLevel(level: string): (s: string) => string {
25
- switch (level) {
26
- case "debug":
27
- return dim;
28
- case "warning":
29
- return yellow;
30
- case "error":
31
- case "critical":
32
- case "alert":
33
- case "emergency":
34
- return red;
35
- default:
36
- return (s: string) => s;
37
- }
16
+ switch (level) {
17
+ case "debug":
18
+ return dim;
19
+ case "warning":
20
+ return yellow;
21
+ case "error":
22
+ case "critical":
23
+ case "alert":
24
+ case "emergency":
25
+ return red;
26
+ default:
27
+ return (s: string) => s;
28
+ }
38
29
  }
39
30
 
40
31
  export interface Spinner {
41
- update(text: string): void;
42
- success(text?: string): void;
43
- error(text?: string): void;
44
- stop(): void;
32
+ update(text: string): void;
33
+ success(text?: string): void;
34
+ error(text?: string): void;
35
+ stop(): void;
45
36
  }
46
37
 
47
38
  class Logger {
48
- private static instance: Logger;
49
- private activeSpinner: ReturnType<typeof createSpinner> | null = null;
50
- private formatOptions: FormatOptions = {};
51
-
52
- private constructor() {}
53
-
54
- static getInstance(): Logger {
55
- if (!Logger.instance) {
56
- Logger.instance = new Logger();
57
- }
58
- return Logger.instance;
59
- }
60
-
61
- /** Set format options (called once during context setup) */
62
- configure(options: FormatOptions): void {
63
- this.formatOptions = options;
64
- }
65
-
66
- /** Whether interactive output is suppressed (JSON mode or non-TTY stderr) */
67
- private isSilent(): boolean {
68
- return !!this.formatOptions.json || !(process.stderr.isTTY ?? false);
69
- }
70
-
71
- /** Write a line to stderr, pausing any active spinner around the write */
72
- private writeStderr(msg: string): void {
73
- if (this.activeSpinner) {
74
- this.activeSpinner.clear();
75
- process.stderr.write(msg + "\n");
76
- this.activeSpinner.render();
77
- } else {
78
- process.stderr.write(msg + "\n");
79
- }
80
- }
81
-
82
- /** Info-level message (dim text on stderr). Suppressed in JSON/non-TTY mode. */
83
- info(msg: string): void {
84
- if (this.isSilent()) return;
85
- this.writeStderr(dim(msg));
86
- }
87
-
88
- /** Warning message (yellow text on stderr). Suppressed in JSON/non-TTY mode. */
89
- warn(msg: string): void {
90
- if (this.isSilent()) return;
91
- this.writeStderr(yellow(msg));
92
- }
93
-
94
- /** Error message (red text on stderr). Always writes. */
95
- error(msg: string): void {
96
- this.writeStderr(red(msg));
97
- }
98
-
99
- /** Debug/verbose message (dim text on stderr). Only when verbose is enabled. */
100
- debug(msg: string): void {
101
- if (!this.formatOptions.verbose || this.isSilent()) return;
102
- this.writeStderr(dim(msg));
103
- }
104
-
105
- /** Write a raw string to stderr. Spinner-aware but no formatting or newline added. */
106
- writeRaw(msg: string): void {
107
- if (this.activeSpinner) {
108
- this.activeSpinner.clear();
109
- process.stderr.write(msg);
110
- this.activeSpinner.render();
111
- } else {
112
- process.stderr.write(msg);
113
- }
114
- }
115
-
116
- /** Display a structured server log message. Suppressed if below configured log level. */
117
- logServerMessage(
118
- serverName: string,
119
- params: { level: string; logger?: string; data: unknown },
120
- ): void {
121
- const minLevel = this.formatOptions.logLevel ?? "warning";
122
- if (logLevelIndex(params.level) < logLevelIndex(minLevel)) return;
123
-
124
- if (this.formatOptions.json) {
125
- // JSON mode: structured object to stderr
126
- const obj = { server: serverName, ...params };
127
- process.stderr.write(JSON.stringify(obj) + "\n");
128
- return;
129
- }
130
-
131
- if (!(process.stderr.isTTY ?? false)) return;
132
-
133
- const prefix = params.logger ? `[${serverName}/${params.logger}]` : `[${serverName}]`;
134
- const dataStr = typeof params.data === "string" ? params.data : JSON.stringify(params.data);
135
- const line = `${prefix} ${params.level}: ${dataStr}`;
136
- const color = colorForLevel(params.level);
137
- this.writeStderr(color(line));
138
- }
139
-
140
- /** Start a spinner. Returns the Spinner interface. */
141
- startSpinner(text: string, options?: FormatOptions): Spinner {
142
- const opts = options ?? this.formatOptions;
143
-
144
- // No spinner in JSON/piped/verbose mode — verbose writeRaw output conflicts with spinner rendering
145
- if (opts.json || opts.verbose || !(process.stderr.isTTY ?? false)) {
146
- return { update() {}, success() {}, error() {}, stop() {} };
147
- }
148
-
149
- const spinner = createSpinner(text, { stream: process.stderr }).start();
150
- this.activeSpinner = spinner;
151
-
152
- return {
153
- update: (text: string) => {
154
- spinner.update({ text });
155
- },
156
- success: (text?: string) => {
157
- spinner.success({ text });
158
- this.activeSpinner = null;
159
- },
160
- error: (text?: string) => {
161
- spinner.error({ text });
162
- this.activeSpinner = null;
163
- },
164
- stop: () => {
165
- spinner.stop();
166
- this.activeSpinner = null;
167
- },
168
- };
169
- }
39
+ private static instance: Logger;
40
+ private activeSpinner: ReturnType<typeof createSpinner> | null = null;
41
+ private formatOptions: FormatOptions = {};
42
+
43
+ private constructor() {}
44
+
45
+ static getInstance(): Logger {
46
+ if (!Logger.instance) {
47
+ Logger.instance = new Logger();
48
+ }
49
+ return Logger.instance;
50
+ }
51
+
52
+ /** Set format options (called once during context setup) */
53
+ configure(options: FormatOptions): void {
54
+ this.formatOptions = options;
55
+ }
56
+
57
+ /** Whether interactive output is suppressed (JSON mode or non-TTY stderr) */
58
+ private isSilent(): boolean {
59
+ return !!this.formatOptions.json || !(process.stderr.isTTY ?? false);
60
+ }
61
+
62
+ /** Write a line to stderr, pausing any active spinner around the write */
63
+ private writeStderr(msg: string): void {
64
+ if (this.activeSpinner) {
65
+ this.activeSpinner.clear();
66
+ process.stderr.write(`${msg}\n`);
67
+ this.activeSpinner.render();
68
+ } else {
69
+ process.stderr.write(`${msg}\n`);
70
+ }
71
+ }
72
+
73
+ /** Info-level message (dim text on stderr). Suppressed in JSON/non-TTY mode. */
74
+ info(msg: string): void {
75
+ if (this.isSilent()) return;
76
+ this.writeStderr(dim(msg));
77
+ }
78
+
79
+ /** Warning message (yellow text on stderr). Suppressed in JSON/non-TTY mode. */
80
+ warn(msg: string): void {
81
+ if (this.isSilent()) return;
82
+ this.writeStderr(yellow(msg));
83
+ }
84
+
85
+ /** Error message (red text on stderr). Always writes. */
86
+ error(msg: string): void {
87
+ this.writeStderr(red(msg));
88
+ }
89
+
90
+ /** Debug/verbose message (dim text on stderr). Only when verbose is enabled. */
91
+ debug(msg: string): void {
92
+ if (!this.formatOptions.verbose || this.isSilent()) return;
93
+ this.writeStderr(dim(msg));
94
+ }
95
+
96
+ /** Write a raw string to stderr. Spinner-aware but no formatting or newline added. */
97
+ writeRaw(msg: string): void {
98
+ if (this.activeSpinner) {
99
+ this.activeSpinner.clear();
100
+ process.stderr.write(msg);
101
+ this.activeSpinner.render();
102
+ } else {
103
+ process.stderr.write(msg);
104
+ }
105
+ }
106
+
107
+ /** Display a structured server log message. Suppressed if below configured log level. */
108
+ logServerMessage(serverName: string, params: { level: string; logger?: string; data: unknown }): void {
109
+ const minLevel = this.formatOptions.logLevel ?? "warning";
110
+ if (logLevelIndex(params.level) < logLevelIndex(minLevel)) return;
111
+
112
+ if (this.formatOptions.json) {
113
+ // JSON mode: structured object to stderr
114
+ const obj = { server: serverName, ...params };
115
+ process.stderr.write(`${JSON.stringify(obj)}\n`);
116
+ return;
117
+ }
118
+
119
+ if (!(process.stderr.isTTY ?? false)) return;
120
+
121
+ const prefix = params.logger ? `[${serverName}/${params.logger}]` : `[${serverName}]`;
122
+ const dataStr = typeof params.data === "string" ? params.data : JSON.stringify(params.data);
123
+ const line = `${prefix} ${params.level}: ${dataStr}`;
124
+ const color = colorForLevel(params.level);
125
+ this.writeStderr(color(line));
126
+ }
127
+
128
+ /** Start a spinner. Returns the Spinner interface. */
129
+ startSpinner(text: string, options?: FormatOptions): Spinner {
130
+ const opts = options ?? this.formatOptions;
131
+
132
+ // No spinner in JSON/piped/verbose mode — verbose writeRaw output conflicts with spinner rendering
133
+ if (opts.json || opts.verbose || !(process.stderr.isTTY ?? false)) {
134
+ return { update() {}, success() {}, error() {}, stop() {} };
135
+ }
136
+
137
+ const spinner = createSpinner(text, { stream: process.stderr }).start();
138
+ this.activeSpinner = spinner;
139
+
140
+ return {
141
+ update: (text: string) => {
142
+ spinner.update({ text });
143
+ },
144
+ success: (text?: string) => {
145
+ spinner.success({ text });
146
+ this.activeSpinner = null;
147
+ },
148
+ error: (text?: string) => {
149
+ spinner.error({ text });
150
+ this.activeSpinner = null;
151
+ },
152
+ stop: () => {
153
+ spinner.stop();
154
+ this.activeSpinner = null;
155
+ },
156
+ };
157
+ }
170
158
  }
171
159
 
172
160
  /** The singleton logger instance */