@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,542 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useMcp Vue Composable
|
|
3
|
+
* Manages MCP connections with SSE-based real-time updates
|
|
4
|
+
* Based on Cloudflare's agents pattern
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ref, onMounted, onUnmounted, watch, computed, shallowRef } from 'vue';
|
|
8
|
+
import { SSEClient, type SSEClientOptions } from '../core/sse-client';
|
|
9
|
+
import type { McpConnectionEvent, McpConnectionState } from '../../shared/events';
|
|
10
|
+
import type {
|
|
11
|
+
ToolInfo,
|
|
12
|
+
FinishAuthResult,
|
|
13
|
+
ListToolsRpcResult,
|
|
14
|
+
ListPromptsResult,
|
|
15
|
+
ListResourcesResult,
|
|
16
|
+
SessionInfo,
|
|
17
|
+
} from '../../shared/types';
|
|
18
|
+
|
|
19
|
+
export interface UseMcpOptions {
|
|
20
|
+
/**
|
|
21
|
+
* SSE endpoint URL
|
|
22
|
+
*/
|
|
23
|
+
url: string;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* User/Client identifier
|
|
27
|
+
*/
|
|
28
|
+
identity: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Optional auth token
|
|
32
|
+
*/
|
|
33
|
+
authToken?: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Auto-connect on mount
|
|
37
|
+
* @default true
|
|
38
|
+
*/
|
|
39
|
+
autoConnect?: boolean;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Auto-initialize sessions on mount
|
|
43
|
+
* @default true
|
|
44
|
+
*/
|
|
45
|
+
autoInitialize?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Connection event callback
|
|
49
|
+
*/
|
|
50
|
+
onConnectionEvent?: (event: McpConnectionEvent) => void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Debug logging callback
|
|
54
|
+
*/
|
|
55
|
+
onLog?: (level: string, message: string, metadata?: Record<string, unknown>) => void;
|
|
56
|
+
/**
|
|
57
|
+
* Optional callback to handle OAuth redirects (e.g. for popup flow)
|
|
58
|
+
* If provided, this will be called instead of window.location.href assignment
|
|
59
|
+
*/
|
|
60
|
+
onRedirect?: (url: string) => void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface McpConnection {
|
|
64
|
+
sessionId: string;
|
|
65
|
+
serverId: string;
|
|
66
|
+
serverName: string;
|
|
67
|
+
serverUrl?: string;
|
|
68
|
+
transport?: string;
|
|
69
|
+
state: McpConnectionState;
|
|
70
|
+
tools: ToolInfo[];
|
|
71
|
+
error?: string;
|
|
72
|
+
connectedAt?: Date;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface McpClient {
|
|
76
|
+
/**
|
|
77
|
+
* All connections (Represents a Reactive Ref)
|
|
78
|
+
*/
|
|
79
|
+
connections: { value: McpConnection[] };
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* SSE connection status (Represents a Reactive Ref)
|
|
83
|
+
*/
|
|
84
|
+
status: { value: 'connecting' | 'connected' | 'disconnected' | 'error' };
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Whether initializing (Represents a Reactive Ref)
|
|
88
|
+
*/
|
|
89
|
+
isInitializing: { value: boolean };
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Connect to an MCP server
|
|
93
|
+
*/
|
|
94
|
+
connect: (params: {
|
|
95
|
+
serverId: string;
|
|
96
|
+
serverName: string;
|
|
97
|
+
serverUrl: string;
|
|
98
|
+
callbackUrl: string;
|
|
99
|
+
transportType?: 'sse' | 'streamable_http';
|
|
100
|
+
}) => Promise<string>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Disconnect from an MCP server
|
|
104
|
+
*/
|
|
105
|
+
disconnect: (sessionId: string) => Promise<void>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get connection by session ID
|
|
109
|
+
*/
|
|
110
|
+
getConnection: (sessionId: string) => McpConnection | undefined;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get connection by server ID
|
|
114
|
+
*/
|
|
115
|
+
getConnectionByServerId: (serverId: string) => McpConnection | undefined;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if server is connected
|
|
119
|
+
*/
|
|
120
|
+
isServerConnected: (serverId: string) => boolean;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get tools for a session
|
|
124
|
+
*/
|
|
125
|
+
getTools: (sessionId: string) => ToolInfo[];
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Refresh all connections
|
|
129
|
+
*/
|
|
130
|
+
refresh: () => Promise<void>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Manually connect SSE
|
|
134
|
+
*/
|
|
135
|
+
connectSSE: () => void;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Manually disconnect SSE
|
|
139
|
+
*/
|
|
140
|
+
disconnectSSE: () => void;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Complete OAuth authorization
|
|
144
|
+
*/
|
|
145
|
+
finishAuth: (sessionId: string, code: string) => Promise<FinishAuthResult>;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Call a tool from a session
|
|
149
|
+
*/
|
|
150
|
+
callTool: (
|
|
151
|
+
sessionId: string,
|
|
152
|
+
toolName: string,
|
|
153
|
+
toolArgs: Record<string, unknown>
|
|
154
|
+
) => Promise<unknown>;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* List available tools for a session
|
|
158
|
+
*/
|
|
159
|
+
listTools: (sessionId: string) => Promise<ListToolsRpcResult>;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* List available prompts for a session
|
|
163
|
+
*/
|
|
164
|
+
listPrompts: (sessionId: string) => Promise<ListPromptsResult>;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get a specific prompt with arguments
|
|
168
|
+
*/
|
|
169
|
+
getPrompt: (sessionId: string, name: string, args?: Record<string, string>) => Promise<unknown>;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* List available resources for a session
|
|
173
|
+
*/
|
|
174
|
+
listResources: (sessionId: string) => Promise<ListResourcesResult>;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Read a specific resource
|
|
178
|
+
*/
|
|
179
|
+
readResource: (sessionId: string, uri: string) => Promise<unknown>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Vue Composable for MCP connection management with SSE
|
|
184
|
+
*/
|
|
185
|
+
export function useMcp(options: UseMcpOptions): McpClient {
|
|
186
|
+
const {
|
|
187
|
+
url,
|
|
188
|
+
identity,
|
|
189
|
+
authToken,
|
|
190
|
+
autoConnect = true,
|
|
191
|
+
autoInitialize = true,
|
|
192
|
+
onConnectionEvent,
|
|
193
|
+
onLog,
|
|
194
|
+
onRedirect,
|
|
195
|
+
} = options;
|
|
196
|
+
|
|
197
|
+
// Use shallowRef for client instance as it doesn't need deep reactivity
|
|
198
|
+
const clientRef = shallowRef<SSEClient | null>(null);
|
|
199
|
+
const isMountedRef = ref(true);
|
|
200
|
+
|
|
201
|
+
const connections = ref<McpConnection[]>([]);
|
|
202
|
+
const status = ref<'connecting' | 'connected' | 'disconnected' | 'error'>('disconnected');
|
|
203
|
+
const isInitializing = ref(false);
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Update connections based on event
|
|
207
|
+
*/
|
|
208
|
+
const updateConnectionsFromEvent = (event: McpConnectionEvent) => {
|
|
209
|
+
if (!isMountedRef.value) return;
|
|
210
|
+
|
|
211
|
+
switch (event.type) {
|
|
212
|
+
case 'state_changed': {
|
|
213
|
+
const existing = connections.value.find((c) => c.sessionId === event.sessionId);
|
|
214
|
+
if (existing) {
|
|
215
|
+
const index = connections.value.indexOf(existing);
|
|
216
|
+
connections.value[index] = { ...existing, state: event.state };
|
|
217
|
+
} else {
|
|
218
|
+
connections.value = [...connections.value, {
|
|
219
|
+
sessionId: event.sessionId,
|
|
220
|
+
serverId: event.serverId,
|
|
221
|
+
serverName: event.serverName,
|
|
222
|
+
state: event.state,
|
|
223
|
+
tools: [],
|
|
224
|
+
}];
|
|
225
|
+
}
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
case 'tools_discovered': {
|
|
230
|
+
const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);
|
|
231
|
+
if (index !== -1) {
|
|
232
|
+
connections.value[index] = { ...connections.value[index], tools: event.tools, state: 'READY' };
|
|
233
|
+
}
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
case 'auth_required': {
|
|
238
|
+
// Handle OAuth redirect
|
|
239
|
+
if (event.authUrl) {
|
|
240
|
+
onLog?.('info', `OAuth required - redirecting to ${event.authUrl}`, { authUrl: event.authUrl });
|
|
241
|
+
|
|
242
|
+
if (onRedirect) {
|
|
243
|
+
onRedirect(event.authUrl);
|
|
244
|
+
} else if (typeof window !== 'undefined') {
|
|
245
|
+
window.location.href = event.authUrl;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);
|
|
249
|
+
if (index !== -1) {
|
|
250
|
+
connections.value[index] = { ...connections.value[index], state: 'AUTHENTICATING' };
|
|
251
|
+
}
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
case 'error': {
|
|
256
|
+
const index = connections.value.findIndex((c) => c.sessionId === event.sessionId);
|
|
257
|
+
if (index !== -1) {
|
|
258
|
+
connections.value[index] = { ...connections.value[index], state: 'FAILED', error: event.error };
|
|
259
|
+
}
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
case 'disconnected': {
|
|
264
|
+
connections.value = connections.value.filter((c) => c.sessionId !== event.sessionId);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Load sessions from server
|
|
272
|
+
*/
|
|
273
|
+
const loadSessions = async () => {
|
|
274
|
+
if (!clientRef.value) return;
|
|
275
|
+
|
|
276
|
+
try {
|
|
277
|
+
isInitializing.value = true;
|
|
278
|
+
|
|
279
|
+
const result = await clientRef.value.getSessions();
|
|
280
|
+
const sessions = result.sessions || [];
|
|
281
|
+
|
|
282
|
+
// Initialize connections
|
|
283
|
+
if (isMountedRef.value) {
|
|
284
|
+
connections.value = sessions.map((s: SessionInfo) => ({
|
|
285
|
+
sessionId: s.sessionId,
|
|
286
|
+
serverId: s.serverId ?? 'unknown',
|
|
287
|
+
serverName: s.serverName ?? 'Unknown Server',
|
|
288
|
+
serverUrl: s.serverUrl,
|
|
289
|
+
transport: s.transport,
|
|
290
|
+
state: 'VALIDATING' as McpConnectionState,
|
|
291
|
+
tools: [],
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Validate each session in parallel
|
|
296
|
+
await Promise.all(
|
|
297
|
+
sessions.map(async (session: SessionInfo) => {
|
|
298
|
+
if (clientRef.value) {
|
|
299
|
+
try {
|
|
300
|
+
await clientRef.value.restoreSession(session.sessionId);
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
})
|
|
306
|
+
);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
console.error('[useMcp] Failed to load sessions:', error);
|
|
309
|
+
onLog?.('error', 'Failed to load sessions', { error });
|
|
310
|
+
} finally {
|
|
311
|
+
if (isMountedRef.value) {
|
|
312
|
+
isInitializing.value = false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Initialize SSE client
|
|
319
|
+
*/
|
|
320
|
+
const initClient = () => {
|
|
321
|
+
// Disconnect existing if any
|
|
322
|
+
if (clientRef.value) {
|
|
323
|
+
clientRef.value.disconnect();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const clientOptions: SSEClientOptions = {
|
|
327
|
+
url,
|
|
328
|
+
identity,
|
|
329
|
+
authToken,
|
|
330
|
+
onConnectionEvent: (event) => {
|
|
331
|
+
// Update local state based on event
|
|
332
|
+
updateConnectionsFromEvent(event);
|
|
333
|
+
|
|
334
|
+
// Call user callback
|
|
335
|
+
onConnectionEvent?.(event);
|
|
336
|
+
},
|
|
337
|
+
onObservabilityEvent: (event) => {
|
|
338
|
+
onLog?.(event.level || 'info', event.message || event.displayMessage || 'No message', event.metadata);
|
|
339
|
+
},
|
|
340
|
+
onStatusChange: (newStatus) => {
|
|
341
|
+
if (isMountedRef.value) {
|
|
342
|
+
status.value = newStatus;
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
const client = new SSEClient(clientOptions);
|
|
348
|
+
clientRef.value = client;
|
|
349
|
+
|
|
350
|
+
if (autoConnect) {
|
|
351
|
+
client.connect();
|
|
352
|
+
|
|
353
|
+
if (autoInitialize) {
|
|
354
|
+
loadSessions();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
onMounted(() => {
|
|
360
|
+
isMountedRef.value = true;
|
|
361
|
+
initClient();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
onUnmounted(() => {
|
|
365
|
+
isMountedRef.value = false;
|
|
366
|
+
clientRef.value?.disconnect();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Connect to an MCP server
|
|
371
|
+
*/
|
|
372
|
+
const connect = async (params: {
|
|
373
|
+
serverId: string;
|
|
374
|
+
serverName: string;
|
|
375
|
+
serverUrl: string;
|
|
376
|
+
callbackUrl: string;
|
|
377
|
+
transportType?: 'sse' | 'streamable_http';
|
|
378
|
+
}): Promise<string> => {
|
|
379
|
+
if (!clientRef.value) {
|
|
380
|
+
throw new Error('SSE client not initialized');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const result = await clientRef.value.connectToServer(params);
|
|
384
|
+
return result.sessionId;
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Disconnect from an MCP server
|
|
389
|
+
*/
|
|
390
|
+
const disconnect = async (sessionId: string): Promise<void> => {
|
|
391
|
+
if (!clientRef.value) {
|
|
392
|
+
throw new Error('SSE client not initialized');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
await clientRef.value.disconnectFromServer(sessionId);
|
|
396
|
+
|
|
397
|
+
// Remove from local state
|
|
398
|
+
if (isMountedRef.value) {
|
|
399
|
+
connections.value = connections.value.filter((c) => c.sessionId !== sessionId);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Refresh all connections
|
|
405
|
+
*/
|
|
406
|
+
const refresh = async () => {
|
|
407
|
+
await loadSessions();
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Manually connect SSE
|
|
412
|
+
*/
|
|
413
|
+
const connectSSE = () => {
|
|
414
|
+
clientRef.value?.connect();
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Manually disconnect SSE
|
|
419
|
+
*/
|
|
420
|
+
const disconnectSSE = () => {
|
|
421
|
+
clientRef.value?.disconnect();
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Complete OAuth authorization
|
|
426
|
+
*/
|
|
427
|
+
const finishAuth = async (sessionId: string, code: string): Promise<FinishAuthResult> => {
|
|
428
|
+
if (!clientRef.value) {
|
|
429
|
+
throw new Error('SSE client not initialized');
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return await clientRef.value.finishAuth(sessionId, code);
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Call a tool
|
|
437
|
+
*/
|
|
438
|
+
const callTool = async (
|
|
439
|
+
sessionId: string,
|
|
440
|
+
toolName: string,
|
|
441
|
+
toolArgs: Record<string, unknown>
|
|
442
|
+
): Promise<unknown> => {
|
|
443
|
+
if (!clientRef.value) {
|
|
444
|
+
throw new Error('SSE client not initialized');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return await clientRef.value.callTool(sessionId, toolName, toolArgs);
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* List tools (refresh tool list)
|
|
452
|
+
*/
|
|
453
|
+
const listTools = async (sessionId: string): Promise<ListToolsRpcResult> => {
|
|
454
|
+
if (!clientRef.value) {
|
|
455
|
+
throw new Error('SSE client not initialized');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return await clientRef.value.listTools(sessionId);
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* List prompts
|
|
463
|
+
*/
|
|
464
|
+
const listPrompts = async (sessionId: string): Promise<ListPromptsResult> => {
|
|
465
|
+
if (!clientRef.value) {
|
|
466
|
+
throw new Error('SSE client not initialized');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return await clientRef.value.listPrompts(sessionId);
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Get a specific prompt
|
|
474
|
+
*/
|
|
475
|
+
const getPrompt = async (sessionId: string, name: string, args?: Record<string, string>): Promise<unknown> => {
|
|
476
|
+
if (!clientRef.value) {
|
|
477
|
+
throw new Error('SSE client not initialized');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return await clientRef.value.getPrompt(sessionId, name, args);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* List resources
|
|
485
|
+
*/
|
|
486
|
+
const listResources = async (sessionId: string): Promise<ListResourcesResult> => {
|
|
487
|
+
if (!clientRef.value) {
|
|
488
|
+
throw new Error('SSE client not initialized');
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return await clientRef.value.listResources(sessionId);
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Read a specific resource
|
|
496
|
+
*/
|
|
497
|
+
const readResource = async (sessionId: string, uri: string): Promise<unknown> => {
|
|
498
|
+
if (!clientRef.value) {
|
|
499
|
+
throw new Error('SSE client not initialized');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return await clientRef.value.readResource(sessionId, uri);
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// Utility functions
|
|
506
|
+
const getConnection = (sessionId: string) => connections.value.find((c) => c.sessionId === sessionId);
|
|
507
|
+
|
|
508
|
+
const getConnectionByServerId = (serverId: string) => connections.value.find((c) => c.serverId === serverId);
|
|
509
|
+
|
|
510
|
+
const isServerConnected = (serverId: string) => {
|
|
511
|
+
const conn = getConnectionByServerId(serverId);
|
|
512
|
+
return conn?.state === 'CONNECTED';
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const getTools = (sessionId: string) => {
|
|
516
|
+
const conn = getConnection(sessionId);
|
|
517
|
+
return conn?.tools || [];
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
return {
|
|
521
|
+
// Return them as Ref objects so they can be destructured and stay reactive
|
|
522
|
+
connections: connections as unknown as { value: McpConnection[] },
|
|
523
|
+
status: status as unknown as { value: 'connecting' | 'connected' | 'disconnected' | 'error' },
|
|
524
|
+
isInitializing: isInitializing as unknown as { value: boolean },
|
|
525
|
+
connect,
|
|
526
|
+
disconnect,
|
|
527
|
+
getConnection,
|
|
528
|
+
getConnectionByServerId,
|
|
529
|
+
isServerConnected,
|
|
530
|
+
getTools,
|
|
531
|
+
refresh,
|
|
532
|
+
connectSSE,
|
|
533
|
+
disconnectSSE,
|
|
534
|
+
finishAuth,
|
|
535
|
+
callTool,
|
|
536
|
+
listTools,
|
|
537
|
+
listPrompts,
|
|
538
|
+
getPrompt,
|
|
539
|
+
listResources,
|
|
540
|
+
readResource,
|
|
541
|
+
};
|
|
542
|
+
}
|
package/src/index.ts
ADDED