@mcp-ts/sdk 1.0.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/LICENSE +21 -0
- package/README.md +297 -0
- package/dist/adapters/agui-adapter.d.mts +119 -0
- package/dist/adapters/agui-adapter.d.ts +119 -0
- package/dist/adapters/agui-adapter.js +109 -0
- package/dist/adapters/agui-adapter.js.map +1 -0
- package/dist/adapters/agui-adapter.mjs +107 -0
- package/dist/adapters/agui-adapter.mjs.map +1 -0
- package/dist/adapters/agui-middleware.d.mts +171 -0
- package/dist/adapters/agui-middleware.d.ts +171 -0
- package/dist/adapters/agui-middleware.js +429 -0
- package/dist/adapters/agui-middleware.js.map +1 -0
- package/dist/adapters/agui-middleware.mjs +417 -0
- package/dist/adapters/agui-middleware.mjs.map +1 -0
- package/dist/adapters/ai-adapter.d.mts +38 -0
- package/dist/adapters/ai-adapter.d.ts +38 -0
- package/dist/adapters/ai-adapter.js +82 -0
- package/dist/adapters/ai-adapter.js.map +1 -0
- package/dist/adapters/ai-adapter.mjs +80 -0
- package/dist/adapters/ai-adapter.mjs.map +1 -0
- package/dist/adapters/langchain-adapter.d.mts +46 -0
- package/dist/adapters/langchain-adapter.d.ts +46 -0
- package/dist/adapters/langchain-adapter.js +102 -0
- package/dist/adapters/langchain-adapter.js.map +1 -0
- package/dist/adapters/langchain-adapter.mjs +100 -0
- package/dist/adapters/langchain-adapter.mjs.map +1 -0
- package/dist/adapters/mastra-adapter.d.mts +49 -0
- package/dist/adapters/mastra-adapter.d.ts +49 -0
- package/dist/adapters/mastra-adapter.js +95 -0
- package/dist/adapters/mastra-adapter.js.map +1 -0
- package/dist/adapters/mastra-adapter.mjs +93 -0
- package/dist/adapters/mastra-adapter.mjs.map +1 -0
- package/dist/client/index.d.mts +119 -0
- package/dist/client/index.d.ts +119 -0
- package/dist/client/index.js +225 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/index.mjs +223 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/client/react.d.mts +151 -0
- package/dist/client/react.d.ts +151 -0
- package/dist/client/react.js +492 -0
- package/dist/client/react.js.map +1 -0
- package/dist/client/react.mjs +489 -0
- package/dist/client/react.mjs.map +1 -0
- package/dist/client/vue.d.mts +157 -0
- package/dist/client/vue.d.ts +157 -0
- package/dist/client/vue.js +474 -0
- package/dist/client/vue.js.map +1 -0
- package/dist/client/vue.mjs +471 -0
- package/dist/client/vue.mjs.map +1 -0
- package/dist/events-BP6WyRNh.d.mts +110 -0
- package/dist/events-BP6WyRNh.d.ts +110 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +2784 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2723 -0
- package/dist/index.mjs.map +1 -0
- package/dist/multi-session-client-BOFgPypS.d.ts +389 -0
- package/dist/multi-session-client-DMF3ED2O.d.mts +389 -0
- package/dist/server/index.d.mts +269 -0
- package/dist/server/index.d.ts +269 -0
- package/dist/server/index.js +2444 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/index.mjs +2414 -0
- package/dist/server/index.mjs.map +1 -0
- package/dist/shared/index.d.mts +24 -0
- package/dist/shared/index.d.ts +24 -0
- package/dist/shared/index.js +223 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/index.mjs +190 -0
- package/dist/shared/index.mjs.map +1 -0
- package/dist/types-SbDlA2VX.d.mts +153 -0
- package/dist/types-SbDlA2VX.d.ts +153 -0
- package/dist/utils-0qmYrqoa.d.mts +92 -0
- package/dist/utils-0qmYrqoa.d.ts +92 -0
- package/package.json +165 -0
- package/src/adapters/agui-adapter.ts +210 -0
- package/src/adapters/agui-middleware.ts +512 -0
- package/src/adapters/ai-adapter.ts +115 -0
- package/src/adapters/langchain-adapter.ts +127 -0
- package/src/adapters/mastra-adapter.ts +126 -0
- package/src/client/core/sse-client.ts +340 -0
- package/src/client/index.ts +26 -0
- package/src/client/react/index.ts +10 -0
- package/src/client/react/useMcp.ts +558 -0
- package/src/client/vue/index.ts +10 -0
- package/src/client/vue/useMcp.ts +542 -0
- package/src/index.ts +11 -0
- package/src/server/handlers/nextjs-handler.ts +216 -0
- package/src/server/handlers/sse-handler.ts +699 -0
- package/src/server/index.ts +57 -0
- package/src/server/mcp/multi-session-client.ts +132 -0
- package/src/server/mcp/oauth-client.ts +1168 -0
- package/src/server/mcp/storage-oauth-provider.ts +239 -0
- package/src/server/storage/file-backend.ts +169 -0
- package/src/server/storage/index.ts +115 -0
- package/src/server/storage/memory-backend.ts +132 -0
- package/src/server/storage/redis-backend.ts +210 -0
- package/src/server/storage/redis.ts +160 -0
- package/src/server/storage/types.ts +109 -0
- package/src/shared/constants.ts +29 -0
- package/src/shared/errors.ts +133 -0
- package/src/shared/events.ts +166 -0
- package/src/shared/index.ts +70 -0
- package/src/shared/types.ts +274 -0
- package/src/shared/utils.ts +16 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { shallowRef, ref, onMounted, onUnmounted } from 'vue';
|
|
2
|
+
import { nanoid } from 'nanoid';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
+
var SSEClient = class {
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.options = options;
|
|
10
|
+
__publicField(this, "eventSource", null);
|
|
11
|
+
__publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
|
|
12
|
+
__publicField(this, "reconnectAttempts", 0);
|
|
13
|
+
__publicField(this, "maxReconnectAttempts", 5);
|
|
14
|
+
__publicField(this, "reconnectDelay", 1e3);
|
|
15
|
+
__publicField(this, "isManuallyDisconnected", false);
|
|
16
|
+
__publicField(this, "connectionPromise", null);
|
|
17
|
+
__publicField(this, "connectionResolver", null);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Connect to SSE endpoint
|
|
21
|
+
*/
|
|
22
|
+
connect() {
|
|
23
|
+
if (this.eventSource) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.isManuallyDisconnected = false;
|
|
27
|
+
this.options.onStatusChange?.("connecting");
|
|
28
|
+
this.connectionPromise = new Promise((resolve) => {
|
|
29
|
+
this.connectionResolver = resolve;
|
|
30
|
+
});
|
|
31
|
+
const url = new URL(this.options.url, typeof window !== "undefined" ? window.location.origin : void 0);
|
|
32
|
+
url.searchParams.set("identity", this.options.identity);
|
|
33
|
+
if (this.options.authToken) {
|
|
34
|
+
url.searchParams.set("token", this.options.authToken);
|
|
35
|
+
}
|
|
36
|
+
this.eventSource = new EventSource(url.toString());
|
|
37
|
+
this.eventSource.addEventListener("open", () => {
|
|
38
|
+
console.log("[SSEClient] Connected");
|
|
39
|
+
this.reconnectAttempts = 0;
|
|
40
|
+
this.options.onStatusChange?.("connected");
|
|
41
|
+
});
|
|
42
|
+
this.eventSource.addEventListener("connected", (e) => {
|
|
43
|
+
const data = JSON.parse(e.data);
|
|
44
|
+
console.log("[SSEClient] Server ready:", data);
|
|
45
|
+
if (this.connectionResolver) {
|
|
46
|
+
this.connectionResolver();
|
|
47
|
+
this.connectionResolver = null;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
this.eventSource.addEventListener("connection", (e) => {
|
|
51
|
+
const event = JSON.parse(e.data);
|
|
52
|
+
this.options.onConnectionEvent?.(event);
|
|
53
|
+
});
|
|
54
|
+
this.eventSource.addEventListener("observability", (e) => {
|
|
55
|
+
const event = JSON.parse(e.data);
|
|
56
|
+
this.options.onObservabilityEvent?.(event);
|
|
57
|
+
});
|
|
58
|
+
this.eventSource.addEventListener("rpc-response", (e) => {
|
|
59
|
+
const response = JSON.parse(e.data);
|
|
60
|
+
this.handleRpcResponse(response);
|
|
61
|
+
});
|
|
62
|
+
this.eventSource.addEventListener("error", () => {
|
|
63
|
+
console.error("[SSEClient] Connection error");
|
|
64
|
+
this.options.onStatusChange?.("error");
|
|
65
|
+
if (!this.isManuallyDisconnected && this.reconnectAttempts < this.maxReconnectAttempts) {
|
|
66
|
+
this.reconnectAttempts++;
|
|
67
|
+
console.log(`[SSEClient] Reconnecting (attempt ${this.reconnectAttempts})...`);
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
this.disconnect();
|
|
70
|
+
this.connect();
|
|
71
|
+
}, this.reconnectDelay * this.reconnectAttempts);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Disconnect from SSE endpoint
|
|
77
|
+
*/
|
|
78
|
+
disconnect() {
|
|
79
|
+
this.isManuallyDisconnected = true;
|
|
80
|
+
if (this.eventSource) {
|
|
81
|
+
this.eventSource.close();
|
|
82
|
+
this.eventSource = null;
|
|
83
|
+
}
|
|
84
|
+
this.connectionPromise = null;
|
|
85
|
+
this.connectionResolver = null;
|
|
86
|
+
for (const [id, { reject }] of this.pendingRequests.entries()) {
|
|
87
|
+
const error = new Error("Connection closed");
|
|
88
|
+
error.name = "ConnectionClosedError";
|
|
89
|
+
reject(error);
|
|
90
|
+
}
|
|
91
|
+
this.pendingRequests.clear();
|
|
92
|
+
this.options.onStatusChange?.("disconnected");
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Send RPC request via SSE
|
|
96
|
+
* Note: SSE is unidirectional (server->client), so we need to send requests via POST
|
|
97
|
+
*/
|
|
98
|
+
async sendRequest(method, params) {
|
|
99
|
+
if (this.connectionPromise) {
|
|
100
|
+
await this.connectionPromise;
|
|
101
|
+
}
|
|
102
|
+
const id = `rpc_${nanoid(10)}`;
|
|
103
|
+
const request = {
|
|
104
|
+
id,
|
|
105
|
+
method,
|
|
106
|
+
params
|
|
107
|
+
};
|
|
108
|
+
const promise = new Promise((resolve, reject) => {
|
|
109
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
if (this.pendingRequests.has(id)) {
|
|
112
|
+
this.pendingRequests.delete(id);
|
|
113
|
+
reject(new Error("Request timeout"));
|
|
114
|
+
}
|
|
115
|
+
}, 3e4);
|
|
116
|
+
});
|
|
117
|
+
try {
|
|
118
|
+
const url = new URL(this.options.url, typeof window !== "undefined" ? window.location.origin : void 0);
|
|
119
|
+
url.searchParams.set("identity", this.options.identity);
|
|
120
|
+
await fetch(url.toString(), {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: {
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
...this.options.authToken && { Authorization: `Bearer ${this.options.authToken}` }
|
|
125
|
+
},
|
|
126
|
+
body: JSON.stringify(request)
|
|
127
|
+
});
|
|
128
|
+
} catch (error) {
|
|
129
|
+
this.pendingRequests.delete(id);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
return promise;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Handle RPC response
|
|
136
|
+
*/
|
|
137
|
+
handleRpcResponse(response) {
|
|
138
|
+
const pending = this.pendingRequests.get(response.id);
|
|
139
|
+
if (pending) {
|
|
140
|
+
this.pendingRequests.delete(response.id);
|
|
141
|
+
if (response.error) {
|
|
142
|
+
pending.reject(new Error(response.error.message));
|
|
143
|
+
} else {
|
|
144
|
+
pending.resolve(response.result);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get all user sessions
|
|
150
|
+
*/
|
|
151
|
+
async getSessions() {
|
|
152
|
+
return this.sendRequest("getSessions");
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Connect to an MCP server
|
|
156
|
+
*/
|
|
157
|
+
async connectToServer(params) {
|
|
158
|
+
return this.sendRequest("connect", params);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Disconnect from an MCP server
|
|
162
|
+
*/
|
|
163
|
+
async disconnectFromServer(sessionId) {
|
|
164
|
+
return this.sendRequest("disconnect", { sessionId });
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* List tools from a session
|
|
168
|
+
*/
|
|
169
|
+
async listTools(sessionId) {
|
|
170
|
+
return this.sendRequest("listTools", { sessionId });
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Call a tool
|
|
174
|
+
*/
|
|
175
|
+
async callTool(sessionId, toolName, toolArgs) {
|
|
176
|
+
return this.sendRequest("callTool", { sessionId, toolName, toolArgs });
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Refresh/validate a session
|
|
180
|
+
*/
|
|
181
|
+
async restoreSession(sessionId) {
|
|
182
|
+
return this.sendRequest("restoreSession", { sessionId });
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Complete OAuth authorization
|
|
186
|
+
*/
|
|
187
|
+
async finishAuth(sessionId, code) {
|
|
188
|
+
return this.sendRequest("finishAuth", { sessionId, code });
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* List available prompts
|
|
192
|
+
*/
|
|
193
|
+
async listPrompts(sessionId) {
|
|
194
|
+
return this.sendRequest("listPrompts", { sessionId });
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get a specific prompt with arguments
|
|
198
|
+
*/
|
|
199
|
+
async getPrompt(sessionId, name, args) {
|
|
200
|
+
return this.sendRequest("getPrompt", { sessionId, name, args });
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* List available resources
|
|
204
|
+
*/
|
|
205
|
+
async listResources(sessionId) {
|
|
206
|
+
return this.sendRequest("listResources", { sessionId });
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Read a specific resource
|
|
210
|
+
*/
|
|
211
|
+
async readResource(sessionId, uri) {
|
|
212
|
+
return this.sendRequest("readResource", { sessionId, uri });
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Check if connected
|
|
216
|
+
*/
|
|
217
|
+
isConnected() {
|
|
218
|
+
return this.eventSource !== null && this.eventSource.readyState === EventSource.OPEN;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// src/client/vue/useMcp.ts
|
|
223
|
+
function useMcp(options) {
|
|
224
|
+
const {
|
|
225
|
+
url,
|
|
226
|
+
identity,
|
|
227
|
+
authToken,
|
|
228
|
+
autoConnect = true,
|
|
229
|
+
autoInitialize = true,
|
|
230
|
+
onConnectionEvent,
|
|
231
|
+
onLog,
|
|
232
|
+
onRedirect
|
|
233
|
+
} = options;
|
|
234
|
+
const clientRef = shallowRef(null);
|
|
235
|
+
const isMountedRef = ref(true);
|
|
236
|
+
const connections = ref([]);
|
|
237
|
+
const status = ref("disconnected");
|
|
238
|
+
const isInitializing = ref(false);
|
|
239
|
+
const updateConnectionsFromEvent = (event) => {
|
|
240
|
+
if (!isMountedRef.value) return;
|
|
241
|
+
switch (event.type) {
|
|
242
|
+
case "state_changed": {
|
|
243
|
+
const existing = connections.value.find((c) => c.sessionId === event.sessionId);
|
|
244
|
+
if (existing) {
|
|
245
|
+
const index = connections.value.indexOf(existing);
|
|
246
|
+
connections.value[index] = { ...existing, state: event.state };
|
|
247
|
+
} else {
|
|
248
|
+
connections.value = [...connections.value, {
|
|
249
|
+
sessionId: event.sessionId,
|
|
250
|
+
serverId: event.serverId,
|
|
251
|
+
serverName: event.serverName,
|
|
252
|
+
state: event.state,
|
|
253
|
+
tools: []
|
|
254
|
+
}];
|
|
255
|
+
}
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
case "tools_discovered": {
|
|
259
|
+
const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);
|
|
260
|
+
if (index !== -1) {
|
|
261
|
+
connections.value[index] = { ...connections.value[index], tools: event.tools, state: "READY" };
|
|
262
|
+
}
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case "auth_required": {
|
|
266
|
+
if (event.authUrl) {
|
|
267
|
+
onLog?.("info", `OAuth required - redirecting to ${event.authUrl}`, { authUrl: event.authUrl });
|
|
268
|
+
if (onRedirect) {
|
|
269
|
+
onRedirect(event.authUrl);
|
|
270
|
+
} else if (typeof window !== "undefined") {
|
|
271
|
+
window.location.href = event.authUrl;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);
|
|
275
|
+
if (index !== -1) {
|
|
276
|
+
connections.value[index] = { ...connections.value[index], state: "AUTHENTICATING" };
|
|
277
|
+
}
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
case "error": {
|
|
281
|
+
const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);
|
|
282
|
+
if (index !== -1) {
|
|
283
|
+
connections.value[index] = { ...connections.value[index], state: "FAILED", error: event.error };
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
case "disconnected": {
|
|
288
|
+
connections.value = connections.value.filter((c) => c.sessionId !== event.sessionId);
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
const loadSessions = async () => {
|
|
294
|
+
if (!clientRef.value) return;
|
|
295
|
+
try {
|
|
296
|
+
isInitializing.value = true;
|
|
297
|
+
const result = await clientRef.value.getSessions();
|
|
298
|
+
const sessions = result.sessions || [];
|
|
299
|
+
if (isMountedRef.value) {
|
|
300
|
+
connections.value = sessions.map((s) => ({
|
|
301
|
+
sessionId: s.sessionId,
|
|
302
|
+
serverId: s.serverId ?? "unknown",
|
|
303
|
+
serverName: s.serverName ?? "Unknown Server",
|
|
304
|
+
serverUrl: s.serverUrl,
|
|
305
|
+
transport: s.transport,
|
|
306
|
+
state: "VALIDATING",
|
|
307
|
+
tools: []
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
await Promise.all(
|
|
311
|
+
sessions.map(async (session) => {
|
|
312
|
+
if (clientRef.value) {
|
|
313
|
+
try {
|
|
314
|
+
await clientRef.value.restoreSession(session.sessionId);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
})
|
|
320
|
+
);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
console.error("[useMcp] Failed to load sessions:", error);
|
|
323
|
+
onLog?.("error", "Failed to load sessions", { error });
|
|
324
|
+
} finally {
|
|
325
|
+
if (isMountedRef.value) {
|
|
326
|
+
isInitializing.value = false;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
const initClient = () => {
|
|
331
|
+
if (clientRef.value) {
|
|
332
|
+
clientRef.value.disconnect();
|
|
333
|
+
}
|
|
334
|
+
const clientOptions = {
|
|
335
|
+
url,
|
|
336
|
+
identity,
|
|
337
|
+
authToken,
|
|
338
|
+
onConnectionEvent: (event) => {
|
|
339
|
+
updateConnectionsFromEvent(event);
|
|
340
|
+
onConnectionEvent?.(event);
|
|
341
|
+
},
|
|
342
|
+
onObservabilityEvent: (event) => {
|
|
343
|
+
onLog?.(event.level || "info", event.message || event.displayMessage || "No message", event.metadata);
|
|
344
|
+
},
|
|
345
|
+
onStatusChange: (newStatus) => {
|
|
346
|
+
if (isMountedRef.value) {
|
|
347
|
+
status.value = newStatus;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
const client = new SSEClient(clientOptions);
|
|
352
|
+
clientRef.value = client;
|
|
353
|
+
if (autoConnect) {
|
|
354
|
+
client.connect();
|
|
355
|
+
if (autoInitialize) {
|
|
356
|
+
loadSessions();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
onMounted(() => {
|
|
361
|
+
isMountedRef.value = true;
|
|
362
|
+
initClient();
|
|
363
|
+
});
|
|
364
|
+
onUnmounted(() => {
|
|
365
|
+
isMountedRef.value = false;
|
|
366
|
+
clientRef.value?.disconnect();
|
|
367
|
+
});
|
|
368
|
+
const connect = async (params) => {
|
|
369
|
+
if (!clientRef.value) {
|
|
370
|
+
throw new Error("SSE client not initialized");
|
|
371
|
+
}
|
|
372
|
+
const result = await clientRef.value.connectToServer(params);
|
|
373
|
+
return result.sessionId;
|
|
374
|
+
};
|
|
375
|
+
const disconnect = async (sessionId) => {
|
|
376
|
+
if (!clientRef.value) {
|
|
377
|
+
throw new Error("SSE client not initialized");
|
|
378
|
+
}
|
|
379
|
+
await clientRef.value.disconnectFromServer(sessionId);
|
|
380
|
+
if (isMountedRef.value) {
|
|
381
|
+
connections.value = connections.value.filter((c) => c.sessionId !== sessionId);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
const refresh = async () => {
|
|
385
|
+
await loadSessions();
|
|
386
|
+
};
|
|
387
|
+
const connectSSE = () => {
|
|
388
|
+
clientRef.value?.connect();
|
|
389
|
+
};
|
|
390
|
+
const disconnectSSE = () => {
|
|
391
|
+
clientRef.value?.disconnect();
|
|
392
|
+
};
|
|
393
|
+
const finishAuth = async (sessionId, code) => {
|
|
394
|
+
if (!clientRef.value) {
|
|
395
|
+
throw new Error("SSE client not initialized");
|
|
396
|
+
}
|
|
397
|
+
return await clientRef.value.finishAuth(sessionId, code);
|
|
398
|
+
};
|
|
399
|
+
const callTool = async (sessionId, toolName, toolArgs) => {
|
|
400
|
+
if (!clientRef.value) {
|
|
401
|
+
throw new Error("SSE client not initialized");
|
|
402
|
+
}
|
|
403
|
+
return await clientRef.value.callTool(sessionId, toolName, toolArgs);
|
|
404
|
+
};
|
|
405
|
+
const listTools = async (sessionId) => {
|
|
406
|
+
if (!clientRef.value) {
|
|
407
|
+
throw new Error("SSE client not initialized");
|
|
408
|
+
}
|
|
409
|
+
return await clientRef.value.listTools(sessionId);
|
|
410
|
+
};
|
|
411
|
+
const listPrompts = async (sessionId) => {
|
|
412
|
+
if (!clientRef.value) {
|
|
413
|
+
throw new Error("SSE client not initialized");
|
|
414
|
+
}
|
|
415
|
+
return await clientRef.value.listPrompts(sessionId);
|
|
416
|
+
};
|
|
417
|
+
const getPrompt = async (sessionId, name, args) => {
|
|
418
|
+
if (!clientRef.value) {
|
|
419
|
+
throw new Error("SSE client not initialized");
|
|
420
|
+
}
|
|
421
|
+
return await clientRef.value.getPrompt(sessionId, name, args);
|
|
422
|
+
};
|
|
423
|
+
const listResources = async (sessionId) => {
|
|
424
|
+
if (!clientRef.value) {
|
|
425
|
+
throw new Error("SSE client not initialized");
|
|
426
|
+
}
|
|
427
|
+
return await clientRef.value.listResources(sessionId);
|
|
428
|
+
};
|
|
429
|
+
const readResource = async (sessionId, uri) => {
|
|
430
|
+
if (!clientRef.value) {
|
|
431
|
+
throw new Error("SSE client not initialized");
|
|
432
|
+
}
|
|
433
|
+
return await clientRef.value.readResource(sessionId, uri);
|
|
434
|
+
};
|
|
435
|
+
const getConnection = (sessionId) => connections.value.find((c) => c.sessionId === sessionId);
|
|
436
|
+
const getConnectionByServerId = (serverId) => connections.value.find((c) => c.serverId === serverId);
|
|
437
|
+
const isServerConnected = (serverId) => {
|
|
438
|
+
const conn = getConnectionByServerId(serverId);
|
|
439
|
+
return conn?.state === "CONNECTED";
|
|
440
|
+
};
|
|
441
|
+
const getTools = (sessionId) => {
|
|
442
|
+
const conn = getConnection(sessionId);
|
|
443
|
+
return conn?.tools || [];
|
|
444
|
+
};
|
|
445
|
+
return {
|
|
446
|
+
// Return them as Ref objects so they can be destructured and stay reactive
|
|
447
|
+
connections,
|
|
448
|
+
status,
|
|
449
|
+
isInitializing,
|
|
450
|
+
connect,
|
|
451
|
+
disconnect,
|
|
452
|
+
getConnection,
|
|
453
|
+
getConnectionByServerId,
|
|
454
|
+
isServerConnected,
|
|
455
|
+
getTools,
|
|
456
|
+
refresh,
|
|
457
|
+
connectSSE,
|
|
458
|
+
disconnectSSE,
|
|
459
|
+
finishAuth,
|
|
460
|
+
callTool,
|
|
461
|
+
listTools,
|
|
462
|
+
listPrompts,
|
|
463
|
+
getPrompt,
|
|
464
|
+
listResources,
|
|
465
|
+
readResource
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export { SSEClient, useMcp };
|
|
470
|
+
//# sourceMappingURL=vue.mjs.map
|
|
471
|
+
//# sourceMappingURL=vue.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/client/core/sse-client.ts","../../src/client/vue/useMcp.ts"],"names":[],"mappings":"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","file":"vue.mjs","sourcesContent":["/**\r\n * SSE Client for MCP Connections\r\n * Browser-side client that connects to SSE endpoint\r\n */\r\n\r\nimport { nanoid } from 'nanoid';\r\nimport type { McpConnectionEvent, McpObservabilityEvent } from '../../shared/events';\r\nimport type {\r\n McpRpcRequest,\r\n McpRpcResponse,\r\n McpRpcMethod,\r\n McpRpcParams,\r\n ConnectParams,\r\n SessionListResult,\r\n ConnectResult,\r\n DisconnectResult,\r\n RestoreSessionResult,\r\n FinishAuthResult,\r\n ListToolsRpcResult,\r\n ListPromptsResult,\r\n ListResourcesResult,\r\n} from '../../shared/types';\r\n\r\nexport interface SSEClientOptions {\r\n /**\r\n * SSE endpoint URL\r\n */\r\n url: string;\r\n\r\n /**\r\n * User/Client identifier\r\n */\r\n identity: string;\r\n\r\n /**\r\n * Optional auth token\r\n */\r\n authToken?: string;\r\n\r\n /**\r\n * Connection event callback\r\n */\r\n onConnectionEvent?: (event: McpConnectionEvent) => void;\r\n\r\n /**\r\n * Observability event callback\r\n */\r\n onObservabilityEvent?: (event: McpObservabilityEvent) => void;\r\n\r\n /**\r\n * Connection status callback\r\n */\r\n onStatusChange?: (status: 'connecting' | 'connected' | 'disconnected' | 'error') => void;\r\n}\r\n\r\n/**\r\n * SSE Client for real-time MCP connection management\r\n */\r\nexport class SSEClient {\r\n private eventSource: EventSource | null = null;\r\n private pendingRequests: Map<\r\n string,\r\n { resolve: (value: unknown) => void; reject: (error: Error) => void }\r\n > = new Map();\r\n private reconnectAttempts: number = 0;\r\n private maxReconnectAttempts: number = 5;\r\n private reconnectDelay: number = 1000;\r\n private isManuallyDisconnected: boolean = false;\r\n private connectionPromise: Promise<void> | null = null;\r\n private connectionResolver: (() => void) | null = null;\r\n\r\n constructor(private options: SSEClientOptions) { }\r\n\r\n /**\r\n * Connect to SSE endpoint\r\n */\r\n connect(): void {\r\n if (this.eventSource) {\r\n return; // Already connected\r\n }\r\n\r\n this.isManuallyDisconnected = false;\r\n this.options.onStatusChange?.('connecting');\r\n\r\n // Create connection promise\r\n this.connectionPromise = new Promise((resolve) => {\r\n this.connectionResolver = resolve;\r\n });\r\n\r\n // Build URL with query params\r\n // Handle both relative and absolute URLs\r\n const url = new URL(this.options.url, typeof window !== 'undefined' ? window.location.origin : undefined);\r\n url.searchParams.set('identity', this.options.identity);\r\n if (this.options.authToken) {\r\n url.searchParams.set('token', this.options.authToken);\r\n }\r\n\r\n // Create EventSource\r\n this.eventSource = new EventSource(url.toString());\r\n\r\n // Handle connection open\r\n this.eventSource.addEventListener('open', () => {\r\n console.log('[SSEClient] Connected');\r\n this.reconnectAttempts = 0;\r\n this.options.onStatusChange?.('connected');\r\n });\r\n\r\n // Handle 'connected' event - server confirms manager is ready\r\n this.eventSource.addEventListener('connected', (e: MessageEvent) => {\r\n const data = JSON.parse(e.data);\r\n console.log('[SSEClient] Server ready:', data);\r\n\r\n // Resolve connection promise - now safe to send requests\r\n if (this.connectionResolver) {\r\n this.connectionResolver();\r\n this.connectionResolver = null;\r\n }\r\n });\r\n\r\n // Handle 'connection' events (MCP connection state changes)\r\n this.eventSource.addEventListener('connection', (e: MessageEvent) => {\r\n const event: McpConnectionEvent = JSON.parse(e.data);\r\n this.options.onConnectionEvent?.(event);\r\n });\r\n\r\n // Handle 'observability' events (debugging/logging)\r\n this.eventSource.addEventListener('observability', (e: MessageEvent) => {\r\n const event: McpObservabilityEvent = JSON.parse(e.data);\r\n this.options.onObservabilityEvent?.(event);\r\n });\r\n\r\n // Handle 'rpc-response' events (RPC method responses)\r\n this.eventSource.addEventListener('rpc-response', (e: MessageEvent) => {\r\n const response: McpRpcResponse = JSON.parse(e.data);\r\n this.handleRpcResponse(response);\r\n });\r\n\r\n // Handle errors\r\n this.eventSource.addEventListener('error', () => {\r\n console.error('[SSEClient] Connection error');\r\n this.options.onStatusChange?.('error');\r\n\r\n // Attempt reconnection\r\n if (!this.isManuallyDisconnected && this.reconnectAttempts < this.maxReconnectAttempts) {\r\n this.reconnectAttempts++;\r\n console.log(`[SSEClient] Reconnecting (attempt ${this.reconnectAttempts})...`);\r\n\r\n setTimeout(() => {\r\n this.disconnect();\r\n this.connect();\r\n }, this.reconnectDelay * this.reconnectAttempts);\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Disconnect from SSE endpoint\r\n */\r\n disconnect(): void {\r\n this.isManuallyDisconnected = true;\r\n\r\n if (this.eventSource) {\r\n this.eventSource.close();\r\n this.eventSource = null;\r\n }\r\n\r\n // Reset connection promise\r\n this.connectionPromise = null;\r\n this.connectionResolver = null;\r\n\r\n // Reject all pending requests with a specific error type\r\n for (const [id, { reject }] of this.pendingRequests.entries()) {\r\n const error = new Error('Connection closed');\r\n error.name = 'ConnectionClosedError';\r\n reject(error);\r\n }\r\n this.pendingRequests.clear();\r\n\r\n this.options.onStatusChange?.('disconnected');\r\n }\r\n\r\n /**\r\n * Send RPC request via SSE\r\n * Note: SSE is unidirectional (server->client), so we need to send requests via POST\r\n */\r\n private async sendRequest<T = unknown>(method: McpRpcMethod, params?: McpRpcParams): Promise<T> {\r\n // Wait for connection to be fully established\r\n if (this.connectionPromise) {\r\n await this.connectionPromise;\r\n }\r\n\r\n // Generate unique request ID using nanoid (e.g., \"rpc_V1StGXR8_Z5jdHi\")\r\n const id = `rpc_${nanoid(10)}`;\r\n\r\n const request: McpRpcRequest = {\r\n id,\r\n method,\r\n params,\r\n };\r\n\r\n // Create promise for response\r\n const promise = new Promise<T>((resolve, reject) => {\r\n this.pendingRequests.set(id, { resolve: resolve as (value: unknown) => void, reject });\r\n\r\n // Timeout after 30 seconds\r\n setTimeout(() => {\r\n if (this.pendingRequests.has(id)) {\r\n this.pendingRequests.delete(id);\r\n reject(new Error('Request timeout'));\r\n }\r\n }, 30000);\r\n });\r\n\r\n // Send request via POST to same endpoint\r\n try {\r\n // Handle both relative and absolute URLs\r\n const url = new URL(this.options.url, typeof window !== 'undefined' ? window.location.origin : undefined);\r\n url.searchParams.set('identity', this.options.identity);\r\n\r\n await fetch(url.toString(), {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...(this.options.authToken && { Authorization: `Bearer ${this.options.authToken}` }),\r\n },\r\n body: JSON.stringify(request),\r\n });\r\n } catch (error) {\r\n this.pendingRequests.delete(id);\r\n throw error;\r\n }\r\n\r\n return promise;\r\n }\r\n\r\n /**\r\n * Handle RPC response\r\n */\r\n private handleRpcResponse(response: McpRpcResponse): void {\r\n const pending = this.pendingRequests.get(response.id);\r\n\r\n if (pending) {\r\n this.pendingRequests.delete(response.id);\r\n\r\n if (response.error) {\r\n pending.reject(new Error(response.error.message));\r\n } else {\r\n pending.resolve(response.result);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Get all user sessions\r\n */\r\n async getSessions(): Promise<SessionListResult> {\r\n return this.sendRequest<SessionListResult>('getSessions');\r\n }\r\n\r\n /**\r\n * Connect to an MCP server\r\n */\r\n async connectToServer(params: ConnectParams): Promise<ConnectResult> {\r\n return this.sendRequest<ConnectResult>('connect', params);\r\n }\r\n\r\n /**\r\n * Disconnect from an MCP server\r\n */\r\n async disconnectFromServer(sessionId: string): Promise<DisconnectResult> {\r\n return this.sendRequest<DisconnectResult>('disconnect', { sessionId });\r\n }\r\n\r\n /**\r\n * List tools from a session\r\n */\r\n async listTools(sessionId: string): Promise<ListToolsRpcResult> {\r\n return this.sendRequest<ListToolsRpcResult>('listTools', { sessionId });\r\n }\r\n\r\n /**\r\n * Call a tool\r\n */\r\n async callTool(\r\n sessionId: string,\r\n toolName: string,\r\n toolArgs: Record<string, unknown>\r\n ): Promise<unknown> {\r\n return this.sendRequest('callTool', { sessionId, toolName, toolArgs });\r\n }\r\n\r\n /**\r\n * Refresh/validate a session\r\n */\r\n async restoreSession(sessionId: string): Promise<RestoreSessionResult> {\r\n return this.sendRequest<RestoreSessionResult>('restoreSession', { sessionId });\r\n }\r\n\r\n /**\r\n * Complete OAuth authorization\r\n */\r\n async finishAuth(sessionId: string, code: string): Promise<FinishAuthResult> {\r\n return this.sendRequest<FinishAuthResult>('finishAuth', { sessionId, code });\r\n }\r\n\r\n /**\r\n * List available prompts\r\n */\r\n async listPrompts(sessionId: string): Promise<ListPromptsResult> {\r\n return this.sendRequest<ListPromptsResult>('listPrompts', { sessionId });\r\n }\r\n\r\n /**\r\n * Get a specific prompt with arguments\r\n */\r\n async getPrompt(sessionId: string, name: string, args?: Record<string, string>): Promise<unknown> {\r\n return this.sendRequest('getPrompt', { sessionId, name, args });\r\n }\r\n\r\n /**\r\n * List available resources\r\n */\r\n async listResources(sessionId: string): Promise<ListResourcesResult> {\r\n return this.sendRequest<ListResourcesResult>('listResources', { sessionId });\r\n }\r\n\r\n /**\r\n * Read a specific resource\r\n */\r\n async readResource(sessionId: string, uri: string): Promise<unknown> {\r\n return this.sendRequest('readResource', { sessionId, uri });\r\n }\r\n\r\n /**\r\n * Check if connected\r\n */\r\n isConnected(): boolean {\r\n return this.eventSource !== null && this.eventSource.readyState === EventSource.OPEN;\r\n }\r\n}\r\n","/**\r\n * useMcp Vue Composable\r\n * Manages MCP connections with SSE-based real-time updates\r\n * Based on Cloudflare's agents pattern\r\n */\r\n\r\nimport { ref, onMounted, onUnmounted, watch, computed, shallowRef } from 'vue';\r\nimport { SSEClient, type SSEClientOptions } from '../core/sse-client';\r\nimport type { McpConnectionEvent, McpConnectionState } from '../../shared/events';\r\nimport type {\r\n ToolInfo,\r\n FinishAuthResult,\r\n ListToolsRpcResult,\r\n ListPromptsResult,\r\n ListResourcesResult,\r\n SessionInfo,\r\n} from '../../shared/types';\r\n\r\nexport interface UseMcpOptions {\r\n /**\r\n * SSE endpoint URL\r\n */\r\n url: string;\r\n\r\n /**\r\n * User/Client identifier\r\n */\r\n identity: string;\r\n\r\n /**\r\n * Optional auth token\r\n */\r\n authToken?: string;\r\n\r\n /**\r\n * Auto-connect on mount\r\n * @default true\r\n */\r\n autoConnect?: boolean;\r\n\r\n /**\r\n * Auto-initialize sessions on mount\r\n * @default true\r\n */\r\n autoInitialize?: boolean;\r\n\r\n /**\r\n * Connection event callback\r\n */\r\n onConnectionEvent?: (event: McpConnectionEvent) => void;\r\n\r\n /**\r\n * Debug logging callback\r\n */\r\n onLog?: (level: string, message: string, metadata?: Record<string, unknown>) => void;\r\n /**\r\n * Optional callback to handle OAuth redirects (e.g. for popup flow)\r\n * If provided, this will be called instead of window.location.href assignment\r\n */\r\n onRedirect?: (url: string) => void;\r\n}\r\n\r\nexport interface McpConnection {\r\n sessionId: string;\r\n serverId: string;\r\n serverName: string;\r\n serverUrl?: string;\r\n transport?: string;\r\n state: McpConnectionState;\r\n tools: ToolInfo[];\r\n error?: string;\r\n connectedAt?: Date;\r\n}\r\n\r\nexport interface McpClient {\r\n /**\r\n * All connections (Represents a Reactive Ref)\r\n */\r\n connections: { value: McpConnection[] };\r\n\r\n /**\r\n * SSE connection status (Represents a Reactive Ref)\r\n */\r\n status: { value: 'connecting' | 'connected' | 'disconnected' | 'error' };\r\n\r\n /**\r\n * Whether initializing (Represents a Reactive Ref)\r\n */\r\n isInitializing: { value: boolean };\r\n\r\n /**\r\n * Connect to an MCP server\r\n */\r\n connect: (params: {\r\n serverId: string;\r\n serverName: string;\r\n serverUrl: string;\r\n callbackUrl: string;\r\n transportType?: 'sse' | 'streamable_http';\r\n }) => Promise<string>;\r\n\r\n /**\r\n * Disconnect from an MCP server\r\n */\r\n disconnect: (sessionId: string) => Promise<void>;\r\n\r\n /**\r\n * Get connection by session ID\r\n */\r\n getConnection: (sessionId: string) => McpConnection | undefined;\r\n\r\n /**\r\n * Get connection by server ID\r\n */\r\n getConnectionByServerId: (serverId: string) => McpConnection | undefined;\r\n\r\n /**\r\n * Check if server is connected\r\n */\r\n isServerConnected: (serverId: string) => boolean;\r\n\r\n /**\r\n * Get tools for a session\r\n */\r\n getTools: (sessionId: string) => ToolInfo[];\r\n\r\n /**\r\n * Refresh all connections\r\n */\r\n refresh: () => Promise<void>;\r\n\r\n /**\r\n * Manually connect SSE\r\n */\r\n connectSSE: () => void;\r\n\r\n /**\r\n * Manually disconnect SSE\r\n */\r\n disconnectSSE: () => void;\r\n\r\n /**\r\n * Complete OAuth authorization\r\n */\r\n finishAuth: (sessionId: string, code: string) => Promise<FinishAuthResult>;\r\n\r\n /**\r\n * Call a tool from a session\r\n */\r\n callTool: (\r\n sessionId: string,\r\n toolName: string,\r\n toolArgs: Record<string, unknown>\r\n ) => Promise<unknown>;\r\n\r\n /**\r\n * List available tools for a session\r\n */\r\n listTools: (sessionId: string) => Promise<ListToolsRpcResult>;\r\n\r\n /**\r\n * List available prompts for a session\r\n */\r\n listPrompts: (sessionId: string) => Promise<ListPromptsResult>;\r\n\r\n /**\r\n * Get a specific prompt with arguments\r\n */\r\n getPrompt: (sessionId: string, name: string, args?: Record<string, string>) => Promise<unknown>;\r\n\r\n /**\r\n * List available resources for a session\r\n */\r\n listResources: (sessionId: string) => Promise<ListResourcesResult>;\r\n\r\n /**\r\n * Read a specific resource\r\n */\r\n readResource: (sessionId: string, uri: string) => Promise<unknown>;\r\n}\r\n\r\n/**\r\n * Vue Composable for MCP connection management with SSE\r\n */\r\nexport function useMcp(options: UseMcpOptions): McpClient {\r\n const {\r\n url,\r\n identity,\r\n authToken,\r\n autoConnect = true,\r\n autoInitialize = true,\r\n onConnectionEvent,\r\n onLog,\r\n onRedirect,\r\n } = options;\r\n\r\n // Use shallowRef for client instance as it doesn't need deep reactivity\r\n const clientRef = shallowRef<SSEClient | null>(null);\r\n const isMountedRef = ref(true);\r\n\r\n const connections = ref<McpConnection[]>([]);\r\n const status = ref<'connecting' | 'connected' | 'disconnected' | 'error'>('disconnected');\r\n const isInitializing = ref(false);\r\n\r\n /**\r\n * Update connections based on event\r\n */\r\n const updateConnectionsFromEvent = (event: McpConnectionEvent) => {\r\n if (!isMountedRef.value) return;\r\n\r\n switch (event.type) {\r\n case 'state_changed': {\r\n const existing = connections.value.find((c) => c.sessionId === event.sessionId);\r\n if (existing) {\r\n const index = connections.value.indexOf(existing);\r\n connections.value[index] = { ...existing, state: event.state };\r\n } else {\r\n connections.value = [...connections.value, {\r\n sessionId: event.sessionId,\r\n serverId: event.serverId,\r\n serverName: event.serverName,\r\n state: event.state,\r\n tools: [],\r\n }];\r\n }\r\n break;\r\n }\r\n\r\n case 'tools_discovered': {\r\n const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);\r\n if (index !== -1) {\r\n connections.value[index] = { ...connections.value[index], tools: event.tools, state: 'READY' };\r\n }\r\n break;\r\n }\r\n\r\n case 'auth_required': {\r\n // Handle OAuth redirect\r\n if (event.authUrl) {\r\n onLog?.('info', `OAuth required - redirecting to ${event.authUrl}`, { authUrl: event.authUrl });\r\n\r\n if (onRedirect) {\r\n onRedirect(event.authUrl);\r\n } else if (typeof window !== 'undefined') {\r\n window.location.href = event.authUrl;\r\n }\r\n }\r\n const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);\r\n if (index !== -1) {\r\n connections.value[index] = { ...connections.value[index], state: 'AUTHENTICATING' };\r\n }\r\n break;\r\n }\r\n\r\n case 'error': {\r\n const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);\r\n if (index !== -1) {\r\n connections.value[index] = { ...connections.value[index], state: 'FAILED', error: event.error };\r\n }\r\n break;\r\n }\r\n\r\n case 'disconnected': {\r\n connections.value = connections.value.filter((c) => c.sessionId !== event.sessionId);\r\n break;\r\n }\r\n }\r\n };\r\n\r\n /**\r\n * Load sessions from server\r\n */\r\n const loadSessions = async () => {\r\n if (!clientRef.value) return;\r\n\r\n try {\r\n isInitializing.value = true;\r\n\r\n const result = await clientRef.value.getSessions();\r\n const sessions = result.sessions || [];\r\n\r\n // Initialize connections\r\n if (isMountedRef.value) {\r\n connections.value = sessions.map((s: SessionInfo) => ({\r\n sessionId: s.sessionId,\r\n serverId: s.serverId ?? 'unknown',\r\n serverName: s.serverName ?? 'Unknown Server',\r\n serverUrl: s.serverUrl,\r\n transport: s.transport,\r\n state: 'VALIDATING' as McpConnectionState,\r\n tools: [],\r\n }));\r\n }\r\n\r\n // Validate each session in parallel\r\n await Promise.all(\r\n sessions.map(async (session: SessionInfo) => {\r\n if (clientRef.value) {\r\n try {\r\n await clientRef.value.restoreSession(session.sessionId);\r\n } catch (error) {\r\n console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);\r\n }\r\n }\r\n })\r\n );\r\n } catch (error) {\r\n console.error('[useMcp] Failed to load sessions:', error);\r\n onLog?.('error', 'Failed to load sessions', { error });\r\n } finally {\r\n if (isMountedRef.value) {\r\n isInitializing.value = false;\r\n }\r\n }\r\n };\r\n\r\n /**\r\n * Initialize SSE client\r\n */\r\n const initClient = () => {\r\n // Disconnect existing if any\r\n if (clientRef.value) {\r\n clientRef.value.disconnect();\r\n }\r\n\r\n const clientOptions: SSEClientOptions = {\r\n url,\r\n identity,\r\n authToken,\r\n onConnectionEvent: (event) => {\r\n // Update local state based on event\r\n updateConnectionsFromEvent(event);\r\n\r\n // Call user callback\r\n onConnectionEvent?.(event);\r\n },\r\n onObservabilityEvent: (event) => {\r\n onLog?.(event.level || 'info', event.message || event.displayMessage || 'No message', event.metadata);\r\n },\r\n onStatusChange: (newStatus) => {\r\n if (isMountedRef.value) {\r\n status.value = newStatus;\r\n }\r\n },\r\n };\r\n\r\n const client = new SSEClient(clientOptions);\r\n clientRef.value = client;\r\n\r\n if (autoConnect) {\r\n client.connect();\r\n\r\n if (autoInitialize) {\r\n loadSessions();\r\n }\r\n }\r\n };\r\n\r\n onMounted(() => {\r\n isMountedRef.value = true;\r\n initClient();\r\n });\r\n\r\n onUnmounted(() => {\r\n isMountedRef.value = false;\r\n clientRef.value?.disconnect();\r\n });\r\n\r\n /**\r\n * Connect to an MCP server\r\n */\r\n const connect = async (params: {\r\n serverId: string;\r\n serverName: string;\r\n serverUrl: string;\r\n callbackUrl: string;\r\n transportType?: 'sse' | 'streamable_http';\r\n }): Promise<string> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n const result = await clientRef.value.connectToServer(params);\r\n return result.sessionId;\r\n };\r\n\r\n /**\r\n * Disconnect from an MCP server\r\n */\r\n const disconnect = async (sessionId: string): Promise<void> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n await clientRef.value.disconnectFromServer(sessionId);\r\n\r\n // Remove from local state\r\n if (isMountedRef.value) {\r\n connections.value = connections.value.filter((c) => c.sessionId !== sessionId);\r\n }\r\n };\r\n\r\n /**\r\n * Refresh all connections\r\n */\r\n const refresh = async () => {\r\n await loadSessions();\r\n };\r\n\r\n /**\r\n * Manually connect SSE\r\n */\r\n const connectSSE = () => {\r\n clientRef.value?.connect();\r\n };\r\n\r\n /**\r\n * Manually disconnect SSE\r\n */\r\n const disconnectSSE = () => {\r\n clientRef.value?.disconnect();\r\n };\r\n\r\n /**\r\n * Complete OAuth authorization\r\n */\r\n const finishAuth = async (sessionId: string, code: string): Promise<FinishAuthResult> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.finishAuth(sessionId, code);\r\n };\r\n\r\n /**\r\n * Call a tool\r\n */\r\n const callTool = async (\r\n sessionId: string,\r\n toolName: string,\r\n toolArgs: Record<string, unknown>\r\n ): Promise<unknown> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.callTool(sessionId, toolName, toolArgs);\r\n };\r\n\r\n /**\r\n * List tools (refresh tool list)\r\n */\r\n const listTools = async (sessionId: string): Promise<ListToolsRpcResult> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.listTools(sessionId);\r\n };\r\n\r\n /**\r\n * List prompts\r\n */\r\n const listPrompts = async (sessionId: string): Promise<ListPromptsResult> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.listPrompts(sessionId);\r\n };\r\n\r\n /**\r\n * Get a specific prompt\r\n */\r\n const getPrompt = async (sessionId: string, name: string, args?: Record<string, string>): Promise<unknown> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.getPrompt(sessionId, name, args);\r\n };\r\n\r\n /**\r\n * List resources\r\n */\r\n const listResources = async (sessionId: string): Promise<ListResourcesResult> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.listResources(sessionId);\r\n };\r\n\r\n /**\r\n * Read a specific resource\r\n */\r\n const readResource = async (sessionId: string, uri: string): Promise<unknown> => {\r\n if (!clientRef.value) {\r\n throw new Error('SSE client not initialized');\r\n }\r\n\r\n return await clientRef.value.readResource(sessionId, uri);\r\n };\r\n\r\n // Utility functions\r\n const getConnection = (sessionId: string) => connections.value.find((c) => c.sessionId === sessionId);\r\n\r\n const getConnectionByServerId = (serverId: string) => connections.value.find((c) => c.serverId === serverId);\r\n\r\n const isServerConnected = (serverId: string) => {\r\n const conn = getConnectionByServerId(serverId);\r\n return conn?.state === 'CONNECTED';\r\n };\r\n\r\n const getTools = (sessionId: string) => {\r\n const conn = getConnection(sessionId);\r\n return conn?.tools || [];\r\n };\r\n\r\n return {\r\n // Return them as Ref objects so they can be destructured and stay reactive\r\n connections: connections as unknown as { value: McpConnection[] },\r\n status: status as unknown as { value: 'connecting' | 'connected' | 'disconnected' | 'error' },\r\n isInitializing: isInitializing as unknown as { value: boolean },\r\n connect,\r\n disconnect,\r\n getConnection,\r\n getConnectionByServerId,\r\n isServerConnected,\r\n getTools,\r\n refresh,\r\n connectSSE,\r\n disconnectSSE,\r\n finishAuth,\r\n callTool,\r\n listTools,\r\n listPrompts,\r\n getPrompt,\r\n listResources,\r\n readResource,\r\n };\r\n}\r\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple event emitter pattern for MCP connection events
|
|
3
|
+
* Inspired by Cloudflare's agents pattern but adapted for serverless
|
|
4
|
+
*/
|
|
5
|
+
type Disposable = {
|
|
6
|
+
dispose(): void;
|
|
7
|
+
};
|
|
8
|
+
type Event<T> = (listener: (event: T) => void) => Disposable;
|
|
9
|
+
/**
|
|
10
|
+
* Event emitter class for type-safe event handling
|
|
11
|
+
* Similar to Cloudflare's Emitter but simplified for our use case
|
|
12
|
+
*/
|
|
13
|
+
declare class Emitter<T> {
|
|
14
|
+
private listeners;
|
|
15
|
+
/**
|
|
16
|
+
* Subscribe to events
|
|
17
|
+
* @param listener - Callback function to handle events
|
|
18
|
+
* @returns Disposable to unsubscribe
|
|
19
|
+
*/
|
|
20
|
+
get event(): Event<T>;
|
|
21
|
+
/**
|
|
22
|
+
* Fire an event to all listeners
|
|
23
|
+
* @param event - Event data to emit
|
|
24
|
+
*/
|
|
25
|
+
fire(event: T): void;
|
|
26
|
+
/**
|
|
27
|
+
* Clear all listeners
|
|
28
|
+
*/
|
|
29
|
+
dispose(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get number of active listeners
|
|
32
|
+
*/
|
|
33
|
+
get listenerCount(): number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Connection state types matching your existing ConnectionStatus
|
|
37
|
+
* Extended with more granular states for better observability
|
|
38
|
+
*/
|
|
39
|
+
type McpConnectionState = 'DISCONNECTED' | 'CONNECTING' | 'AUTHENTICATING' | 'AUTHENTICATED' | 'DISCOVERING' | 'CONNECTED' | 'READY' | 'VALIDATING' | 'RECONNECTING' | 'INITIALIZING' | 'FAILED';
|
|
40
|
+
/**
|
|
41
|
+
* MCP Connection Event Types
|
|
42
|
+
* Discriminated union for type-safe event handling
|
|
43
|
+
*/
|
|
44
|
+
type McpConnectionEvent = {
|
|
45
|
+
type: 'state_changed';
|
|
46
|
+
sessionId: string;
|
|
47
|
+
serverId: string;
|
|
48
|
+
serverName: string;
|
|
49
|
+
state: McpConnectionState;
|
|
50
|
+
previousState: McpConnectionState;
|
|
51
|
+
timestamp: number;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'tools_discovered';
|
|
54
|
+
sessionId: string;
|
|
55
|
+
serverId: string;
|
|
56
|
+
toolCount: number;
|
|
57
|
+
tools: any[];
|
|
58
|
+
timestamp: number;
|
|
59
|
+
} | {
|
|
60
|
+
type: 'auth_required';
|
|
61
|
+
sessionId: string;
|
|
62
|
+
serverId: string;
|
|
63
|
+
authUrl: string;
|
|
64
|
+
timestamp: number;
|
|
65
|
+
} | {
|
|
66
|
+
type: 'error';
|
|
67
|
+
sessionId: string;
|
|
68
|
+
serverId: string;
|
|
69
|
+
error: string;
|
|
70
|
+
errorType: 'connection' | 'auth' | 'validation' | 'unknown';
|
|
71
|
+
timestamp: number;
|
|
72
|
+
} | {
|
|
73
|
+
type: 'disconnected';
|
|
74
|
+
sessionId: string;
|
|
75
|
+
serverId: string;
|
|
76
|
+
reason?: string;
|
|
77
|
+
timestamp: number;
|
|
78
|
+
} | {
|
|
79
|
+
type: 'progress';
|
|
80
|
+
sessionId: string;
|
|
81
|
+
serverId: string;
|
|
82
|
+
message: string;
|
|
83
|
+
timestamp: number;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Observability event for debugging and monitoring
|
|
87
|
+
*/
|
|
88
|
+
interface McpObservabilityEvent {
|
|
89
|
+
type?: string;
|
|
90
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
91
|
+
message?: string;
|
|
92
|
+
displayMessage?: string;
|
|
93
|
+
sessionId?: string;
|
|
94
|
+
serverId?: string;
|
|
95
|
+
payload?: Record<string, any>;
|
|
96
|
+
metadata?: Record<string, any>;
|
|
97
|
+
timestamp: number;
|
|
98
|
+
id?: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* DisposableStore for managing multiple disposables
|
|
102
|
+
* Useful for cleanup in React hooks
|
|
103
|
+
*/
|
|
104
|
+
declare class DisposableStore {
|
|
105
|
+
private disposables;
|
|
106
|
+
add(disposable: Disposable): void;
|
|
107
|
+
dispose(): void;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { type Disposable as D, Emitter as E, type McpConnectionEvent as M, DisposableStore as a, type Event as b, type McpConnectionState as c, type McpObservabilityEvent as d };
|