@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.
- package/package.json +63 -63
- package/src/cli.ts +46 -54
- package/src/client/browser.ts +36 -15
- package/src/client/debug-fetch.ts +64 -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 +103 -103
- 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 +794 -815
- 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 +53 -58
package/src/client/trace.ts
CHANGED
|
@@ -4,13 +4,13 @@ import { cyan, dim, green, red, yellow } from "ansis";
|
|
|
4
4
|
import { logger } from "../output/logger.ts";
|
|
5
5
|
|
|
6
6
|
export interface TraceOptions {
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
json: boolean;
|
|
8
|
+
serverName: string;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
interface PendingRequest {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
method: string;
|
|
13
|
+
sentAt: number;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -19,166 +19,160 @@ interface PendingRequest {
|
|
|
19
19
|
* Uses a Proxy so all other transport properties pass through transparently.
|
|
20
20
|
*/
|
|
21
21
|
export function wrapTransportWithTrace(transport: Transport, options: TraceOptions): Transport {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
22
|
+
const pending = new Map<string | number, PendingRequest>();
|
|
23
|
+
const isTTY = process.stderr.isTTY ?? false;
|
|
24
|
+
|
|
25
|
+
let clientOnMessage: ((message: JSONRPCMessage, extra?: unknown) => void) | undefined;
|
|
26
|
+
|
|
27
|
+
return new Proxy(transport, {
|
|
28
|
+
get(target, prop, receiver) {
|
|
29
|
+
if (prop === "send") {
|
|
30
|
+
return async (message: JSONRPCMessage) => {
|
|
31
|
+
logOutgoing(message, pending, options, isTTY);
|
|
32
|
+
return target.send(message);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (prop === "onmessage") {
|
|
36
|
+
return clientOnMessage;
|
|
37
|
+
}
|
|
38
|
+
return Reflect.get(target, prop, receiver);
|
|
39
|
+
},
|
|
40
|
+
set(target, prop, value) {
|
|
41
|
+
if (prop === "onmessage") {
|
|
42
|
+
clientOnMessage = value;
|
|
43
|
+
target.onmessage = (message: JSONRPCMessage, extra?: unknown) => {
|
|
44
|
+
logIncoming(message, pending, options, isTTY);
|
|
45
|
+
clientOnMessage?.(message, extra);
|
|
46
|
+
};
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return Reflect.set(target, prop, value);
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function logOutgoing(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
message: JSONRPCMessage,
|
|
56
|
+
pending: Map<string | number, PendingRequest>,
|
|
57
|
+
options: TraceOptions,
|
|
58
|
+
isTTY: boolean,
|
|
59
59
|
): void {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
logger.writeRaw(`${arrow} ${dim(m.method)}\n`);
|
|
83
|
-
}
|
|
60
|
+
// Track pending requests for timing (needed in both modes)
|
|
61
|
+
if ("id" in message && "method" in message) {
|
|
62
|
+
const m = message as { id: string | number; method: string };
|
|
63
|
+
pending.set(m.id, { method: m.method, sentAt: performance.now() });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (options.json) {
|
|
67
|
+
logger.writeRaw(`${JSON.stringify({ trace: "outgoing", server: options.serverName, message })}\n`);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if ("id" in message && "method" in message) {
|
|
72
|
+
const m = message as { id: string | number; method: string; params?: unknown };
|
|
73
|
+
const arrow = isTTY ? cyan("→") : "→";
|
|
74
|
+
const detail = summarizeParams(m.method, m.params);
|
|
75
|
+
const detailStr = detail ? ` ${detail}` : "";
|
|
76
|
+
logger.writeRaw(`${arrow} ${dim(`${m.method} (id: ${m.id})${detailStr}`)}\n`);
|
|
77
|
+
} else if ("method" in message) {
|
|
78
|
+
const m = message as { method: string };
|
|
79
|
+
const arrow = isTTY ? cyan("→") : "→";
|
|
80
|
+
logger.writeRaw(`${arrow} ${dim(m.method)}\n`);
|
|
81
|
+
}
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
function logIncoming(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
message: JSONRPCMessage,
|
|
86
|
+
pending: Map<string | number, PendingRequest>,
|
|
87
|
+
options: TraceOptions,
|
|
88
|
+
isTTY: boolean,
|
|
91
89
|
): void {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
logger.writeRaw(`${arrow} ${dim(`${m.method}${params}`)}\n`);
|
|
133
|
-
}
|
|
90
|
+
if ("id" in message && !("method" in message)) {
|
|
91
|
+
// Response to a request
|
|
92
|
+
const m = message as { id: string | number; result?: unknown; error?: unknown };
|
|
93
|
+
const req = pending.get(m.id);
|
|
94
|
+
pending.delete(m.id);
|
|
95
|
+
const elapsed = req ? Math.round(performance.now() - req.sentAt) : undefined;
|
|
96
|
+
const method = req?.method ?? "unknown";
|
|
97
|
+
|
|
98
|
+
if (options.json) {
|
|
99
|
+
logger.writeRaw(
|
|
100
|
+
`${JSON.stringify({
|
|
101
|
+
trace: "incoming",
|
|
102
|
+
server: options.serverName,
|
|
103
|
+
message,
|
|
104
|
+
...(elapsed !== undefined && { elapsed_ms: elapsed }),
|
|
105
|
+
request_method: method,
|
|
106
|
+
})}\n`,
|
|
107
|
+
);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const isError = m.error !== undefined;
|
|
112
|
+
const arrow = isTTY ? (isError ? red("←") : green("←")) : "←";
|
|
113
|
+
const timing = elapsed !== undefined ? ` [${elapsed}ms]` : "";
|
|
114
|
+
const summary = summarizeResult(method, m.result);
|
|
115
|
+
const summaryStr = summary ? ` — ${summary}` : "";
|
|
116
|
+
logger.writeRaw(`${arrow} ${dim(`${method} (id: ${m.id})${timing}${summaryStr}`)}\n`);
|
|
117
|
+
} else if ("method" in message) {
|
|
118
|
+
// Notification (incoming)
|
|
119
|
+
const m = message as { method: string; params?: unknown };
|
|
120
|
+
|
|
121
|
+
if (options.json) {
|
|
122
|
+
logger.writeRaw(`${JSON.stringify({ trace: "incoming", server: options.serverName, message })}\n`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const arrow = isTTY ? yellow("←") : "←";
|
|
127
|
+
const params = m.params ? ` ${JSON.stringify(m.params)}` : "";
|
|
128
|
+
logger.writeRaw(`${arrow} ${dim(`${m.method}${params}`)}\n`);
|
|
129
|
+
}
|
|
134
130
|
}
|
|
135
131
|
|
|
136
132
|
function summarizeParams(method: string, params: unknown): string | undefined {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
133
|
+
if (!params || typeof params !== "object") return undefined;
|
|
134
|
+
const p = params as Record<string, unknown>;
|
|
135
|
+
|
|
136
|
+
switch (method) {
|
|
137
|
+
case "tools/call": {
|
|
138
|
+
const name = p.name as string | undefined;
|
|
139
|
+
const args = p.arguments;
|
|
140
|
+
if (!name) return undefined;
|
|
141
|
+
const argsStr = args ? ` ${JSON.stringify(args)}` : "";
|
|
142
|
+
return `${name}${argsStr}`;
|
|
143
|
+
}
|
|
144
|
+
case "resources/read":
|
|
145
|
+
return p.uri ? String(p.uri) : undefined;
|
|
146
|
+
case "prompts/get":
|
|
147
|
+
return p.name ? String(p.name) : undefined;
|
|
148
|
+
default:
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
155
151
|
}
|
|
156
152
|
|
|
157
153
|
function summarizeResult(method: string, result: unknown): string | undefined {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return "ok";
|
|
183
|
-
}
|
|
154
|
+
if (!result || typeof result !== "object") return undefined;
|
|
155
|
+
const r = result as Record<string, unknown>;
|
|
156
|
+
|
|
157
|
+
switch (method) {
|
|
158
|
+
case "tools/list":
|
|
159
|
+
return Array.isArray(r.tools) ? `${r.tools.length} tools` : undefined;
|
|
160
|
+
case "resources/list":
|
|
161
|
+
return Array.isArray(r.resources) ? `${r.resources.length} resources` : undefined;
|
|
162
|
+
case "resources/templates/list":
|
|
163
|
+
return Array.isArray(r.resourceTemplates) ? `${r.resourceTemplates.length} templates` : undefined;
|
|
164
|
+
case "prompts/list":
|
|
165
|
+
return Array.isArray(r.prompts) ? `${r.prompts.length} prompts` : undefined;
|
|
166
|
+
case "initialize": {
|
|
167
|
+
const info = r.serverInfo as { name?: string; version?: string } | undefined;
|
|
168
|
+
if (info?.name) return info.version ? `${info.name} v${info.version}` : info.name;
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
case "tools/call":
|
|
172
|
+
return r.isError ? "error" : "ok";
|
|
173
|
+
case "ping":
|
|
174
|
+
return "pong";
|
|
175
|
+
default:
|
|
176
|
+
return "ok";
|
|
177
|
+
}
|
|
184
178
|
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
2
|
+
import pkg from "../../package.json";
|
|
2
3
|
import type { HttpServerConfig } from "../config/schemas.ts";
|
|
3
4
|
import { createDebugFetch, type FetchLike } from "./debug-fetch.ts";
|
|
4
|
-
import pkg from "../../package.json";
|
|
5
5
|
|
|
6
6
|
export interface TransportDeps {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
config: HttpServerConfig;
|
|
8
|
+
authProvider?: OAuthClientProvider;
|
|
9
|
+
verbose?: boolean;
|
|
10
|
+
showSecrets?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/** Build shared transport init options (auth, headers, User-Agent, debug fetch) */
|
|
14
14
|
export function buildTransportInit(deps: TransportDeps): {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
authProvider?: OAuthClientProvider;
|
|
16
|
+
requestInit: RequestInit;
|
|
17
|
+
fetch?: FetchLike;
|
|
18
18
|
} {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
19
|
+
const { config, authProvider, verbose = false, showSecrets = false } = deps;
|
|
20
|
+
const userAgent = `${pkg.name}/${pkg.version}`;
|
|
21
|
+
return {
|
|
22
|
+
authProvider,
|
|
23
|
+
requestInit: {
|
|
24
|
+
headers: {
|
|
25
|
+
"User-Agent": userAgent,
|
|
26
|
+
...config.headers,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
fetch: verbose ? createDebugFetch(showSecrets) : undefined,
|
|
30
|
+
};
|
|
31
31
|
}
|