@mcpjam/inspector 0.2.3 → 0.3.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/cli/build/cli.js +25 -3
- package/client/bin/start.js +28 -4
- package/client/dist/assets/{OAuthCallback-CfsBsNUt.js → OAuthCallback-CdxuZKBm.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-DuorYCq_.js → OAuthDebugCallback-BJaIMNT8.js} +1 -1
- package/client/dist/assets/{index-CHsLKjnG.js → index-CdlQwnmd.js} +2715 -780
- package/client/dist/assets/{index-C5Ywrn22.css → index-De3JSks9.css} +165 -0
- package/client/dist/index.html +2 -2
- package/package.json +2 -1
- package/server/build/index.js +85 -72
package/server/build/index.js
CHANGED
|
@@ -36,9 +36,9 @@ app.use((req, res, next) => {
|
|
|
36
36
|
next();
|
|
37
37
|
});
|
|
38
38
|
const webAppTransports = new Map(); // Transports by sessionId
|
|
39
|
+
const backingServerTransports = new Map();
|
|
39
40
|
const createTransport = async (req) => {
|
|
40
41
|
const query = req.query;
|
|
41
|
-
console.log("Query parameters:", query);
|
|
42
42
|
const transportType = query.transportType;
|
|
43
43
|
if (transportType === "stdio") {
|
|
44
44
|
const command = query.command;
|
|
@@ -46,7 +46,7 @@ const createTransport = async (req) => {
|
|
|
46
46
|
const queryEnv = query.env ? JSON.parse(query.env) : {};
|
|
47
47
|
const env = { ...process.env, ...defaultEnvironment, ...queryEnv };
|
|
48
48
|
const { cmd, args } = findActualExecutable(command, origArgs);
|
|
49
|
-
console.log(
|
|
49
|
+
console.log(`🚀 Stdio transport: command=${cmd}, args=${args}`);
|
|
50
50
|
const transport = new StdioClientTransport({
|
|
51
51
|
command: cmd,
|
|
52
52
|
args,
|
|
@@ -54,7 +54,6 @@ const createTransport = async (req) => {
|
|
|
54
54
|
stderr: "pipe",
|
|
55
55
|
});
|
|
56
56
|
await transport.start();
|
|
57
|
-
console.log("Spawned stdio transport");
|
|
58
57
|
return transport;
|
|
59
58
|
}
|
|
60
59
|
else if (transportType === "sse") {
|
|
@@ -69,7 +68,6 @@ const createTransport = async (req) => {
|
|
|
69
68
|
const value = req.headers[key];
|
|
70
69
|
headers[key] = Array.isArray(value) ? value[value.length - 1] : value;
|
|
71
70
|
}
|
|
72
|
-
console.log(`SSE transport: url=${url}, headers=${Object.keys(headers)}`);
|
|
73
71
|
const transport = new SSEClientTransport(new URL(url), {
|
|
74
72
|
eventSourceInit: {
|
|
75
73
|
fetch: (url, init) => fetch(url, { ...init, headers }),
|
|
@@ -79,7 +77,6 @@ const createTransport = async (req) => {
|
|
|
79
77
|
},
|
|
80
78
|
});
|
|
81
79
|
await transport.start();
|
|
82
|
-
console.log("Connected to SSE transport");
|
|
83
80
|
return transport;
|
|
84
81
|
}
|
|
85
82
|
else if (transportType === "streamable-http") {
|
|
@@ -99,18 +96,16 @@ const createTransport = async (req) => {
|
|
|
99
96
|
},
|
|
100
97
|
});
|
|
101
98
|
await transport.start();
|
|
102
|
-
console.log("Connected to Streamable HTTP transport");
|
|
103
99
|
return transport;
|
|
104
100
|
}
|
|
105
101
|
else {
|
|
106
|
-
console.error(
|
|
102
|
+
console.error(`❌ Invalid transport type: ${transportType}`);
|
|
107
103
|
throw new Error("Invalid transport type specified");
|
|
108
104
|
}
|
|
109
105
|
};
|
|
110
|
-
let backingServerTransport;
|
|
111
106
|
app.get("/mcp", async (req, res) => {
|
|
112
107
|
const sessionId = req.headers["mcp-session-id"];
|
|
113
|
-
console.log(
|
|
108
|
+
console.log(`📥 Received GET message for sessionId ${sessionId}`);
|
|
114
109
|
try {
|
|
115
110
|
const transport = webAppTransports.get(sessionId);
|
|
116
111
|
if (!transport) {
|
|
@@ -122,45 +117,51 @@ app.get("/mcp", async (req, res) => {
|
|
|
122
117
|
}
|
|
123
118
|
}
|
|
124
119
|
catch (error) {
|
|
125
|
-
console.error("Error in /mcp route:", error);
|
|
120
|
+
console.error("❌ Error in /mcp route:", error);
|
|
126
121
|
res.status(500).json(error);
|
|
127
122
|
}
|
|
128
123
|
});
|
|
129
124
|
app.post("/mcp", async (req, res) => {
|
|
130
125
|
const sessionId = req.headers["mcp-session-id"];
|
|
131
|
-
console.log(
|
|
126
|
+
console.log(`📥 Received POST message for sessionId ${sessionId}`);
|
|
132
127
|
if (!sessionId) {
|
|
133
128
|
try {
|
|
134
|
-
console.log("New streamable-http connection");
|
|
129
|
+
console.log("🔄 New streamable-http connection");
|
|
130
|
+
let backingServerTransport;
|
|
135
131
|
try {
|
|
136
|
-
await backingServerTransport?.close();
|
|
137
132
|
backingServerTransport = await createTransport(req);
|
|
138
133
|
}
|
|
139
134
|
catch (error) {
|
|
140
135
|
if (error instanceof SseError && error.code === 401) {
|
|
141
|
-
console.error("Received 401 Unauthorized from MCP server:", error.message);
|
|
136
|
+
console.error("🔒 Received 401 Unauthorized from MCP server:", error.message);
|
|
142
137
|
res.status(401).json(error);
|
|
143
138
|
return;
|
|
144
139
|
}
|
|
145
140
|
throw error;
|
|
146
141
|
}
|
|
147
|
-
console.log("Connected MCP client to backing server transport");
|
|
148
142
|
const webAppTransport = new StreamableHTTPServerTransport({
|
|
149
143
|
sessionIdGenerator: randomUUID,
|
|
150
|
-
onsessioninitialized: (
|
|
151
|
-
|
|
152
|
-
|
|
144
|
+
onsessioninitialized: (newSessionId) => {
|
|
145
|
+
console.log("✨ Created streamable web app transport " + newSessionId);
|
|
146
|
+
webAppTransports.set(newSessionId, webAppTransport);
|
|
147
|
+
backingServerTransports.set(newSessionId, backingServerTransport);
|
|
148
|
+
console.log(`✨ Connected MCP client to backing server transport for session ${newSessionId}`);
|
|
149
|
+
mcpProxy({
|
|
150
|
+
transportToClient: webAppTransport,
|
|
151
|
+
transportToServer: backingServerTransport,
|
|
152
|
+
});
|
|
153
|
+
webAppTransport.onclose = () => {
|
|
154
|
+
console.log(`🧹 Cleaning up transports for session ${newSessionId}`);
|
|
155
|
+
webAppTransports.delete(newSessionId);
|
|
156
|
+
backingServerTransports.delete(newSessionId);
|
|
157
|
+
};
|
|
153
158
|
},
|
|
154
159
|
});
|
|
155
160
|
await webAppTransport.start();
|
|
156
|
-
mcpProxy({
|
|
157
|
-
transportToClient: webAppTransport,
|
|
158
|
-
transportToServer: backingServerTransport,
|
|
159
|
-
});
|
|
160
161
|
await webAppTransport.handleRequest(req, res, req.body);
|
|
161
162
|
}
|
|
162
163
|
catch (error) {
|
|
163
|
-
console.error("Error in /mcp POST route:", error);
|
|
164
|
+
console.error("❌ Error in /mcp POST route:", error);
|
|
164
165
|
res.status(500).json(error);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
@@ -175,86 +176,96 @@ app.post("/mcp", async (req, res) => {
|
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
catch (error) {
|
|
178
|
-
console.error("Error in /mcp route:", error);
|
|
179
|
+
console.error("❌ Error in /mcp route:", error);
|
|
179
180
|
res.status(500).json(error);
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
});
|
|
183
184
|
app.get("/stdio", async (req, res) => {
|
|
184
185
|
try {
|
|
185
|
-
console.log("New connection");
|
|
186
|
+
console.log("🔄 New stdio/sse connection");
|
|
187
|
+
const webAppTransport = new SSEServerTransport("/message", res);
|
|
188
|
+
const sessionId = webAppTransport.sessionId;
|
|
189
|
+
webAppTransports.set(sessionId, webAppTransport);
|
|
186
190
|
try {
|
|
187
|
-
await
|
|
188
|
-
backingServerTransport
|
|
191
|
+
const backingServerTransport = await createTransport(req);
|
|
192
|
+
backingServerTransports.set(sessionId, backingServerTransport);
|
|
193
|
+
webAppTransport.onclose = () => {
|
|
194
|
+
console.log(`🧹 Cleaning up transports for session ${sessionId}`);
|
|
195
|
+
webAppTransports.delete(sessionId);
|
|
196
|
+
backingServerTransports.delete(sessionId);
|
|
197
|
+
};
|
|
198
|
+
await webAppTransport.start();
|
|
199
|
+
if (backingServerTransport instanceof StdioClientTransport) {
|
|
200
|
+
backingServerTransport.stderr.on("data", (chunk) => {
|
|
201
|
+
webAppTransport.send({
|
|
202
|
+
jsonrpc: "2.0",
|
|
203
|
+
method: "stderr",
|
|
204
|
+
params: {
|
|
205
|
+
data: chunk.toString(),
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
mcpProxy({
|
|
211
|
+
transportToClient: webAppTransport,
|
|
212
|
+
transportToServer: backingServerTransport,
|
|
213
|
+
});
|
|
214
|
+
console.log(`✨ Connected MCP client to backing server transport for session ${sessionId}`);
|
|
189
215
|
}
|
|
190
216
|
catch (error) {
|
|
191
217
|
if (error instanceof SseError && error.code === 401) {
|
|
192
|
-
console.error("Received 401 Unauthorized from MCP server:", error.message);
|
|
218
|
+
console.error("🔒 Received 401 Unauthorized from MCP server:", error.message);
|
|
193
219
|
res.status(401).json(error);
|
|
194
220
|
return;
|
|
195
221
|
}
|
|
196
222
|
throw error;
|
|
197
223
|
}
|
|
198
|
-
console.log("Connected MCP client to backing server transport");
|
|
199
|
-
const webAppTransport = new SSEServerTransport("/message", res);
|
|
200
|
-
webAppTransports.set(webAppTransport.sessionId, webAppTransport);
|
|
201
|
-
console.log("Created web app transport");
|
|
202
|
-
await webAppTransport.start();
|
|
203
|
-
backingServerTransport.stderr.on("data", (chunk) => {
|
|
204
|
-
webAppTransport.send({
|
|
205
|
-
jsonrpc: "2.0",
|
|
206
|
-
method: "notifications/stderr",
|
|
207
|
-
params: {
|
|
208
|
-
content: chunk.toString(),
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
mcpProxy({
|
|
213
|
-
transportToClient: webAppTransport,
|
|
214
|
-
transportToServer: backingServerTransport,
|
|
215
|
-
});
|
|
216
|
-
console.log("Set up MCP proxy");
|
|
217
224
|
}
|
|
218
225
|
catch (error) {
|
|
219
|
-
console.error("Error in /stdio route:", error);
|
|
220
|
-
|
|
226
|
+
console.error("❌ Error in /stdio route:", error);
|
|
227
|
+
// Can't send a 500 response if headers already sent (which they are for SSE)
|
|
221
228
|
}
|
|
222
229
|
});
|
|
223
230
|
app.get("/sse", async (req, res) => {
|
|
224
231
|
try {
|
|
225
|
-
console.log("New
|
|
232
|
+
console.log("🔄 New sse connection");
|
|
233
|
+
const webAppTransport = new SSEServerTransport("/message", res);
|
|
234
|
+
const sessionId = webAppTransport.sessionId;
|
|
235
|
+
webAppTransports.set(sessionId, webAppTransport);
|
|
226
236
|
try {
|
|
227
|
-
await
|
|
228
|
-
backingServerTransport
|
|
237
|
+
const backingServerTransport = await createTransport(req);
|
|
238
|
+
backingServerTransports.set(sessionId, backingServerTransport);
|
|
239
|
+
webAppTransport.onclose = () => {
|
|
240
|
+
console.log(`🧹 Cleaning up transports for session ${sessionId}`);
|
|
241
|
+
webAppTransports.delete(sessionId);
|
|
242
|
+
backingServerTransports.delete(sessionId);
|
|
243
|
+
};
|
|
244
|
+
await webAppTransport.start();
|
|
245
|
+
mcpProxy({
|
|
246
|
+
transportToClient: webAppTransport,
|
|
247
|
+
transportToServer: backingServerTransport,
|
|
248
|
+
});
|
|
249
|
+
console.log(`✨ Connected MCP client to backing server transport for session ${sessionId}`);
|
|
229
250
|
}
|
|
230
251
|
catch (error) {
|
|
231
252
|
if (error instanceof SseError && error.code === 401) {
|
|
232
|
-
console.error("Received 401 Unauthorized from MCP server:", error.message);
|
|
253
|
+
console.error("🔒 Received 401 Unauthorized from MCP server:", error.message);
|
|
233
254
|
res.status(401).json(error);
|
|
234
255
|
return;
|
|
235
256
|
}
|
|
236
257
|
throw error;
|
|
237
258
|
}
|
|
238
|
-
console.log("Connected MCP client to backing server transport");
|
|
239
|
-
const webAppTransport = new SSEServerTransport("/message", res);
|
|
240
|
-
webAppTransports.set(webAppTransport.sessionId, webAppTransport);
|
|
241
|
-
console.log("Created web app transport");
|
|
242
|
-
await webAppTransport.start();
|
|
243
|
-
mcpProxy({
|
|
244
|
-
transportToClient: webAppTransport,
|
|
245
|
-
transportToServer: backingServerTransport,
|
|
246
|
-
});
|
|
247
|
-
console.log("Set up MCP proxy");
|
|
248
259
|
}
|
|
249
260
|
catch (error) {
|
|
250
|
-
console.error("Error in /sse route:", error);
|
|
251
|
-
|
|
261
|
+
console.error("❌ Error in /sse route:", error);
|
|
262
|
+
// Can't send a 500 response if headers already sent (which they are for SSE)
|
|
252
263
|
}
|
|
253
264
|
});
|
|
254
265
|
app.post("/message", async (req, res) => {
|
|
255
266
|
try {
|
|
256
267
|
const sessionId = req.query.sessionId;
|
|
257
|
-
console.log(
|
|
268
|
+
console.log(`📥 Received message for sessionId ${sessionId}`);
|
|
258
269
|
const transport = webAppTransports.get(sessionId);
|
|
259
270
|
if (!transport) {
|
|
260
271
|
res.status(404).end("Session not found");
|
|
@@ -263,7 +274,7 @@ app.post("/message", async (req, res) => {
|
|
|
263
274
|
await transport.handlePostMessage(req, res);
|
|
264
275
|
}
|
|
265
276
|
catch (error) {
|
|
266
|
-
console.error("Error in /message route:", error);
|
|
277
|
+
console.error("❌ Error in /message route:", error);
|
|
267
278
|
res.status(500).json(error);
|
|
268
279
|
}
|
|
269
280
|
});
|
|
@@ -281,7 +292,7 @@ app.get("/config", (req, res) => {
|
|
|
281
292
|
});
|
|
282
293
|
}
|
|
283
294
|
catch (error) {
|
|
284
|
-
console.error("Error in /config route:", error);
|
|
295
|
+
console.error("❌ Error in /config route:", error);
|
|
285
296
|
res.status(500).json(error);
|
|
286
297
|
}
|
|
287
298
|
});
|
|
@@ -295,10 +306,12 @@ const findAvailablePort = async (startPort) => {
|
|
|
295
306
|
resolve(port);
|
|
296
307
|
});
|
|
297
308
|
});
|
|
298
|
-
server.on(
|
|
299
|
-
if (err.code ===
|
|
309
|
+
server.on("error", (err) => {
|
|
310
|
+
if (err.code === "EADDRINUSE") {
|
|
300
311
|
// Port is in use, try the next one
|
|
301
|
-
findAvailablePort(startPort + 1)
|
|
312
|
+
findAvailablePort(startPort + 1)
|
|
313
|
+
.then(resolve)
|
|
314
|
+
.catch(reject);
|
|
302
315
|
}
|
|
303
316
|
else {
|
|
304
317
|
reject(err);
|
|
@@ -316,7 +329,7 @@ const startServer = async () => {
|
|
|
316
329
|
if (availablePort !== Number(PORT)) {
|
|
317
330
|
console.log(`⚠️ Port ${PORT} was in use, using available port ${availablePort} instead`);
|
|
318
331
|
}
|
|
319
|
-
console.log(`⚙️ Proxy server listening on port ${availablePort}`);
|
|
332
|
+
console.log(`\x1b[32m%s\x1b[0m`, `⚙️ Proxy server listening on port ${availablePort}`);
|
|
320
333
|
});
|
|
321
334
|
server.on("error", (err) => {
|
|
322
335
|
console.error(`❌ Server error: ${err.message}`);
|