@mcp-ts/sdk 1.2.0 → 1.3.1
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 +44 -40
- package/dist/adapters/agui-middleware.d.mts +2 -21
- package/dist/adapters/agui-middleware.d.ts +2 -21
- package/dist/adapters/agui-middleware.js +30 -50
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs +31 -50
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/client/react.d.mts +51 -331
- package/dist/client/react.d.ts +51 -331
- package/dist/client/react.js +76 -281
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +78 -277
- package/dist/client/react.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/agui-middleware.ts +60 -109
- package/src/client/react/index.ts +16 -30
- package/src/client/react/use-mcp-apps.tsx +214 -0
- package/src/client/react/agui-subscriber.ts +0 -275
- package/src/client/react/use-agui-subscriber.ts +0 -270
- package/src/client/react/use-mcp-app-iframe.ts +0 -164
package/dist/client/react.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useRef, useState, useEffect, useCallback
|
|
1
|
+
import { memo, useRef, useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import { nanoid } from 'nanoid';
|
|
3
3
|
import { AppBridge, PostMessageTransport } from '@modelcontextprotocol/ext-apps/app-bridge';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
5
|
|
|
5
6
|
var __defProp = Object.defineProperty;
|
|
6
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -926,302 +927,102 @@ function useAppHost(client, iframeRef, options) {
|
|
|
926
927
|
}, [client, iframeRef]);
|
|
927
928
|
return { host, error };
|
|
928
929
|
}
|
|
929
|
-
function
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
930
|
+
var McpAppRenderer = memo(function McpAppRenderer2({
|
|
931
|
+
metadata,
|
|
932
|
+
input,
|
|
933
|
+
result,
|
|
934
|
+
status,
|
|
935
|
+
sseClient,
|
|
936
|
+
className
|
|
936
937
|
}) {
|
|
937
938
|
const iframeRef = useRef(null);
|
|
938
939
|
const { host, error: hostError } = useAppHost(sseClient, iframeRef);
|
|
939
940
|
const [isLaunched, setIsLaunched] = useState(false);
|
|
940
941
|
const [error, setError] = useState(null);
|
|
941
|
-
const
|
|
942
|
-
const
|
|
943
|
-
const
|
|
942
|
+
const sentInputRef = useRef(false);
|
|
943
|
+
const sentResultRef = useRef(false);
|
|
944
|
+
const lastInputRef = useRef(input);
|
|
945
|
+
const lastResultRef = useRef(result);
|
|
946
|
+
const lastStatusRef = useRef(status);
|
|
944
947
|
useEffect(() => {
|
|
945
|
-
if (
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
}, [hostError]);
|
|
949
|
-
useEffect(() => {
|
|
950
|
-
if (!host || !resourceUri || !sessionId || launchAttemptedRef.current) return;
|
|
951
|
-
launchAttemptedRef.current = true;
|
|
952
|
-
host.launch(resourceUri, sessionId).then(() => {
|
|
953
|
-
setIsLaunched(true);
|
|
954
|
-
}).catch((err) => {
|
|
955
|
-
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
956
|
-
setError(error2);
|
|
957
|
-
});
|
|
958
|
-
}, [host, resourceUri, sessionId]);
|
|
948
|
+
if (!host || !metadata.resourceUri || !metadata.sessionId) return;
|
|
949
|
+
host.launch(metadata.resourceUri, metadata.sessionId).then(() => setIsLaunched(true)).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
|
|
950
|
+
}, [host, metadata.resourceUri, metadata.sessionId]);
|
|
959
951
|
useEffect(() => {
|
|
960
|
-
if (!host || !isLaunched || !
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
if (!host || !isLaunched || toolResult === void 0 || toolResultSentRef.current) return;
|
|
966
|
-
if (toolStatus !== "complete") return;
|
|
967
|
-
toolResultSentRef.current = true;
|
|
968
|
-
const formattedResult = typeof toolResult === "string" ? { content: [{ type: "text", text: toolResult }] } : toolResult;
|
|
969
|
-
host.sendToolResult(formattedResult);
|
|
970
|
-
}, [host, isLaunched, toolResult, toolStatus]);
|
|
971
|
-
return {
|
|
972
|
-
iframeRef,
|
|
973
|
-
isLaunched,
|
|
974
|
-
error
|
|
975
|
-
};
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// src/client/react/agui-subscriber.ts
|
|
979
|
-
function createMcpAppSubscriber(config) {
|
|
980
|
-
const eventName = config.eventName || "mcp-apps-ui";
|
|
981
|
-
const subscriber = {
|
|
982
|
-
// Listen for custom MCP app events from middleware
|
|
983
|
-
onCustomEvent: ({ event }) => {
|
|
984
|
-
if (event.name === eventName && config.onMcpApp) {
|
|
985
|
-
const payload = event.value;
|
|
986
|
-
config.onMcpApp(payload);
|
|
987
|
-
}
|
|
988
|
-
},
|
|
989
|
-
// Listen for tool call lifecycle events
|
|
990
|
-
onToolCallStartEvent: (params) => {
|
|
991
|
-
if (config.onToolCall && params.event.toolCallName) {
|
|
992
|
-
config.onToolCall({
|
|
993
|
-
toolCallId: params.event.toolCallId || "",
|
|
994
|
-
toolName: params.event.toolCallName,
|
|
995
|
-
status: "start"
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
},
|
|
999
|
-
onToolCallArgsEvent: (params) => {
|
|
1000
|
-
if (config.onToolCall) {
|
|
1001
|
-
const args = params.partialToolCallArgs;
|
|
1002
|
-
config.onToolCall({
|
|
1003
|
-
toolCallId: params.event.toolCallId || "",
|
|
1004
|
-
toolName: params.toolCallName || "",
|
|
1005
|
-
// toolCallName is in params, not event
|
|
1006
|
-
args,
|
|
1007
|
-
status: "args"
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
},
|
|
1011
|
-
onToolCallEndEvent: (params) => {
|
|
1012
|
-
if (config.onToolCall && params.event.toolCallId) {
|
|
1013
|
-
config.onToolCall({
|
|
1014
|
-
toolCallId: params.event.toolCallId,
|
|
1015
|
-
toolName: params.toolCallName || "",
|
|
1016
|
-
// toolCallName is in params, not event
|
|
1017
|
-
status: "end"
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
},
|
|
1021
|
-
onToolCallResultEvent: (params) => {
|
|
1022
|
-
if (config.onToolCall && params.event.toolCallId) {
|
|
1023
|
-
config.onToolCall({
|
|
1024
|
-
toolCallId: params.event.toolCallId,
|
|
1025
|
-
toolName: "",
|
|
1026
|
-
// Not available in result event
|
|
1027
|
-
result: params.event.content,
|
|
1028
|
-
// content contains the result
|
|
1029
|
-
status: "result"
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
};
|
|
1034
|
-
return subscriber;
|
|
1035
|
-
}
|
|
1036
|
-
function subscribeMcpAppEvents(agent, config) {
|
|
1037
|
-
const subscriber = createMcpAppSubscriber(config);
|
|
1038
|
-
const { unsubscribe } = agent.subscribe(subscriber);
|
|
1039
|
-
return unsubscribe;
|
|
1040
|
-
}
|
|
1041
|
-
var McpAppEventManager = class {
|
|
1042
|
-
constructor() {
|
|
1043
|
-
__publicField(this, "events", /* @__PURE__ */ new Map());
|
|
1044
|
-
__publicField(this, "toolCalls", /* @__PURE__ */ new Map());
|
|
1045
|
-
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
1046
|
-
__publicField(this, "unsubscribe");
|
|
1047
|
-
__publicField(this, "cachedSnapshot", {});
|
|
1048
|
-
}
|
|
1049
|
-
/**
|
|
1050
|
-
* Attach to an AG-UI agent
|
|
1051
|
-
*/
|
|
1052
|
-
attach(agent) {
|
|
1053
|
-
if (this.unsubscribe) {
|
|
1054
|
-
this.unsubscribe();
|
|
952
|
+
if (!host || !isLaunched || !input) return;
|
|
953
|
+
if (!sentInputRef.current || JSON.stringify(input) !== JSON.stringify(lastInputRef.current)) {
|
|
954
|
+
sentInputRef.current = true;
|
|
955
|
+
lastInputRef.current = input;
|
|
956
|
+
host.sendToolInput(input);
|
|
1055
957
|
}
|
|
1056
|
-
|
|
1057
|
-
onMcpApp: (event) => {
|
|
1058
|
-
this.events.set(event.toolName, event);
|
|
1059
|
-
this.cachedSnapshot = Object.fromEntries(this.events);
|
|
1060
|
-
this.notify();
|
|
1061
|
-
},
|
|
1062
|
-
onToolCall: (event) => {
|
|
1063
|
-
if (event.toolCallId) {
|
|
1064
|
-
this.toolCalls.set(event.toolCallId, event);
|
|
1065
|
-
this.notify();
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
});
|
|
1069
|
-
}
|
|
1070
|
-
/**
|
|
1071
|
-
* Detach from the current agent
|
|
1072
|
-
*/
|
|
1073
|
-
detach() {
|
|
1074
|
-
if (this.unsubscribe) {
|
|
1075
|
-
this.unsubscribe();
|
|
1076
|
-
this.unsubscribe = void 0;
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
/**
|
|
1080
|
-
* Get MCP app event for a specific tool
|
|
1081
|
-
*/
|
|
1082
|
-
getEvent(toolName) {
|
|
1083
|
-
return this.events.get(toolName);
|
|
1084
|
-
}
|
|
1085
|
-
/**
|
|
1086
|
-
* Get all MCP app events (cached for useSyncExternalStore)
|
|
1087
|
-
*/
|
|
1088
|
-
getAllEvents() {
|
|
1089
|
-
return this.cachedSnapshot;
|
|
1090
|
-
}
|
|
1091
|
-
/**
|
|
1092
|
-
* Get tool call event by ID
|
|
1093
|
-
*/
|
|
1094
|
-
getToolCall(toolCallId) {
|
|
1095
|
-
return this.toolCalls.get(toolCallId);
|
|
1096
|
-
}
|
|
1097
|
-
/**
|
|
1098
|
-
* Subscribe to event changes
|
|
1099
|
-
*/
|
|
1100
|
-
subscribe(listener) {
|
|
1101
|
-
this.listeners.add(listener);
|
|
1102
|
-
return () => this.listeners.delete(listener);
|
|
1103
|
-
}
|
|
1104
|
-
/**
|
|
1105
|
-
* Clear all events
|
|
1106
|
-
*/
|
|
1107
|
-
clear() {
|
|
1108
|
-
this.events.clear();
|
|
1109
|
-
this.toolCalls.clear();
|
|
1110
|
-
this.cachedSnapshot = {};
|
|
1111
|
-
this.notify();
|
|
1112
|
-
}
|
|
1113
|
-
notify() {
|
|
1114
|
-
this.listeners.forEach((listener) => listener());
|
|
1115
|
-
}
|
|
1116
|
-
};
|
|
1117
|
-
|
|
1118
|
-
// src/client/react/use-agui-subscriber.ts
|
|
1119
|
-
function useAguiSubscriber(agent, config) {
|
|
958
|
+
}, [host, isLaunched, input]);
|
|
1120
959
|
useEffect(() => {
|
|
1121
|
-
if (!
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
|
|
960
|
+
if (!host || !isLaunched || result === void 0) return;
|
|
961
|
+
if (status !== "complete") return;
|
|
962
|
+
if (!sentResultRef.current || JSON.stringify(result) !== JSON.stringify(lastResultRef.current)) {
|
|
963
|
+
sentResultRef.current = true;
|
|
964
|
+
lastResultRef.current = result;
|
|
965
|
+
const formattedResult = typeof result === "string" ? { content: [{ type: "text", text: result }] } : result;
|
|
966
|
+
host.sendToolResult(formattedResult);
|
|
967
|
+
}
|
|
968
|
+
}, [host, isLaunched, result, status]);
|
|
1129
969
|
useEffect(() => {
|
|
1130
|
-
if (
|
|
1131
|
-
|
|
1132
|
-
|
|
970
|
+
if (status === "executing" && lastStatusRef.current !== "executing") {
|
|
971
|
+
sentInputRef.current = false;
|
|
972
|
+
sentResultRef.current = false;
|
|
1133
973
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
974
|
+
lastStatusRef.current = status;
|
|
975
|
+
}, [status]);
|
|
976
|
+
const displayError = error || hostError;
|
|
977
|
+
if (displayError) {
|
|
978
|
+
return /* @__PURE__ */ jsxs("div", { className: `p-4 bg-red-900/20 border border-red-700 rounded text-red-200 ${className || ""}`, children: [
|
|
979
|
+
"Error: ",
|
|
980
|
+
displayError.message || String(displayError)
|
|
981
|
+
] });
|
|
982
|
+
}
|
|
983
|
+
return /* @__PURE__ */ jsxs("div", { className: `w-full border border-gray-700 rounded overflow-hidden bg-white min-h-96 my-2 relative ${className || ""}`, children: [
|
|
984
|
+
/* @__PURE__ */ jsx(
|
|
985
|
+
"iframe",
|
|
986
|
+
{
|
|
987
|
+
ref: iframeRef,
|
|
988
|
+
sandbox: "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads",
|
|
989
|
+
className: "w-full h-full min-h-96",
|
|
990
|
+
style: { height: "auto" },
|
|
991
|
+
title: "MCP App"
|
|
992
|
+
}
|
|
993
|
+
),
|
|
994
|
+
!isLaunched && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gray-900/50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsx("div", { className: "w-6 h-6 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" }) })
|
|
995
|
+
] });
|
|
996
|
+
});
|
|
997
|
+
function useMcpApps(mcpClient) {
|
|
998
|
+
const getAppMetadata = useCallback(
|
|
999
|
+
(toolName) => {
|
|
1000
|
+
if (!mcpClient) return void 0;
|
|
1001
|
+
const extractedName = extractToolName(toolName);
|
|
1146
1002
|
for (const conn of mcpClient.connections) {
|
|
1147
1003
|
for (const tool of conn.tools) {
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
const resourceUri = typeof ui.resourceUri === "string" ? ui.resourceUri : typeof ui.uri === "string" ? ui.uri : void 0;
|
|
1154
|
-
if (resourceUri) {
|
|
1155
|
-
combined[tool.name] = {
|
|
1156
|
-
toolCallId: "",
|
|
1004
|
+
const candidateName = extractToolName(tool.name);
|
|
1005
|
+
const resourceUri = tool.mcpApp?.resourceUri ?? tool._meta?.ui?.resourceUri ?? tool._meta?.["ui/resourceUri"];
|
|
1006
|
+
if (resourceUri && candidateName === extractedName) {
|
|
1007
|
+
return {
|
|
1008
|
+
toolName: candidateName,
|
|
1157
1009
|
resourceUri,
|
|
1158
|
-
sessionId: conn.sessionId
|
|
1159
|
-
toolName: tool.name
|
|
1010
|
+
sessionId: conn.sessionId
|
|
1160
1011
|
};
|
|
1161
1012
|
}
|
|
1162
1013
|
}
|
|
1163
1014
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
toolCallId: event.toolCallId || combined[toolName].toolCallId,
|
|
1170
|
-
result: event.result,
|
|
1171
|
-
input: event.input,
|
|
1172
|
-
status: event.status
|
|
1173
|
-
};
|
|
1174
|
-
} else {
|
|
1175
|
-
combined[toolName] = event;
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
return new Proxy(combined, {
|
|
1179
|
-
get(target, prop) {
|
|
1180
|
-
if (typeof prop !== "string") return void 0;
|
|
1181
|
-
if (prop in target) return target[prop];
|
|
1182
|
-
const match = prop.match(/^tool_[^_]+_(.+)$/);
|
|
1183
|
-
if (match && match[1] in target) {
|
|
1184
|
-
return target[match[1]];
|
|
1185
|
-
}
|
|
1186
|
-
return void 0;
|
|
1187
|
-
},
|
|
1188
|
-
// Support Object.entries, Object.keys, etc. by returning base names
|
|
1189
|
-
ownKeys(target) {
|
|
1190
|
-
return Reflect.ownKeys(target);
|
|
1191
|
-
},
|
|
1192
|
-
getOwnPropertyDescriptor(target, prop) {
|
|
1193
|
-
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
}, [agentApps, mcpClient]);
|
|
1197
|
-
return {
|
|
1198
|
-
apps,
|
|
1199
|
-
// getApp handles both base and prefixed names transparently via the Proxy
|
|
1200
|
-
getApp: (toolName) => apps[toolName],
|
|
1201
|
-
clear: () => manager.clear()
|
|
1202
|
-
};
|
|
1015
|
+
return void 0;
|
|
1016
|
+
},
|
|
1017
|
+
[mcpClient]
|
|
1018
|
+
);
|
|
1019
|
+
return { getAppMetadata, McpAppRenderer };
|
|
1203
1020
|
}
|
|
1204
|
-
function
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
if (!agent) {
|
|
1208
|
-
setToolCalls({});
|
|
1209
|
-
return;
|
|
1210
|
-
}
|
|
1211
|
-
const subscriber = createMcpAppSubscriber({
|
|
1212
|
-
onToolCall: (event) => {
|
|
1213
|
-
setToolCalls((prev) => ({
|
|
1214
|
-
...prev,
|
|
1215
|
-
[event.toolCallId]: event
|
|
1216
|
-
}));
|
|
1217
|
-
}
|
|
1218
|
-
});
|
|
1219
|
-
const { unsubscribe } = agent.subscribe(subscriber);
|
|
1220
|
-
return () => unsubscribe();
|
|
1221
|
-
}, [agent]);
|
|
1222
|
-
return { toolCalls };
|
|
1021
|
+
function extractToolName(fullName) {
|
|
1022
|
+
const match = fullName.match(/(?:tool_[^_]+_)?(.+)$/);
|
|
1023
|
+
return match?.[1] || fullName;
|
|
1223
1024
|
}
|
|
1224
1025
|
|
|
1225
|
-
export { AppHost,
|
|
1026
|
+
export { AppHost, SSEClient, useAppHost, useMcp, useMcpApps };
|
|
1226
1027
|
//# sourceMappingURL=react.mjs.map
|
|
1227
1028
|
//# sourceMappingURL=react.mjs.map
|