@mcpjam/inspector 1.0.1 → 1.0.3
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 +28 -8
- package/dist/client/apps_sdk_pizza.png +0 -0
- package/dist/client/assets/index-BtfU0Trt.js +1874 -0
- package/dist/client/assets/index-D5Niv-PI.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +385 -57
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/index-BZlC0Ubf.css +0 -1
- package/dist/client/assets/index-Dn41SYnl.js +0 -1874
package/dist/server/index.js
CHANGED
|
@@ -286,7 +286,9 @@ tools.post("/execute", async (c) => {
|
|
|
286
286
|
return c.json({ error: `Server '${serverId}' is not connected` }, 400);
|
|
287
287
|
}
|
|
288
288
|
const executionId = `exec_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
289
|
-
const execPromise = Promise.resolve().then(
|
|
289
|
+
const execPromise = Promise.resolve().then(
|
|
290
|
+
() => mcp2.executeToolDirect(`${serverId}:${toolName}`, parameters || {})
|
|
291
|
+
).catch((error) => {
|
|
290
292
|
if (state) state.error = error;
|
|
291
293
|
throw error;
|
|
292
294
|
});
|
|
@@ -345,10 +347,7 @@ tools.post("/execute", async (c) => {
|
|
|
345
347
|
state.result = race.res;
|
|
346
348
|
activeExecution = null;
|
|
347
349
|
mcp2.clearElicitationCallback();
|
|
348
|
-
return c.json(
|
|
349
|
-
{ status: "completed", toolName, result: race.res.result },
|
|
350
|
-
200
|
|
351
|
-
);
|
|
350
|
+
return c.json({ status: "completed", toolName, result: race.res }, 200);
|
|
352
351
|
}
|
|
353
352
|
return c.json(
|
|
354
353
|
{
|
|
@@ -400,7 +399,7 @@ tools.post("/respond", async (c) => {
|
|
|
400
399
|
{
|
|
401
400
|
status: "completed",
|
|
402
401
|
toolName: state.toolName,
|
|
403
|
-
result: race.res
|
|
402
|
+
result: race.res
|
|
404
403
|
},
|
|
405
404
|
200
|
|
406
405
|
);
|
|
@@ -502,6 +501,270 @@ resources.post("/read", async (c) => {
|
|
|
502
501
|
);
|
|
503
502
|
}
|
|
504
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 base64Decoded = Buffer.from(widgetData, "base64").toString("binary");
|
|
547
|
+
const percentEncoded = base64Decoded.split("").map((c2) => "%" + ("00" + c2.charCodeAt(0).toString(16)).slice(-2)).join("");
|
|
548
|
+
const jsonString = decodeURIComponent(percentEncoded);
|
|
549
|
+
const { serverId, uri, toolInput, toolOutput, toolId } = JSON.parse(jsonString);
|
|
550
|
+
const mcpClientManager = c.mcpJamClientManager;
|
|
551
|
+
const connectedServers = mcpClientManager.getConnectedServers();
|
|
552
|
+
let actualServerId = serverId;
|
|
553
|
+
if (!connectedServers[serverId]) {
|
|
554
|
+
const serverNames = Object.keys(connectedServers);
|
|
555
|
+
const match = serverNames.find(
|
|
556
|
+
(name) => name.toLowerCase() === serverId.toLowerCase()
|
|
557
|
+
);
|
|
558
|
+
if (match) {
|
|
559
|
+
actualServerId = match;
|
|
560
|
+
} else {
|
|
561
|
+
return c.html(
|
|
562
|
+
`<html><body>
|
|
563
|
+
<h3>Error: Server not connected</h3>
|
|
564
|
+
<p>Requested server: ${serverId}</p>
|
|
565
|
+
<p>Available servers: ${serverNames.join(", ")}</p>
|
|
566
|
+
</body></html>`,
|
|
567
|
+
404
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const content = await mcpClientManager.getResource(uri, actualServerId);
|
|
572
|
+
let htmlContent = "";
|
|
573
|
+
if (Array.isArray(content)) {
|
|
574
|
+
htmlContent = content[0]?.text || content[0]?.blob || "";
|
|
575
|
+
} else if (content && typeof content === "object") {
|
|
576
|
+
htmlContent = content.text || content.blob || "";
|
|
577
|
+
if (!htmlContent && Array.isArray(content.contents)) {
|
|
578
|
+
htmlContent = content.contents[0]?.text || content.contents[0]?.blob || "";
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
if (!htmlContent) {
|
|
582
|
+
return c.html(
|
|
583
|
+
"<html><body>Error: No HTML content found</body></html>",
|
|
584
|
+
404
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
const widgetStateKey = `openai-widget-state:${toolId}`;
|
|
588
|
+
const apiScript = `
|
|
589
|
+
<script>
|
|
590
|
+
(function() {
|
|
591
|
+
'use strict';
|
|
592
|
+
|
|
593
|
+
const openaiAPI = {
|
|
594
|
+
toolInput: ${JSON.stringify(toolInput)},
|
|
595
|
+
toolOutput: ${JSON.stringify(toolOutput)},
|
|
596
|
+
displayMode: 'inline',
|
|
597
|
+
maxHeight: 600,
|
|
598
|
+
theme: 'dark',
|
|
599
|
+
locale: 'en-US',
|
|
600
|
+
safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
601
|
+
userAgent: {},
|
|
602
|
+
widgetState: null,
|
|
603
|
+
|
|
604
|
+
async setWidgetState(state) {
|
|
605
|
+
this.widgetState = state;
|
|
606
|
+
try {
|
|
607
|
+
localStorage.setItem(${JSON.stringify(widgetStateKey)}, JSON.stringify(state));
|
|
608
|
+
} catch (err) {
|
|
609
|
+
console.error('[OpenAI Widget] Failed to save widget state:', err);
|
|
610
|
+
}
|
|
611
|
+
window.parent.postMessage({
|
|
612
|
+
type: 'openai:setWidgetState',
|
|
613
|
+
toolId: ${JSON.stringify(toolId)},
|
|
614
|
+
state
|
|
615
|
+
}, '*');
|
|
616
|
+
},
|
|
617
|
+
|
|
618
|
+
async callTool(toolName, params = {}) {
|
|
619
|
+
return new Promise((resolve, reject) => {
|
|
620
|
+
const requestId = \`tool_\${Date.now()}_\${Math.random()}\`;
|
|
621
|
+
const handler = (event) => {
|
|
622
|
+
if (event.data.type === 'openai:callTool:response' &&
|
|
623
|
+
event.data.requestId === requestId) {
|
|
624
|
+
window.removeEventListener('message', handler);
|
|
625
|
+
if (event.data.error) {
|
|
626
|
+
reject(new Error(event.data.error));
|
|
627
|
+
} else {
|
|
628
|
+
resolve(event.data.result);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
window.addEventListener('message', handler);
|
|
633
|
+
window.parent.postMessage({
|
|
634
|
+
type: 'openai:callTool',
|
|
635
|
+
requestId,
|
|
636
|
+
toolName,
|
|
637
|
+
params
|
|
638
|
+
}, '*');
|
|
639
|
+
setTimeout(() => {
|
|
640
|
+
window.removeEventListener('message', handler);
|
|
641
|
+
reject(new Error('Tool call timeout'));
|
|
642
|
+
}, 30000);
|
|
643
|
+
});
|
|
644
|
+
},
|
|
645
|
+
|
|
646
|
+
async sendFollowupTurn(message) {
|
|
647
|
+
const payload = typeof message === 'string'
|
|
648
|
+
? { prompt: message }
|
|
649
|
+
: message;
|
|
650
|
+
window.parent.postMessage({
|
|
651
|
+
type: 'openai:sendFollowup',
|
|
652
|
+
message: payload.prompt || payload
|
|
653
|
+
}, '*');
|
|
654
|
+
},
|
|
655
|
+
|
|
656
|
+
async requestDisplayMode(options = {}) {
|
|
657
|
+
const mode = options.mode || 'inline';
|
|
658
|
+
this.displayMode = mode;
|
|
659
|
+
window.parent.postMessage({
|
|
660
|
+
type: 'openai:requestDisplayMode',
|
|
661
|
+
mode
|
|
662
|
+
}, '*');
|
|
663
|
+
return { mode };
|
|
664
|
+
},
|
|
665
|
+
|
|
666
|
+
async sendFollowUpMessage(args) {
|
|
667
|
+
const prompt = typeof args === 'string' ? args : (args?.prompt || '');
|
|
668
|
+
return this.sendFollowupTurn(prompt);
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
Object.defineProperty(window, 'openai', {
|
|
673
|
+
value: openaiAPI,
|
|
674
|
+
writable: false,
|
|
675
|
+
configurable: false,
|
|
676
|
+
enumerable: true
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
Object.defineProperty(window, 'webplus', {
|
|
680
|
+
value: openaiAPI,
|
|
681
|
+
writable: false,
|
|
682
|
+
configurable: false,
|
|
683
|
+
enumerable: true
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
setTimeout(() => {
|
|
687
|
+
try {
|
|
688
|
+
const globalsEvent = new CustomEvent('webplus:set_globals', {
|
|
689
|
+
detail: {
|
|
690
|
+
globals: {
|
|
691
|
+
displayMode: openaiAPI.displayMode,
|
|
692
|
+
maxHeight: openaiAPI.maxHeight,
|
|
693
|
+
theme: openaiAPI.theme,
|
|
694
|
+
locale: openaiAPI.locale,
|
|
695
|
+
safeArea: openaiAPI.safeArea,
|
|
696
|
+
userAgent: openaiAPI.userAgent
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
window.dispatchEvent(globalsEvent);
|
|
701
|
+
} catch (err) {}
|
|
702
|
+
}, 0);
|
|
703
|
+
|
|
704
|
+
setTimeout(() => {
|
|
705
|
+
try {
|
|
706
|
+
const stored = localStorage.getItem(${JSON.stringify(widgetStateKey)});
|
|
707
|
+
if (stored && window.openai) {
|
|
708
|
+
window.openai.widgetState = JSON.parse(stored);
|
|
709
|
+
}
|
|
710
|
+
} catch (err) {}
|
|
711
|
+
}, 0);
|
|
712
|
+
})();
|
|
713
|
+
</script>
|
|
714
|
+
`;
|
|
715
|
+
let modifiedHtml;
|
|
716
|
+
if (htmlContent.includes("<html>") && htmlContent.includes("<head>")) {
|
|
717
|
+
modifiedHtml = htmlContent.replace(
|
|
718
|
+
"<head>",
|
|
719
|
+
`<head><base href="/">${apiScript}`
|
|
720
|
+
);
|
|
721
|
+
} else {
|
|
722
|
+
modifiedHtml = `<!DOCTYPE html>
|
|
723
|
+
<html>
|
|
724
|
+
<head>
|
|
725
|
+
<base href="/">
|
|
726
|
+
<meta charset="UTF-8">
|
|
727
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
728
|
+
${apiScript}
|
|
729
|
+
</head>
|
|
730
|
+
<body>
|
|
731
|
+
${htmlContent}
|
|
732
|
+
</body>
|
|
733
|
+
</html>`;
|
|
734
|
+
}
|
|
735
|
+
const trustedCdns = [
|
|
736
|
+
"https://persistent.oaistatic.com",
|
|
737
|
+
"https://*.oaistatic.com",
|
|
738
|
+
"https://unpkg.com",
|
|
739
|
+
"https://cdn.jsdelivr.net",
|
|
740
|
+
"https://cdnjs.cloudflare.com",
|
|
741
|
+
"https://cdn.skypack.dev"
|
|
742
|
+
].join(" ");
|
|
743
|
+
c.header(
|
|
744
|
+
"Content-Security-Policy",
|
|
745
|
+
[
|
|
746
|
+
"default-src 'self'",
|
|
747
|
+
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${trustedCdns}`,
|
|
748
|
+
"worker-src 'self' blob:",
|
|
749
|
+
"child-src 'self' blob:",
|
|
750
|
+
`style-src 'self' 'unsafe-inline' ${trustedCdns}`,
|
|
751
|
+
"img-src 'self' data: https: blob:",
|
|
752
|
+
"media-src 'self' data: https: blob:",
|
|
753
|
+
`font-src 'self' data: ${trustedCdns}`,
|
|
754
|
+
"connect-src 'self' https: wss: ws:",
|
|
755
|
+
"frame-ancestors 'self'"
|
|
756
|
+
].join("; ")
|
|
757
|
+
);
|
|
758
|
+
c.header("X-Frame-Options", "SAMEORIGIN");
|
|
759
|
+
c.header("X-Content-Type-Options", "nosniff");
|
|
760
|
+
return c.html(modifiedHtml);
|
|
761
|
+
} catch (error) {
|
|
762
|
+
return c.html(
|
|
763
|
+
`<html><body>Error: ${error instanceof Error ? error.message : "Unknown error"}</body></html>`,
|
|
764
|
+
500
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
505
768
|
var resources_default = resources;
|
|
506
769
|
|
|
507
770
|
// routes/mcp/prompts.ts
|
|
@@ -776,11 +1039,16 @@ function convertMastraToolsToVercelTools(mastraTools) {
|
|
|
776
1039
|
}
|
|
777
1040
|
|
|
778
1041
|
// ../shared/http-tool-calls.ts
|
|
779
|
-
function
|
|
1042
|
+
function flattenToolsetsWithServerId(toolsets) {
|
|
780
1043
|
const flattened = {};
|
|
781
|
-
for (const serverTools of Object.
|
|
1044
|
+
for (const [serverId, serverTools] of Object.entries(toolsets || {})) {
|
|
782
1045
|
if (serverTools && typeof serverTools === "object") {
|
|
783
|
-
Object.
|
|
1046
|
+
for (const [toolName, tool2] of Object.entries(serverTools)) {
|
|
1047
|
+
flattened[toolName] = {
|
|
1048
|
+
...tool2,
|
|
1049
|
+
_serverId: serverId
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
784
1052
|
}
|
|
785
1053
|
}
|
|
786
1054
|
return flattened;
|
|
@@ -818,13 +1086,18 @@ async function executeToolCallsFromMessages(messages, options) {
|
|
|
818
1086
|
let tools2 = {};
|
|
819
1087
|
if (options.client) {
|
|
820
1088
|
const toolsets = await options.client.getToolsets();
|
|
821
|
-
tools2 =
|
|
1089
|
+
tools2 = flattenToolsetsWithServerId(toolsets);
|
|
822
1090
|
} else if (options.toolsets) {
|
|
823
|
-
|
|
1091
|
+
const toolsets = options.toolsets;
|
|
1092
|
+
tools2 = flattenToolsetsWithServerId(toolsets);
|
|
824
1093
|
} else {
|
|
825
1094
|
tools2 = options.tools;
|
|
826
1095
|
}
|
|
827
1096
|
const index = buildIndexWithAliases(tools2);
|
|
1097
|
+
const extractServerId = (toolName) => {
|
|
1098
|
+
const tool2 = index[toolName];
|
|
1099
|
+
return tool2?._serverId;
|
|
1100
|
+
};
|
|
828
1101
|
const existingToolResultIds = /* @__PURE__ */ new Set();
|
|
829
1102
|
for (const msg of messages) {
|
|
830
1103
|
if (!msg || msg.role !== "tool" || !Array.isArray(msg.content))
|
|
@@ -861,6 +1134,7 @@ async function executeToolCallsFromMessages(messages, options) {
|
|
|
861
1134
|
} else {
|
|
862
1135
|
output = { type: "text", value: String(result) };
|
|
863
1136
|
}
|
|
1137
|
+
const serverId = extractServerId(toolName);
|
|
864
1138
|
const toolResultMessage = {
|
|
865
1139
|
role: "tool",
|
|
866
1140
|
content: [
|
|
@@ -868,7 +1142,11 @@ async function executeToolCallsFromMessages(messages, options) {
|
|
|
868
1142
|
type: "tool-result",
|
|
869
1143
|
toolCallId: content.toolCallId,
|
|
870
1144
|
toolName,
|
|
871
|
-
output
|
|
1145
|
+
output,
|
|
1146
|
+
// Preserve full result including _meta for OpenAI Apps SDK
|
|
1147
|
+
result,
|
|
1148
|
+
// Add serverId for OpenAI component resolution
|
|
1149
|
+
serverId
|
|
872
1150
|
}
|
|
873
1151
|
]
|
|
874
1152
|
};
|
|
@@ -951,11 +1229,15 @@ var runBackendConversation = async (options) => {
|
|
|
951
1229
|
if (msg.role === "tool" && Array.isArray(content)) {
|
|
952
1230
|
for (const item of content) {
|
|
953
1231
|
if (item?.type === "tool-result") {
|
|
1232
|
+
const fullResult = item.result;
|
|
954
1233
|
const rawOutput = item.output ?? item.result ?? item.value ?? item.data ?? item.content;
|
|
955
1234
|
const resultEvent = {
|
|
956
1235
|
toolName: item.toolName ?? item.name,
|
|
957
|
-
result
|
|
958
|
-
|
|
1236
|
+
// Use full result if available, otherwise extract value from output
|
|
1237
|
+
result: fullResult ?? extractToolResultValue(rawOutput),
|
|
1238
|
+
error: item.error,
|
|
1239
|
+
// Preserve serverId if present
|
|
1240
|
+
serverId: item.serverId
|
|
959
1241
|
};
|
|
960
1242
|
iterationToolResults.push(resultEvent);
|
|
961
1243
|
handlers?.onToolResult?.(resultEvent);
|
|
@@ -1036,6 +1318,8 @@ var handleAgentStepFinish = (streamingContext, text, toolCalls, toolResults, emi
|
|
|
1036
1318
|
for (const call of toolCalls) {
|
|
1037
1319
|
const currentToolCallId = ++streamingContext.toolCallId;
|
|
1038
1320
|
streamingContext.lastEmittedToolCallId = currentToolCallId;
|
|
1321
|
+
const toolName = call.name || call.toolName;
|
|
1322
|
+
streamingContext.toolCallIdToName.set(currentToolCallId, toolName);
|
|
1039
1323
|
if (streamingContext.controller && streamingContext.encoder) {
|
|
1040
1324
|
sendSseEvent(
|
|
1041
1325
|
streamingContext.controller,
|
|
@@ -1044,7 +1328,7 @@ var handleAgentStepFinish = (streamingContext, text, toolCalls, toolResults, emi
|
|
|
1044
1328
|
type: "tool_call",
|
|
1045
1329
|
toolCall: {
|
|
1046
1330
|
id: currentToolCallId,
|
|
1047
|
-
name:
|
|
1331
|
+
name: toolName,
|
|
1048
1332
|
parameters: call.params || call.args || {},
|
|
1049
1333
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1050
1334
|
status: "executing"
|
|
@@ -1066,7 +1350,8 @@ var handleAgentStepFinish = (streamingContext, text, toolCalls, toolResults, emi
|
|
|
1066
1350
|
toolResult: {
|
|
1067
1351
|
id: currentToolCallId,
|
|
1068
1352
|
toolCallId: currentToolCallId,
|
|
1069
|
-
result
|
|
1353
|
+
// Preserve full result which may include _meta for OpenAI Apps SDK
|
|
1354
|
+
result: result.result || result,
|
|
1070
1355
|
error: result.error,
|
|
1071
1356
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1072
1357
|
}
|
|
@@ -1096,7 +1381,11 @@ var handleAgentStepFinish = (streamingContext, text, toolCalls, toolResults, emi
|
|
|
1096
1381
|
} catch {
|
|
1097
1382
|
}
|
|
1098
1383
|
};
|
|
1099
|
-
var createStreamingResponse = async (model, aiSdkTools, messages, streamingContext, provider, temperature, systemPrompt) => {
|
|
1384
|
+
var createStreamingResponse = async (model, aiSdkTools, messages, streamingContext, provider, toolsWithServerId, temperature, systemPrompt) => {
|
|
1385
|
+
const extractServerId = (toolName) => {
|
|
1386
|
+
const tool2 = toolsWithServerId[toolName];
|
|
1387
|
+
return tool2?._serverId;
|
|
1388
|
+
};
|
|
1100
1389
|
const messageHistory = (messages || []).map((m) => {
|
|
1101
1390
|
switch (m.role) {
|
|
1102
1391
|
case "system":
|
|
@@ -1146,6 +1435,7 @@ var createStreamingResponse = async (model, aiSdkTools, messages, streamingConte
|
|
|
1146
1435
|
streamingContext.lastEmittedToolCallId = currentToolCallId;
|
|
1147
1436
|
const name = chunk.chunk.toolName || chunk.chunk.name;
|
|
1148
1437
|
const parameters = chunk.chunk.input ?? chunk.chunk.parameters ?? chunk.chunk.args ?? {};
|
|
1438
|
+
streamingContext.toolCallIdToName.set(currentToolCallId, name);
|
|
1149
1439
|
iterationToolCalls.push({ name, params: parameters });
|
|
1150
1440
|
sendSseEvent(
|
|
1151
1441
|
streamingContext.controller,
|
|
@@ -1165,7 +1455,9 @@ var createStreamingResponse = async (model, aiSdkTools, messages, streamingConte
|
|
|
1165
1455
|
}
|
|
1166
1456
|
case "tool-result": {
|
|
1167
1457
|
const result = chunk.chunk.output ?? chunk.chunk.result ?? chunk.chunk.value;
|
|
1168
|
-
const currentToolCallId = streamingContext.lastEmittedToolCallId
|
|
1458
|
+
const currentToolCallId = streamingContext.lastEmittedToolCallId ?? ++streamingContext.toolCallId;
|
|
1459
|
+
const toolName = streamingContext.toolCallIdToName.get(currentToolCallId);
|
|
1460
|
+
const serverId = toolName ? extractServerId(toolName) : void 0;
|
|
1169
1461
|
iterationToolResults.push({ result });
|
|
1170
1462
|
sendSseEvent(
|
|
1171
1463
|
streamingContext.controller,
|
|
@@ -1176,7 +1468,8 @@ var createStreamingResponse = async (model, aiSdkTools, messages, streamingConte
|
|
|
1176
1468
|
id: currentToolCallId,
|
|
1177
1469
|
toolCallId: currentToolCallId,
|
|
1178
1470
|
result,
|
|
1179
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1471
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1472
|
+
serverId
|
|
1180
1473
|
}
|
|
1181
1474
|
}
|
|
1182
1475
|
);
|
|
@@ -1203,6 +1496,8 @@ var createStreamingResponse = async (model, aiSdkTools, messages, streamingConte
|
|
|
1203
1496
|
if (m.role === "tool") {
|
|
1204
1497
|
const currentToolCallId = streamingContext.lastEmittedToolCallId != null ? streamingContext.lastEmittedToolCallId : ++streamingContext.toolCallId;
|
|
1205
1498
|
const value = m.content;
|
|
1499
|
+
const toolName = streamingContext.toolCallIdToName.get(currentToolCallId);
|
|
1500
|
+
const serverId = toolName ? extractServerId(toolName) : void 0;
|
|
1206
1501
|
iterationToolResults.push({ result: value });
|
|
1207
1502
|
sendSseEvent(streamingContext.controller, streamingContext.encoder, {
|
|
1208
1503
|
type: "tool_result",
|
|
@@ -1210,7 +1505,8 @@ var createStreamingResponse = async (model, aiSdkTools, messages, streamingConte
|
|
|
1210
1505
|
id: currentToolCallId,
|
|
1211
1506
|
toolCallId: currentToolCallId,
|
|
1212
1507
|
result: value,
|
|
1213
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1508
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1509
|
+
serverId
|
|
1214
1510
|
}
|
|
1215
1511
|
});
|
|
1216
1512
|
}
|
|
@@ -1243,20 +1539,24 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1243
1539
|
return { role: "user", content: m.content };
|
|
1244
1540
|
}
|
|
1245
1541
|
});
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
)
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1542
|
+
const toolsets = await mcpClientManager.getToolsetsWithServerIds(selectedServers);
|
|
1543
|
+
const toolDefs = [];
|
|
1544
|
+
for (const serverTools of Object.values(toolsets)) {
|
|
1545
|
+
for (const [name, tool2] of Object.entries(serverTools)) {
|
|
1546
|
+
toolDefs.push({
|
|
1547
|
+
name,
|
|
1548
|
+
description: tool2?.description,
|
|
1549
|
+
inputSchema: zodToJsonSchema3(tool2?.inputSchema)
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1254
1553
|
if (!baseUrl) {
|
|
1255
1554
|
throw new Error("CONVEX_HTTP_URL is not set");
|
|
1256
1555
|
}
|
|
1257
1556
|
const emitToolCall = (call) => {
|
|
1258
1557
|
const currentToolCallId = ++streamingContext.toolCallId;
|
|
1259
1558
|
streamingContext.lastEmittedToolCallId = currentToolCallId;
|
|
1559
|
+
streamingContext.toolCallIdToName.set(currentToolCallId, call.name);
|
|
1260
1560
|
sendSseEvent(streamingContext.controller, streamingContext.encoder, {
|
|
1261
1561
|
type: "tool_call",
|
|
1262
1562
|
toolCall: {
|
|
@@ -1277,7 +1577,9 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1277
1577
|
toolCallId: currentToolCallId,
|
|
1278
1578
|
result: result.result,
|
|
1279
1579
|
error: result.error,
|
|
1280
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1580
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1581
|
+
serverId: result.serverId
|
|
1582
|
+
// Propagate serverId
|
|
1281
1583
|
}
|
|
1282
1584
|
});
|
|
1283
1585
|
};
|
|
@@ -1301,7 +1603,7 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1301
1603
|
},
|
|
1302
1604
|
executeToolCalls: async (messages2) => {
|
|
1303
1605
|
await executeToolCallsFromMessages(messages2, {
|
|
1304
|
-
|
|
1606
|
+
toolsets
|
|
1305
1607
|
});
|
|
1306
1608
|
},
|
|
1307
1609
|
handlers: {
|
|
@@ -1323,7 +1625,7 @@ var sendMessagesToBackend = async (messages, streamingContext, mcpClientManager,
|
|
|
1323
1625
|
text,
|
|
1324
1626
|
toolCalls,
|
|
1325
1627
|
toolResults.map((result) => ({
|
|
1326
|
-
result: result.result,
|
|
1628
|
+
result: result.result || result,
|
|
1327
1629
|
error: result.error
|
|
1328
1630
|
})),
|
|
1329
1631
|
false
|
|
@@ -1418,7 +1720,8 @@ chat.post("/", async (c) => {
|
|
|
1418
1720
|
encoder,
|
|
1419
1721
|
toolCallId: 0,
|
|
1420
1722
|
lastEmittedToolCallId: null,
|
|
1421
|
-
stepIndex: 0
|
|
1723
|
+
stepIndex: 0,
|
|
1724
|
+
toolCallIdToName: /* @__PURE__ */ new Map()
|
|
1422
1725
|
};
|
|
1423
1726
|
mcpClientManager.setElicitationCallback(async (request) => {
|
|
1424
1727
|
const elicitationRequest = {
|
|
@@ -1466,10 +1769,23 @@ chat.post("/", async (c) => {
|
|
|
1466
1769
|
requestData.selectedServers
|
|
1467
1770
|
);
|
|
1468
1771
|
} else {
|
|
1469
|
-
const
|
|
1772
|
+
const toolsets = await mcpClientManager.getToolsetsWithServerIds(
|
|
1470
1773
|
requestData.selectedServers
|
|
1471
1774
|
);
|
|
1472
|
-
const
|
|
1775
|
+
const flatToolsWithServerId = {};
|
|
1776
|
+
for (const [serverId, serverTools] of Object.entries(
|
|
1777
|
+
toolsets || {}
|
|
1778
|
+
)) {
|
|
1779
|
+
if (serverTools && typeof serverTools === "object") {
|
|
1780
|
+
for (const [toolName, tool2] of Object.entries(serverTools)) {
|
|
1781
|
+
flatToolsWithServerId[toolName] = {
|
|
1782
|
+
...tool2,
|
|
1783
|
+
_serverId: serverId
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
const aiSdkTools = convertMastraToolsToVercelTools(flatToolsWithServerId);
|
|
1473
1789
|
const llmModel = createLlmModel(
|
|
1474
1790
|
model,
|
|
1475
1791
|
apiKey || "",
|
|
@@ -1481,6 +1797,7 @@ chat.post("/", async (c) => {
|
|
|
1481
1797
|
messages,
|
|
1482
1798
|
streamingContext,
|
|
1483
1799
|
provider,
|
|
1800
|
+
flatToolsWithServerId,
|
|
1484
1801
|
temperature,
|
|
1485
1802
|
systemPrompt
|
|
1486
1803
|
);
|
|
@@ -9445,6 +9762,15 @@ var MCPJamClientManager = class {
|
|
|
9445
9762
|
getServerIdForName(serverName) {
|
|
9446
9763
|
return this.serverIdMapping.get(serverName);
|
|
9447
9764
|
}
|
|
9765
|
+
// Reverse lookup: get server name from internal server ID
|
|
9766
|
+
getServerNameForId(serverId) {
|
|
9767
|
+
for (const [name, id] of this.serverIdMapping.entries()) {
|
|
9768
|
+
if (id === serverId) {
|
|
9769
|
+
return name;
|
|
9770
|
+
}
|
|
9771
|
+
}
|
|
9772
|
+
return void 0;
|
|
9773
|
+
}
|
|
9448
9774
|
flattenToolsets(toolsets) {
|
|
9449
9775
|
const flattenedTools = {};
|
|
9450
9776
|
Object.values(toolsets).forEach((serverTools) => {
|
|
@@ -9452,6 +9778,26 @@ var MCPJamClientManager = class {
|
|
|
9452
9778
|
});
|
|
9453
9779
|
return flattenedTools;
|
|
9454
9780
|
}
|
|
9781
|
+
async getToolsetsWithServerIds(serverNameFilter) {
|
|
9782
|
+
const toolsetsByServer = {};
|
|
9783
|
+
const allServerIdsFromFilter = serverNameFilter?.map(
|
|
9784
|
+
(serverName) => this.getServerIdForName(serverName)
|
|
9785
|
+
);
|
|
9786
|
+
for (const [serverId, client] of this.mcpClients.entries()) {
|
|
9787
|
+
if (serverNameFilter && !allServerIdsFromFilter?.includes(serverId))
|
|
9788
|
+
continue;
|
|
9789
|
+
if (this.getConnectionStatus(serverId) !== "connected") continue;
|
|
9790
|
+
try {
|
|
9791
|
+
const toolsets = await client.getToolsets();
|
|
9792
|
+
const flattenedTools = this.flattenToolsets(toolsets);
|
|
9793
|
+
const serverName = this.getServerNameForId(serverId) || serverId;
|
|
9794
|
+
toolsetsByServer[serverName] = flattenedTools;
|
|
9795
|
+
} catch (error) {
|
|
9796
|
+
console.warn(`Failed to get tools from server ${serverId}:`, error);
|
|
9797
|
+
}
|
|
9798
|
+
}
|
|
9799
|
+
return toolsetsByServer;
|
|
9800
|
+
}
|
|
9455
9801
|
async getFlattenedToolsetsForEnabledServers(serverNameFilter) {
|
|
9456
9802
|
const allFlattenedTools = {};
|
|
9457
9803
|
const allServerIdsFromFilter = serverNameFilter?.map(
|
|
@@ -9687,30 +10033,12 @@ var MCPJamClientManager = class {
|
|
|
9687
10033
|
const tool2 = flattenedTools[name];
|
|
9688
10034
|
if (!tool2)
|
|
9689
10035
|
throw new Error(`Tool '${name}' not found in server '${serverId}'`);
|
|
9690
|
-
const
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
);
|
|
9695
|
-
const requiresContext = hasContextProperty || schema && Array.isArray(schema.required) && schema.required.includes("context");
|
|
9696
|
-
const contextWrapped = { context: parameters || {} };
|
|
9697
|
-
const direct = parameters || {};
|
|
9698
|
-
const attempts = requiresContext ? [contextWrapped, direct] : [direct, contextWrapped];
|
|
9699
|
-
let lastError = void 0;
|
|
9700
|
-
for (const args of attempts) {
|
|
9701
|
-
try {
|
|
9702
|
-
console.log("args", args);
|
|
9703
|
-
const result = await tool2.execute(args);
|
|
9704
|
-
if (result && result.isError) {
|
|
9705
|
-
const errorText = result.content && result.content[0] && result.content[0].text ? result.content[0].text : "Unknown error";
|
|
9706
|
-
throw new Error(errorText);
|
|
9707
|
-
}
|
|
9708
|
-
return { result };
|
|
9709
|
-
} catch (err) {
|
|
9710
|
-
lastError = err;
|
|
9711
|
-
}
|
|
10036
|
+
const result = await tool2.execute({ context: parameters || {} });
|
|
10037
|
+
if (result && result.isError) {
|
|
10038
|
+
const errorText = result.content && result.content[0] && result.content[0].text ? result.content[0].text : "Unknown error";
|
|
10039
|
+
throw new Error(errorText);
|
|
9712
10040
|
}
|
|
9713
|
-
|
|
10041
|
+
return { result };
|
|
9714
10042
|
}
|
|
9715
10043
|
async getResource(resourceUri, serverId) {
|
|
9716
10044
|
let uri = resourceUri;
|