@mcpjam/inspector 1.0.0 → 1.0.2
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/README.md +16 -55
- package/dist/client/assets/index-D5Niv-PI.css +1 -0
- package/dist/client/assets/index-DfX8IFHm.js +1874 -0
- package/dist/client/demo_1.png +0 -0
- package/dist/client/demo_2.png +0 -0
- package/dist/client/demo_3.png +0 -0
- package/dist/client/demo_4.png +0 -0
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +378 -56
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/index-BQ-ekSd_.js +0 -1874
- package/dist/client/assets/index-BZlC0Ubf.css +0 -1
package/dist/client/demo_1.png
CHANGED
|
Binary file
|
package/dist/client/demo_2.png
CHANGED
|
Binary file
|
package/dist/client/demo_3.png
CHANGED
|
Binary file
|
|
Binary file
|
package/dist/client/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/mcp_jam.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>MCPJam Inspector</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DfX8IFHm.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-D5Niv-PI.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/dist/server/index.js
CHANGED
|
@@ -272,6 +272,8 @@ tools.post("/list", async (c) => {
|
|
|
272
272
|
}
|
|
273
273
|
});
|
|
274
274
|
tools.post("/execute", async (c) => {
|
|
275
|
+
const mcp2 = c.mcpJamClientManager;
|
|
276
|
+
let state = null;
|
|
275
277
|
try {
|
|
276
278
|
const { serverId, toolName, parameters } = await c.req.json();
|
|
277
279
|
if (!serverId) return c.json({ error: "serverId is required" }, 400);
|
|
@@ -279,19 +281,22 @@ tools.post("/execute", async (c) => {
|
|
|
279
281
|
if (activeExecution) {
|
|
280
282
|
return c.json({ error: "Another execution is already in progress" }, 409);
|
|
281
283
|
}
|
|
282
|
-
const mcp2 = c.mcpJamClientManager;
|
|
283
284
|
const status = mcp2.getConnectionStatus(serverId);
|
|
284
285
|
if (status !== "connected") {
|
|
285
286
|
return c.json({ error: `Server '${serverId}' is not connected` }, 400);
|
|
286
287
|
}
|
|
287
288
|
const executionId = `exec_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
288
|
-
const
|
|
289
|
+
const execPromise = Promise.resolve().then(
|
|
290
|
+
() => mcp2.executeToolDirect(`${serverId}:${toolName}`, parameters || {})
|
|
291
|
+
).catch((error) => {
|
|
292
|
+
if (state) state.error = error;
|
|
293
|
+
throw error;
|
|
294
|
+
});
|
|
295
|
+
state = {
|
|
289
296
|
id: executionId,
|
|
290
297
|
serverId,
|
|
291
298
|
toolName,
|
|
292
|
-
execPromise
|
|
293
|
-
() => mcp2.executeToolDirect(toolName, parameters || {})
|
|
294
|
-
),
|
|
299
|
+
execPromise,
|
|
295
300
|
completed: false,
|
|
296
301
|
queue: [],
|
|
297
302
|
waiters: []
|
|
@@ -342,10 +347,7 @@ tools.post("/execute", async (c) => {
|
|
|
342
347
|
state.result = race.res;
|
|
343
348
|
activeExecution = null;
|
|
344
349
|
mcp2.clearElicitationCallback();
|
|
345
|
-
return c.json(
|
|
346
|
-
{ status: "completed", toolName, result: race.res.result },
|
|
347
|
-
200
|
|
348
|
-
);
|
|
350
|
+
return c.json({ status: "completed", toolName, result: race.res }, 200);
|
|
349
351
|
}
|
|
350
352
|
return c.json(
|
|
351
353
|
{
|
|
@@ -360,20 +362,27 @@ tools.post("/execute", async (c) => {
|
|
|
360
362
|
202
|
|
361
363
|
);
|
|
362
364
|
} catch (err) {
|
|
365
|
+
if (state && activeExecution === state) {
|
|
366
|
+
state.error = state.error ?? err;
|
|
367
|
+
state.waiters.length = 0;
|
|
368
|
+
state.queue.length = 0;
|
|
369
|
+
activeExecution = null;
|
|
370
|
+
mcp2.clearElicitationCallback();
|
|
371
|
+
}
|
|
363
372
|
const msg = err instanceof Error ? err.message : String(err);
|
|
364
373
|
return c.json({ error: msg }, 500);
|
|
365
374
|
}
|
|
366
375
|
});
|
|
367
376
|
tools.post("/respond", async (c) => {
|
|
377
|
+
const mcp2 = c.mcpJamClientManager;
|
|
378
|
+
const state = activeExecution;
|
|
368
379
|
try {
|
|
369
380
|
const { requestId, response } = await c.req.json();
|
|
370
381
|
if (!requestId) return c.json({ error: "requestId is required" }, 400);
|
|
371
|
-
if (!
|
|
372
|
-
const mcp2 = c.mcpJamClientManager;
|
|
382
|
+
if (!state) return c.json({ error: "No active execution" }, 404);
|
|
373
383
|
const ok = mcp2.respondToElicitation(requestId, response);
|
|
374
384
|
if (!ok)
|
|
375
385
|
return c.json({ error: "No pending elicitation for requestId" }, 404);
|
|
376
|
-
const state = activeExecution;
|
|
377
386
|
try {
|
|
378
387
|
const race = await Promise.race([
|
|
379
388
|
state.execPromise.then((res) => ({ kind: "done", res })),
|
|
@@ -390,7 +399,7 @@ tools.post("/respond", async (c) => {
|
|
|
390
399
|
{
|
|
391
400
|
status: "completed",
|
|
392
401
|
toolName: state.toolName,
|
|
393
|
-
result: race.res
|
|
402
|
+
result: race.res
|
|
394
403
|
},
|
|
395
404
|
200
|
|
396
405
|
);
|
|
@@ -408,10 +417,24 @@ tools.post("/respond", async (c) => {
|
|
|
408
417
|
202
|
|
409
418
|
);
|
|
410
419
|
} catch (e) {
|
|
420
|
+
state.error = state.error ?? e;
|
|
421
|
+
state.waiters.length = 0;
|
|
422
|
+
state.queue.length = 0;
|
|
423
|
+
if (activeExecution === state) {
|
|
424
|
+
activeExecution = null;
|
|
425
|
+
mcp2.clearElicitationCallback();
|
|
426
|
+
}
|
|
411
427
|
const msg = e instanceof Error ? e.message : String(e);
|
|
412
428
|
return c.json({ error: msg }, 500);
|
|
413
429
|
}
|
|
414
430
|
} catch (err) {
|
|
431
|
+
if (state && activeExecution === state) {
|
|
432
|
+
state.error = state.error ?? err;
|
|
433
|
+
state.waiters.length = 0;
|
|
434
|
+
state.queue.length = 0;
|
|
435
|
+
activeExecution = null;
|
|
436
|
+
mcp2.clearElicitationCallback();
|
|
437
|
+
}
|
|
415
438
|
const msg = err instanceof Error ? err.message : String(err);
|
|
416
439
|
return c.json({ error: msg }, 500);
|
|
417
440
|
}
|
|
@@ -478,6 +501,269 @@ resources.post("/read", async (c) => {
|
|
|
478
501
|
);
|
|
479
502
|
}
|
|
480
503
|
});
|
|
504
|
+
resources.get("/widget/:sessionId", async (c) => {
|
|
505
|
+
const sessionId = c.req.param("sessionId");
|
|
506
|
+
const widgetData = c.req.query("data");
|
|
507
|
+
if (!widgetData) {
|
|
508
|
+
return c.html("<html><body>Error: Missing widget data</body></html>", 400);
|
|
509
|
+
}
|
|
510
|
+
return c.html(`
|
|
511
|
+
<!DOCTYPE html>
|
|
512
|
+
<html>
|
|
513
|
+
<head>
|
|
514
|
+
<meta charset="utf-8">
|
|
515
|
+
<title>Loading Widget...</title>
|
|
516
|
+
</head>
|
|
517
|
+
<body>
|
|
518
|
+
<script>
|
|
519
|
+
(async function() {
|
|
520
|
+
// Change URL to "/" BEFORE loading widget (for React Router)
|
|
521
|
+
history.replaceState(null, '', '/');
|
|
522
|
+
|
|
523
|
+
// Fetch the actual widget HTML
|
|
524
|
+
const response = await fetch('/api/mcp/resources/widget-content?data=${encodeURIComponent(widgetData)}');
|
|
525
|
+
const html = await response.text();
|
|
526
|
+
|
|
527
|
+
// Replace entire document with widget HTML
|
|
528
|
+
document.open();
|
|
529
|
+
document.write(html);
|
|
530
|
+
document.close();
|
|
531
|
+
})();
|
|
532
|
+
</script>
|
|
533
|
+
</body>
|
|
534
|
+
</html>
|
|
535
|
+
`);
|
|
536
|
+
});
|
|
537
|
+
resources.get("/widget-content", async (c) => {
|
|
538
|
+
try {
|
|
539
|
+
const widgetData = c.req.query("data");
|
|
540
|
+
if (!widgetData) {
|
|
541
|
+
return c.html(
|
|
542
|
+
"<html><body>Error: Missing widget data</body></html>",
|
|
543
|
+
400
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
const { serverId, uri, toolInput, toolOutput, toolId } = JSON.parse(
|
|
547
|
+
Buffer.from(widgetData, "base64").toString()
|
|
548
|
+
);
|
|
549
|
+
const mcpClientManager = c.mcpJamClientManager;
|
|
550
|
+
const connectedServers = mcpClientManager.getConnectedServers();
|
|
551
|
+
let actualServerId = serverId;
|
|
552
|
+
if (!connectedServers[serverId]) {
|
|
553
|
+
const serverNames = Object.keys(connectedServers);
|
|
554
|
+
const match = serverNames.find(
|
|
555
|
+
(name) => name.toLowerCase() === serverId.toLowerCase()
|
|
556
|
+
);
|
|
557
|
+
if (match) {
|
|
558
|
+
actualServerId = match;
|
|
559
|
+
} else {
|
|
560
|
+
return c.html(
|
|
561
|
+
`<html><body>
|
|
562
|
+
<h3>Error: Server not connected</h3>
|
|
563
|
+
<p>Requested server: ${serverId}</p>
|
|
564
|
+
<p>Available servers: ${serverNames.join(", ")}</p>
|
|
565
|
+
</body></html>`,
|
|
566
|
+
404
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const content = await mcpClientManager.getResource(uri, actualServerId);
|
|
571
|
+
let htmlContent = "";
|
|
572
|
+
if (Array.isArray(content)) {
|
|
573
|
+
htmlContent = content[0]?.text || content[0]?.blob || "";
|
|
574
|
+
} else if (content && typeof content === "object") {
|
|
575
|
+
htmlContent = content.text || content.blob || "";
|
|
576
|
+
if (!htmlContent && Array.isArray(content.contents)) {
|
|
577
|
+
htmlContent = content.contents[0]?.text || content.contents[0]?.blob || "";
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (!htmlContent) {
|
|
581
|
+
return c.html(
|
|
582
|
+
"<html><body>Error: No HTML content found</body></html>",
|
|
583
|
+
404
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
const widgetStateKey = `openai-widget-state:${toolId}`;
|
|
587
|
+
const apiScript = `
|
|
588
|
+
<script>
|
|
589
|
+
(function() {
|
|
590
|
+
'use strict';
|
|
591
|
+
|
|
592
|
+
const openaiAPI = {
|
|
593
|
+
toolInput: ${JSON.stringify(toolInput)},
|
|
594
|
+
toolOutput: ${JSON.stringify(toolOutput)},
|
|
595
|
+
displayMode: 'inline',
|
|
596
|
+
maxHeight: 600,
|
|
597
|
+
theme: 'dark',
|
|
598
|
+
locale: 'en-US',
|
|
599
|
+
safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
600
|
+
userAgent: {},
|
|
601
|
+
widgetState: null,
|
|
602
|
+
|
|
603
|
+
async setWidgetState(state) {
|
|
604
|
+
this.widgetState = state;
|
|
605
|
+
try {
|
|
606
|
+
localStorage.setItem(${JSON.stringify(widgetStateKey)}, JSON.stringify(state));
|
|
607
|
+
} catch (err) {
|
|
608
|
+
console.error('[OpenAI Widget] Failed to save widget state:', err);
|
|
609
|
+
}
|
|
610
|
+
window.parent.postMessage({
|
|
611
|
+
type: 'openai:setWidgetState',
|
|
612
|
+
toolId: ${JSON.stringify(toolId)},
|
|
613
|
+
state
|
|
614
|
+
}, '*');
|
|
615
|
+
},
|
|
616
|
+
|
|
617
|
+
async callTool(toolName, params = {}) {
|
|
618
|
+
return new Promise((resolve, reject) => {
|
|
619
|
+
const requestId = \`tool_\${Date.now()}_\${Math.random()}\`;
|
|
620
|
+
const handler = (event) => {
|
|
621
|
+
if (event.data.type === 'openai:callTool:response' &&
|
|
622
|
+
event.data.requestId === requestId) {
|
|
623
|
+
window.removeEventListener('message', handler);
|
|
624
|
+
if (event.data.error) {
|
|
625
|
+
reject(new Error(event.data.error));
|
|
626
|
+
} else {
|
|
627
|
+
resolve(event.data.result);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
window.addEventListener('message', handler);
|
|
632
|
+
window.parent.postMessage({
|
|
633
|
+
type: 'openai:callTool',
|
|
634
|
+
requestId,
|
|
635
|
+
toolName,
|
|
636
|
+
params
|
|
637
|
+
}, '*');
|
|
638
|
+
setTimeout(() => {
|
|
639
|
+
window.removeEventListener('message', handler);
|
|
640
|
+
reject(new Error('Tool call timeout'));
|
|
641
|
+
}, 30000);
|
|
642
|
+
});
|
|
643
|
+
},
|
|
644
|
+
|
|
645
|
+
async sendFollowupTurn(message) {
|
|
646
|
+
const payload = typeof message === 'string'
|
|
647
|
+
? { prompt: message }
|
|
648
|
+
: message;
|
|
649
|
+
window.parent.postMessage({
|
|
650
|
+
type: 'openai:sendFollowup',
|
|
651
|
+
message: payload.prompt || payload
|
|
652
|
+
}, '*');
|
|
653
|
+
},
|
|
654
|
+
|
|
655
|
+
async requestDisplayMode(options = {}) {
|
|
656
|
+
const mode = options.mode || 'inline';
|
|
657
|
+
this.displayMode = mode;
|
|
658
|
+
window.parent.postMessage({
|
|
659
|
+
type: 'openai:requestDisplayMode',
|
|
660
|
+
mode
|
|
661
|
+
}, '*');
|
|
662
|
+
return { mode };
|
|
663
|
+
},
|
|
664
|
+
|
|
665
|
+
async sendFollowUpMessage(args) {
|
|
666
|
+
const prompt = typeof args === 'string' ? args : (args?.prompt || '');
|
|
667
|
+
return this.sendFollowupTurn(prompt);
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
Object.defineProperty(window, 'openai', {
|
|
672
|
+
value: openaiAPI,
|
|
673
|
+
writable: false,
|
|
674
|
+
configurable: false,
|
|
675
|
+
enumerable: true
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
Object.defineProperty(window, 'webplus', {
|
|
679
|
+
value: openaiAPI,
|
|
680
|
+
writable: false,
|
|
681
|
+
configurable: false,
|
|
682
|
+
enumerable: true
|
|
683
|
+
});
|
|
684
|
+
|
|
685
|
+
setTimeout(() => {
|
|
686
|
+
try {
|
|
687
|
+
const globalsEvent = new CustomEvent('webplus:set_globals', {
|
|
688
|
+
detail: {
|
|
689
|
+
globals: {
|
|
690
|
+
displayMode: openaiAPI.displayMode,
|
|
691
|
+
maxHeight: openaiAPI.maxHeight,
|
|
692
|
+
theme: openaiAPI.theme,
|
|
693
|
+
locale: openaiAPI.locale,
|
|
694
|
+
safeArea: openaiAPI.safeArea,
|
|
695
|
+
userAgent: openaiAPI.userAgent
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
window.dispatchEvent(globalsEvent);
|
|
700
|
+
} catch (err) {}
|
|
701
|
+
}, 0);
|
|
702
|
+
|
|
703
|
+
setTimeout(() => {
|
|
704
|
+
try {
|
|
705
|
+
const stored = localStorage.getItem(${JSON.stringify(widgetStateKey)});
|
|
706
|
+
if (stored && window.openai) {
|
|
707
|
+
window.openai.widgetState = JSON.parse(stored);
|
|
708
|
+
}
|
|
709
|
+
} catch (err) {}
|
|
710
|
+
}, 0);
|
|
711
|
+
})();
|
|
712
|
+
</script>
|
|
713
|
+
`;
|
|
714
|
+
let modifiedHtml;
|
|
715
|
+
if (htmlContent.includes("<html>") && htmlContent.includes("<head>")) {
|
|
716
|
+
modifiedHtml = htmlContent.replace(
|
|
717
|
+
"<head>",
|
|
718
|
+
`<head><base href="/">${apiScript}`
|
|
719
|
+
);
|
|
720
|
+
} else {
|
|
721
|
+
modifiedHtml = `<!DOCTYPE html>
|
|
722
|
+
<html>
|
|
723
|
+
<head>
|
|
724
|
+
<base href="/">
|
|
725
|
+
<meta charset="UTF-8">
|
|
726
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
727
|
+
${apiScript}
|
|
728
|
+
</head>
|
|
729
|
+
<body>
|
|
730
|
+
${htmlContent}
|
|
731
|
+
</body>
|
|
732
|
+
</html>`;
|
|
733
|
+
}
|
|
734
|
+
const trustedCdns = [
|
|
735
|
+
"https://persistent.oaistatic.com",
|
|
736
|
+
"https://*.oaistatic.com",
|
|
737
|
+
"https://unpkg.com",
|
|
738
|
+
"https://cdn.jsdelivr.net",
|
|
739
|
+
"https://cdnjs.cloudflare.com",
|
|
740
|
+
"https://cdn.skypack.dev"
|
|
741
|
+
].join(" ");
|
|
742
|
+
c.header(
|
|
743
|
+
"Content-Security-Policy",
|
|
744
|
+
[
|
|
745
|
+
"default-src 'self'",
|
|
746
|
+
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${trustedCdns}`,
|
|
747
|
+
"worker-src 'self' blob:",
|
|
748
|
+
"child-src 'self' blob:",
|
|
749
|
+
`style-src 'self' 'unsafe-inline' ${trustedCdns}`,
|
|
750
|
+
"img-src 'self' data: https: blob:",
|
|
751
|
+
"media-src 'self' data: https: blob:",
|
|
752
|
+
`font-src 'self' data: ${trustedCdns}`,
|
|
753
|
+
"connect-src 'self' https: wss: ws:",
|
|
754
|
+
"frame-ancestors 'self'"
|
|
755
|
+
].join("; ")
|
|
756
|
+
);
|
|
757
|
+
c.header("X-Frame-Options", "SAMEORIGIN");
|
|
758
|
+
c.header("X-Content-Type-Options", "nosniff");
|
|
759
|
+
return c.html(modifiedHtml);
|
|
760
|
+
} catch (error) {
|
|
761
|
+
return c.html(
|
|
762
|
+
`<html><body>Error: ${error instanceof Error ? error.message : "Unknown error"}</body></html>`,
|
|
763
|
+
500
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
});
|
|
481
767
|
var resources_default = resources;
|
|
482
768
|
|
|
483
769
|
// routes/mcp/prompts.ts
|
|
@@ -752,11 +1038,16 @@ function convertMastraToolsToVercelTools(mastraTools) {
|
|
|
752
1038
|
}
|
|
753
1039
|
|
|
754
1040
|
// ../shared/http-tool-calls.ts
|
|
755
|
-
function
|
|
1041
|
+
function flattenToolsetsWithServerId(toolsets) {
|
|
756
1042
|
const flattened = {};
|
|
757
|
-
for (const serverTools of Object.
|
|
1043
|
+
for (const [serverId, serverTools] of Object.entries(toolsets || {})) {
|
|
758
1044
|
if (serverTools && typeof serverTools === "object") {
|
|
759
|
-
Object.
|
|
1045
|
+
for (const [toolName, tool2] of Object.entries(serverTools)) {
|
|
1046
|
+
flattened[toolName] = {
|
|
1047
|
+
...tool2,
|
|
1048
|
+
_serverId: serverId
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
760
1051
|
}
|
|
761
1052
|
}
|
|
762
1053
|
return flattened;
|
|
@@ -794,13 +1085,18 @@ async function executeToolCallsFromMessages(messages, options) {
|
|
|
794
1085
|
let tools2 = {};
|
|
795
1086
|
if (options.client) {
|
|
796
1087
|
const toolsets = await options.client.getToolsets();
|
|
797
|
-
tools2 =
|
|
1088
|
+
tools2 = flattenToolsetsWithServerId(toolsets);
|
|
798
1089
|
} else if (options.toolsets) {
|
|
799
|
-
|
|
1090
|
+
const toolsets = options.toolsets;
|
|
1091
|
+
tools2 = flattenToolsetsWithServerId(toolsets);
|
|
800
1092
|
} else {
|
|
801
1093
|
tools2 = options.tools;
|
|
802
1094
|
}
|
|
803
1095
|
const index = buildIndexWithAliases(tools2);
|
|
1096
|
+
const extractServerId = (toolName) => {
|
|
1097
|
+
const tool2 = index[toolName];
|
|
1098
|
+
return tool2?._serverId;
|
|
1099
|
+
};
|
|
804
1100
|
const existingToolResultIds = /* @__PURE__ */ new Set();
|
|
805
1101
|
for (const msg of messages) {
|
|
806
1102
|
if (!msg || msg.role !== "tool" || !Array.isArray(msg.content))
|
|
@@ -837,6 +1133,7 @@ async function executeToolCallsFromMessages(messages, options) {
|
|
|
837
1133
|
} else {
|
|
838
1134
|
output = { type: "text", value: String(result) };
|
|
839
1135
|
}
|
|
1136
|
+
const serverId = extractServerId(toolName);
|
|
840
1137
|
const toolResultMessage = {
|
|
841
1138
|
role: "tool",
|
|
842
1139
|
content: [
|
|
@@ -844,7 +1141,11 @@ async function executeToolCallsFromMessages(messages, options) {
|
|
|
844
1141
|
type: "tool-result",
|
|
845
1142
|
toolCallId: content.toolCallId,
|
|
846
1143
|
toolName,
|
|
847
|
-
output
|
|
1144
|
+
output,
|
|
1145
|
+
// Preserve full result including _meta for OpenAI Apps SDK
|
|
1146
|
+
result,
|
|
1147
|
+
// Add serverId for OpenAI component resolution
|
|
1148
|
+
serverId
|
|
848
1149
|
}
|
|
849
1150
|
]
|
|
850
1151
|
};
|
|
@@ -927,11 +1228,15 @@ var runBackendConversation = async (options) => {
|
|
|
927
1228
|
if (msg.role === "tool" && Array.isArray(content)) {
|
|
928
1229
|
for (const item of content) {
|
|
929
1230
|
if (item?.type === "tool-result") {
|
|
1231
|
+
const fullResult = item.result;
|
|
930
1232
|
const rawOutput = item.output ?? item.result ?? item.value ?? item.data ?? item.content;
|
|
931
1233
|
const resultEvent = {
|
|
932
1234
|
toolName: item.toolName ?? item.name,
|
|
933
|
-
result
|
|
934
|
-
|
|
1235
|
+
// Use full result if available, otherwise extract value from output
|
|
1236
|
+
result: fullResult ?? extractToolResultValue(rawOutput),
|
|
1237
|
+
error: item.error,
|
|
1238
|
+
// Preserve serverId if present
|
|
1239
|
+
serverId: item.serverId
|
|
935
1240
|
};
|
|
936
1241
|
iterationToolResults.push(resultEvent);
|
|
937
1242
|
handlers?.onToolResult?.(resultEvent);
|
|
@@ -1042,7 +1347,8 @@ var handleAgentStepFinish = (streamingContext, text, toolCalls, toolResults, emi
|
|
|
1042
1347
|
toolResult: {
|
|
1043
1348
|
id: currentToolCallId,
|
|
1044
1349
|
toolCallId: currentToolCallId,
|
|
1045
|
-
result
|
|
1350
|
+
// Preserve full result which may include _meta for OpenAI Apps SDK
|
|
1351
|
+
result: result.result || result,
|
|
1046
1352
|
error: result.error,
|
|
1047
1353
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1048
1354
|
}
|
|
@@ -1219,14 +1525,17 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1219
1525
|
return { role: "user", content: m.content };
|
|
1220
1526
|
}
|
|
1221
1527
|
});
|
|
1222
|
-
const
|
|
1223
|
-
|
|
1224
|
-
)
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1528
|
+
const toolsets = await mcpClientManager.getToolsetsWithServerIds(selectedServers);
|
|
1529
|
+
const toolDefs = [];
|
|
1530
|
+
for (const serverTools of Object.values(toolsets)) {
|
|
1531
|
+
for (const [name, tool2] of Object.entries(serverTools)) {
|
|
1532
|
+
toolDefs.push({
|
|
1533
|
+
name,
|
|
1534
|
+
description: tool2?.description,
|
|
1535
|
+
inputSchema: zodToJsonSchema3(tool2?.inputSchema)
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1230
1539
|
if (!baseUrl) {
|
|
1231
1540
|
throw new Error("CONVEX_HTTP_URL is not set");
|
|
1232
1541
|
}
|
|
@@ -1253,7 +1562,9 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1253
1562
|
toolCallId: currentToolCallId,
|
|
1254
1563
|
result: result.result,
|
|
1255
1564
|
error: result.error,
|
|
1256
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1565
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1566
|
+
serverId: result.serverId
|
|
1567
|
+
// Propagate serverId
|
|
1257
1568
|
}
|
|
1258
1569
|
});
|
|
1259
1570
|
};
|
|
@@ -1277,7 +1588,7 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1277
1588
|
},
|
|
1278
1589
|
executeToolCalls: async (messages2) => {
|
|
1279
1590
|
await executeToolCallsFromMessages(messages2, {
|
|
1280
|
-
|
|
1591
|
+
toolsets
|
|
1281
1592
|
});
|
|
1282
1593
|
},
|
|
1283
1594
|
handlers: {
|
|
@@ -1299,7 +1610,7 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1299
1610
|
text,
|
|
1300
1611
|
toolCalls,
|
|
1301
1612
|
toolResults.map((result) => ({
|
|
1302
|
-
result: result.result,
|
|
1613
|
+
result: result.result || result,
|
|
1303
1614
|
error: result.error
|
|
1304
1615
|
})),
|
|
1305
1616
|
false
|
|
@@ -9421,6 +9732,15 @@ var MCPJamClientManager = class {
|
|
|
9421
9732
|
getServerIdForName(serverName) {
|
|
9422
9733
|
return this.serverIdMapping.get(serverName);
|
|
9423
9734
|
}
|
|
9735
|
+
// Reverse lookup: get server name from internal server ID
|
|
9736
|
+
getServerNameForId(serverId) {
|
|
9737
|
+
for (const [name, id] of this.serverIdMapping.entries()) {
|
|
9738
|
+
if (id === serverId) {
|
|
9739
|
+
return name;
|
|
9740
|
+
}
|
|
9741
|
+
}
|
|
9742
|
+
return void 0;
|
|
9743
|
+
}
|
|
9424
9744
|
flattenToolsets(toolsets) {
|
|
9425
9745
|
const flattenedTools = {};
|
|
9426
9746
|
Object.values(toolsets).forEach((serverTools) => {
|
|
@@ -9428,6 +9748,26 @@ var MCPJamClientManager = class {
|
|
|
9428
9748
|
});
|
|
9429
9749
|
return flattenedTools;
|
|
9430
9750
|
}
|
|
9751
|
+
async getToolsetsWithServerIds(serverNameFilter) {
|
|
9752
|
+
const toolsetsByServer = {};
|
|
9753
|
+
const allServerIdsFromFilter = serverNameFilter?.map(
|
|
9754
|
+
(serverName) => this.getServerIdForName(serverName)
|
|
9755
|
+
);
|
|
9756
|
+
for (const [serverId, client] of this.mcpClients.entries()) {
|
|
9757
|
+
if (serverNameFilter && !allServerIdsFromFilter?.includes(serverId))
|
|
9758
|
+
continue;
|
|
9759
|
+
if (this.getConnectionStatus(serverId) !== "connected") continue;
|
|
9760
|
+
try {
|
|
9761
|
+
const toolsets = await client.getToolsets();
|
|
9762
|
+
const flattenedTools = this.flattenToolsets(toolsets);
|
|
9763
|
+
const serverName = this.getServerNameForId(serverId) || serverId;
|
|
9764
|
+
toolsetsByServer[serverName] = flattenedTools;
|
|
9765
|
+
} catch (error) {
|
|
9766
|
+
console.warn(`Failed to get tools from server ${serverId}:`, error);
|
|
9767
|
+
}
|
|
9768
|
+
}
|
|
9769
|
+
return toolsetsByServer;
|
|
9770
|
+
}
|
|
9431
9771
|
async getFlattenedToolsetsForEnabledServers(serverNameFilter) {
|
|
9432
9772
|
const allFlattenedTools = {};
|
|
9433
9773
|
const allServerIdsFromFilter = serverNameFilter?.map(
|
|
@@ -9663,30 +10003,12 @@ var MCPJamClientManager = class {
|
|
|
9663
10003
|
const tool2 = flattenedTools[name];
|
|
9664
10004
|
if (!tool2)
|
|
9665
10005
|
throw new Error(`Tool '${name}' not found in server '${serverId}'`);
|
|
9666
|
-
const
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
);
|
|
9671
|
-
const requiresContext = hasContextProperty || schema && Array.isArray(schema.required) && schema.required.includes("context");
|
|
9672
|
-
const contextWrapped = { context: parameters || {} };
|
|
9673
|
-
const direct = parameters || {};
|
|
9674
|
-
const attempts = requiresContext ? [contextWrapped, direct] : [direct, contextWrapped];
|
|
9675
|
-
let lastError = void 0;
|
|
9676
|
-
for (const args of attempts) {
|
|
9677
|
-
try {
|
|
9678
|
-
console.log("args", args);
|
|
9679
|
-
const result = await tool2.execute(args);
|
|
9680
|
-
if (result && result.isError) {
|
|
9681
|
-
const errorText = result.content && result.content[0] && result.content[0].text ? result.content[0].text : "Unknown error";
|
|
9682
|
-
throw new Error(errorText);
|
|
9683
|
-
}
|
|
9684
|
-
return { result };
|
|
9685
|
-
} catch (err) {
|
|
9686
|
-
lastError = err;
|
|
9687
|
-
}
|
|
10006
|
+
const result = await tool2.execute({ context: parameters || {} });
|
|
10007
|
+
if (result && result.isError) {
|
|
10008
|
+
const errorText = result.content && result.content[0] && result.content[0].text ? result.content[0].text : "Unknown error";
|
|
10009
|
+
throw new Error(errorText);
|
|
9688
10010
|
}
|
|
9689
|
-
|
|
10011
|
+
return { result };
|
|
9690
10012
|
}
|
|
9691
10013
|
async getResource(resourceUri, serverId) {
|
|
9692
10014
|
let uri = resourceUri;
|