@mcp-ts/sdk 1.1.0 → 1.2.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/README.md +21 -10
- package/dist/adapters/agui-adapter.js +0 -1
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +0 -1
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +5 -0
- package/dist/adapters/agui-middleware.d.ts +5 -0
- package/dist/adapters/agui-middleware.js +12 -23
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs +12 -23
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/client/react.d.mts +351 -3
- package/dist/client/react.d.ts +351 -3
- package/dist/client/react.js +308 -6
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +302 -7
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.js +1 -1
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +1 -1
- package/dist/client/vue.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -1
- package/dist/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +38 -2
- package/dist/shared/index.d.ts +38 -2
- package/dist/shared/index.js +19 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +18 -1
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/adapters/agui-adapter.ts +2 -4
- package/src/adapters/agui-middleware.ts +15 -27
- package/src/client/react/agui-subscriber.ts +275 -0
- package/src/client/react/index.ts +23 -4
- package/src/client/react/use-agui-subscriber.ts +270 -0
- package/src/client/react/{use-mcp-app.ts → use-app-host.ts} +2 -2
- package/src/client/react/use-mcp-app-iframe.ts +164 -0
- package/src/client/react/{useMcp.ts → use-mcp.ts} +2 -2
- package/src/client/vue/index.ts +1 -1
- package/src/shared/index.ts +6 -1
- package/src/shared/tool-utils.ts +61 -0
- /package/src/client/vue/{useMcp.ts → use-mcp.ts} +0 -0
package/dist/client/react.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useRef, useState, useEffect, useCallback } from 'react';
|
|
1
|
+
import { useRef, useState, useEffect, useCallback, useSyncExternalStore, useMemo } from 'react';
|
|
2
2
|
import { nanoid } from 'nanoid';
|
|
3
3
|
import { AppBridge, PostMessageTransport } from '@modelcontextprotocol/ext-apps/app-bridge';
|
|
4
4
|
|
|
@@ -327,7 +327,7 @@ var SSEClient = class {
|
|
|
327
327
|
}
|
|
328
328
|
};
|
|
329
329
|
|
|
330
|
-
// src/client/react/
|
|
330
|
+
// src/client/react/use-mcp.ts
|
|
331
331
|
function useMcp(options) {
|
|
332
332
|
const {
|
|
333
333
|
url,
|
|
@@ -593,7 +593,7 @@ function useMcp(options) {
|
|
|
593
593
|
getPrompt,
|
|
594
594
|
listResources,
|
|
595
595
|
readResource,
|
|
596
|
-
|
|
596
|
+
sseClient: clientRef.current
|
|
597
597
|
};
|
|
598
598
|
}
|
|
599
599
|
var HOST_INFO = { name: "mcp-ts-host", version: "1.0.0" };
|
|
@@ -893,8 +893,8 @@ var AppHost = class {
|
|
|
893
893
|
}
|
|
894
894
|
};
|
|
895
895
|
|
|
896
|
-
// src/client/react/use-
|
|
897
|
-
function
|
|
896
|
+
// src/client/react/use-app-host.ts
|
|
897
|
+
function useAppHost(client, iframeRef, options) {
|
|
898
898
|
const [host, setHost] = useState(null);
|
|
899
899
|
const [error, setError] = useState(null);
|
|
900
900
|
const initializingRef = useRef(false);
|
|
@@ -914,7 +914,7 @@ function useMcpApp(client, iframeRef, options) {
|
|
|
914
914
|
setHost(appHost);
|
|
915
915
|
await appHost.start();
|
|
916
916
|
} catch (err) {
|
|
917
|
-
console.error("[
|
|
917
|
+
console.error("[useAppHost] Failed to initialize AppHost:", err);
|
|
918
918
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
919
919
|
}
|
|
920
920
|
};
|
|
@@ -926,7 +926,302 @@ function useMcpApp(client, iframeRef, options) {
|
|
|
926
926
|
}, [client, iframeRef]);
|
|
927
927
|
return { host, error };
|
|
928
928
|
}
|
|
929
|
+
function useMcpAppIframe({
|
|
930
|
+
resourceUri,
|
|
931
|
+
sessionId,
|
|
932
|
+
toolInput,
|
|
933
|
+
toolResult,
|
|
934
|
+
toolStatus,
|
|
935
|
+
sseClient
|
|
936
|
+
}) {
|
|
937
|
+
const iframeRef = useRef(null);
|
|
938
|
+
const { host, error: hostError } = useAppHost(sseClient, iframeRef);
|
|
939
|
+
const [isLaunched, setIsLaunched] = useState(false);
|
|
940
|
+
const [error, setError] = useState(null);
|
|
941
|
+
const launchAttemptedRef = useRef(false);
|
|
942
|
+
const toolInputSentRef = useRef(false);
|
|
943
|
+
const toolResultSentRef = useRef(false);
|
|
944
|
+
useEffect(() => {
|
|
945
|
+
if (hostError) {
|
|
946
|
+
setError(hostError);
|
|
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]);
|
|
959
|
+
useEffect(() => {
|
|
960
|
+
if (!host || !isLaunched || !toolInput || toolInputSentRef.current) return;
|
|
961
|
+
toolInputSentRef.current = true;
|
|
962
|
+
host.sendToolInput(toolInput);
|
|
963
|
+
}, [host, isLaunched, toolInput]);
|
|
964
|
+
useEffect(() => {
|
|
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();
|
|
1055
|
+
}
|
|
1056
|
+
this.unsubscribe = subscribeMcpAppEvents(agent, {
|
|
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) {
|
|
1120
|
+
useEffect(() => {
|
|
1121
|
+
if (!agent) return;
|
|
1122
|
+
const subscriber = createMcpAppSubscriber(config);
|
|
1123
|
+
const { unsubscribe } = agent.subscribe(subscriber);
|
|
1124
|
+
return () => unsubscribe();
|
|
1125
|
+
}, [agent, config]);
|
|
1126
|
+
}
|
|
1127
|
+
function useMcpApps(agent, mcpClient) {
|
|
1128
|
+
const [manager] = useState(() => new McpAppEventManager());
|
|
1129
|
+
useEffect(() => {
|
|
1130
|
+
if (!agent) {
|
|
1131
|
+
manager.detach();
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
manager.attach(agent);
|
|
1135
|
+
return () => manager.detach();
|
|
1136
|
+
}, [agent, manager]);
|
|
1137
|
+
const agentApps = useSyncExternalStore(
|
|
1138
|
+
(callback) => manager.subscribe(callback),
|
|
1139
|
+
() => manager.getAllEvents(),
|
|
1140
|
+
() => ({})
|
|
1141
|
+
// Server-side snapshot
|
|
1142
|
+
);
|
|
1143
|
+
const apps = useMemo(() => {
|
|
1144
|
+
const combined = {};
|
|
1145
|
+
if (mcpClient) {
|
|
1146
|
+
for (const conn of mcpClient.connections) {
|
|
1147
|
+
for (const tool of conn.tools) {
|
|
1148
|
+
const meta = tool._meta;
|
|
1149
|
+
if (!meta?.ui) continue;
|
|
1150
|
+
const ui = meta.ui;
|
|
1151
|
+
if (typeof ui !== "object" || !ui) continue;
|
|
1152
|
+
if (ui.visibility && !ui.visibility.includes("app")) continue;
|
|
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: "",
|
|
1157
|
+
resourceUri,
|
|
1158
|
+
sessionId: conn.sessionId,
|
|
1159
|
+
toolName: tool.name
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
for (const [toolName, event] of Object.entries(agentApps)) {
|
|
1166
|
+
if (combined[toolName]) {
|
|
1167
|
+
combined[toolName] = {
|
|
1168
|
+
...combined[toolName],
|
|
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
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
function useToolCallEvents(agent) {
|
|
1205
|
+
const [toolCalls, setToolCalls] = useState({});
|
|
1206
|
+
useEffect(() => {
|
|
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 };
|
|
1223
|
+
}
|
|
929
1224
|
|
|
930
|
-
export { AppHost, SSEClient, useMcp,
|
|
1225
|
+
export { AppHost, McpAppEventManager, SSEClient, createMcpAppSubscriber, subscribeMcpAppEvents, useAguiSubscriber, useAppHost, useMcp, useMcpAppIframe, useMcpApps, useToolCallEvents };
|
|
931
1226
|
//# sourceMappingURL=react.mjs.map
|
|
932
1227
|
//# sourceMappingURL=react.mjs.map
|