@mcp-ts/sdk 1.0.0 → 1.1.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 +25 -13
- package/dist/adapters/agui-adapter.d.mts +21 -44
- package/dist/adapters/agui-adapter.d.ts +21 -44
- package/dist/adapters/agui-adapter.js +93 -67
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +93 -68
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +32 -134
- package/dist/adapters/agui-middleware.d.ts +32 -134
- package/dist/adapters/agui-middleware.js +314 -350
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs +314 -351
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +2 -2
- package/dist/adapters/ai-adapter.d.ts +2 -2
- package/dist/adapters/langchain-adapter.d.mts +2 -2
- package/dist/adapters/langchain-adapter.d.ts +2 -2
- package/dist/adapters/mastra-adapter.d.mts +2 -2
- package/dist/adapters/mastra-adapter.d.ts +2 -2
- package/dist/client/index.d.mts +184 -57
- package/dist/client/index.d.ts +184 -57
- package/dist/client/index.js +535 -130
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +535 -131
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +40 -6
- package/dist/client/react.d.ts +40 -6
- package/dist/client/react.js +587 -142
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +586 -143
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +5 -5
- package/dist/client/vue.d.ts +5 -5
- package/dist/client/vue.js +545 -140
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +545 -141
- package/dist/client/vue.mjs.map +1 -1
- package/dist/{events-BP6WyRNh.d.mts → events-BgeztGYZ.d.mts} +12 -1
- package/dist/{events-BP6WyRNh.d.ts → events-BgeztGYZ.d.ts} +12 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +779 -248
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +775 -245
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-DMF3ED2O.d.mts → multi-session-client-CxogNckF.d.mts} +1 -1
- package/dist/{multi-session-client-BOFgPypS.d.ts → multi-session-client-cox_WXUj.d.ts} +1 -1
- package/dist/server/index.d.mts +44 -40
- package/dist/server/index.d.ts +44 -40
- package/dist/server/index.js +242 -116
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +238 -112
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +2 -2
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{types-SbDlA2VX.d.mts → types-CLccx9wW.d.mts} +1 -1
- package/dist/{types-SbDlA2VX.d.ts → types-CLccx9wW.d.ts} +1 -1
- package/package.json +8 -1
- package/src/adapters/agui-adapter.ts +121 -107
- package/src/adapters/agui-middleware.ts +474 -512
- package/src/client/core/app-host.ts +417 -0
- package/src/client/core/sse-client.ts +365 -212
- package/src/client/core/types.ts +31 -0
- package/src/client/index.ts +1 -0
- package/src/client/react/index.ts +1 -0
- package/src/client/react/use-mcp-app.ts +73 -0
- package/src/client/react/useMcp.ts +18 -0
- package/src/server/handlers/nextjs-handler.ts +8 -7
- package/src/server/handlers/sse-handler.ts +131 -164
- package/src/server/mcp/oauth-client.ts +32 -2
- package/src/server/storage/index.ts +17 -1
- package/src/server/storage/sqlite-backend.ts +185 -0
- package/src/server/storage/types.ts +1 -1
- package/src/shared/events.ts +12 -0
- package/src/shared/types.ts +4 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { SessionListResult } from '../../shared/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Abstraction layer for the AppHost's network communication.
|
|
5
|
+
*
|
|
6
|
+
* This interface decouples the `AppHost` from the concrete networking implementation (like `SSEClient`).
|
|
7
|
+
* Implementation can be:
|
|
8
|
+
* 1. `SSEClient`: Direct connection to MCP Server (Browser -> Server).
|
|
9
|
+
* 2. `ProxyClient`: Connection via an intermediary API (Browser -> Next.js API -> Server).
|
|
10
|
+
*/
|
|
11
|
+
export interface AppHostClient {
|
|
12
|
+
/**
|
|
13
|
+
* Check if the client is connected
|
|
14
|
+
*/
|
|
15
|
+
isConnected(): boolean;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get list of active sessions
|
|
19
|
+
*/
|
|
20
|
+
getSessions(): Promise<SessionListResult>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Call a tool on a specific session
|
|
24
|
+
*/
|
|
25
|
+
callTool(sessionId: string, toolName: string, toolArgs: Record<string, unknown>): Promise<unknown>;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Read a resource from a specific session
|
|
29
|
+
*/
|
|
30
|
+
readResource(sessionId: string, uri: string): Promise<unknown>;
|
|
31
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useEffect, useRef, useState, useCallback } from 'react';
|
|
2
|
+
import type { SSEClient } from '../core/sse-client';
|
|
3
|
+
import { AppHost } from '../core/app-host';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hook to host an MCP App in a React component
|
|
7
|
+
*
|
|
8
|
+
* Optimized for instant loading:
|
|
9
|
+
* - Creates AppHost synchronously
|
|
10
|
+
* - Starts bridge connection immediately
|
|
11
|
+
* - Returns host before connection completes (ready to call launch)
|
|
12
|
+
*
|
|
13
|
+
* @param client - Connected SSEClient instance
|
|
14
|
+
* @param iframeRef - Reference to the iframe element
|
|
15
|
+
* @param options - Optional configuration
|
|
16
|
+
* @returns Object containing the AppHost instance (or null) and error state
|
|
17
|
+
*/
|
|
18
|
+
export function useMcpApp(
|
|
19
|
+
client: SSEClient,
|
|
20
|
+
iframeRef: React.RefObject<HTMLIFrameElement>,
|
|
21
|
+
options?: {
|
|
22
|
+
/** Callback when the App sends a message (e.g. to chat) */
|
|
23
|
+
onMessage?: (params: { role: string; content: unknown }) => void;
|
|
24
|
+
}
|
|
25
|
+
) {
|
|
26
|
+
const [host, setHost] = useState<AppHost | null>(null);
|
|
27
|
+
const [error, setError] = useState<Error | null>(null);
|
|
28
|
+
const initializingRef = useRef(false);
|
|
29
|
+
|
|
30
|
+
// Store latest callback in ref to avoid re-initializing AppHost on callback change
|
|
31
|
+
const onMessageRef = useRef(options?.onMessage);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
onMessageRef.current = options?.onMessage;
|
|
34
|
+
}, [options?.onMessage]);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!client || !iframeRef.current || initializingRef.current) return;
|
|
38
|
+
|
|
39
|
+
// Prevent double initialization in strict mode
|
|
40
|
+
initializingRef.current = true;
|
|
41
|
+
|
|
42
|
+
const initHost = async () => {
|
|
43
|
+
try {
|
|
44
|
+
// Initialize AppHost with security enforcement
|
|
45
|
+
const appHost = new AppHost(client, iframeRef.current!);
|
|
46
|
+
|
|
47
|
+
// Register message handler
|
|
48
|
+
appHost.onAppMessage = (params) => {
|
|
49
|
+
onMessageRef.current?.(params);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Set host immediately so launch can be called
|
|
53
|
+
// (launch will wait for bridge if needed)
|
|
54
|
+
setHost(appHost);
|
|
55
|
+
|
|
56
|
+
// Start bridge connection (this is fast, just sets up PostMessage)
|
|
57
|
+
await appHost.start();
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.error('[useMcpApp] Failed to initialize AppHost:', err);
|
|
60
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
initHost();
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
initializingRef.current = false;
|
|
68
|
+
setHost(null);
|
|
69
|
+
};
|
|
70
|
+
}, [client, iframeRef]);
|
|
71
|
+
|
|
72
|
+
return { host, error };
|
|
73
|
+
}
|
|
@@ -58,6 +58,12 @@ export interface UseMcpOptions {
|
|
|
58
58
|
* If provided, this will be called instead of window.location.href assignment
|
|
59
59
|
*/
|
|
60
60
|
onRedirect?: (url: string) => void;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Request timeout in milliseconds
|
|
64
|
+
* @default 60000
|
|
65
|
+
*/
|
|
66
|
+
requestTimeout?: number;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
export interface McpConnection {
|
|
@@ -177,6 +183,11 @@ export interface McpClient {
|
|
|
177
183
|
* Read a specific resource
|
|
178
184
|
*/
|
|
179
185
|
readResource: (sessionId: string, uri: string) => Promise<unknown>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Access the underlying SSEClient instance (for advanced usage like AppHost)
|
|
189
|
+
*/
|
|
190
|
+
client: SSEClient | null;
|
|
180
191
|
}
|
|
181
192
|
|
|
182
193
|
/**
|
|
@@ -228,6 +239,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
|
|
|
228
239
|
setStatus(newStatus);
|
|
229
240
|
}
|
|
230
241
|
},
|
|
242
|
+
requestTimeout: options.requestTimeout,
|
|
231
243
|
};
|
|
232
244
|
|
|
233
245
|
const client = new SSEClient(clientOptions);
|
|
@@ -276,6 +288,11 @@ export function useMcp(options: UseMcpOptions): McpClient {
|
|
|
276
288
|
}
|
|
277
289
|
|
|
278
290
|
case 'tools_discovered': {
|
|
291
|
+
// Preload UI resources for instant loading when tools are discovered
|
|
292
|
+
if (clientRef.current && event.tools?.length) {
|
|
293
|
+
clientRef.current.preloadToolUiResources(event.sessionId, event.tools);
|
|
294
|
+
}
|
|
295
|
+
|
|
279
296
|
return prev.map((c: McpConnection) =>
|
|
280
297
|
c.sessionId === event.sessionId ? { ...c, tools: event.tools, state: 'READY' } : c
|
|
281
298
|
);
|
|
@@ -554,5 +571,6 @@ export function useMcp(options: UseMcpOptions): McpClient {
|
|
|
554
571
|
getPrompt,
|
|
555
572
|
listResources,
|
|
556
573
|
readResource,
|
|
574
|
+
client: clientRef.current,
|
|
557
575
|
};
|
|
558
576
|
}
|
|
@@ -100,9 +100,6 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
|
|
|
100
100
|
});
|
|
101
101
|
};
|
|
102
102
|
|
|
103
|
-
// Send initial connection event
|
|
104
|
-
sendSSE('connected', { timestamp: Date.now() });
|
|
105
|
-
|
|
106
103
|
// Clean up previous manager if exists (prevents memory leaks on reconnect)
|
|
107
104
|
const previousManager = managers.get(identity);
|
|
108
105
|
if (previousManager) {
|
|
@@ -138,6 +135,10 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
|
|
|
138
135
|
|
|
139
136
|
managers.set(identity, manager);
|
|
140
137
|
|
|
138
|
+
// Send connected event AFTER manager is registered (prevents race condition
|
|
139
|
+
// where client sends POST before manager is available)
|
|
140
|
+
sendSSE('connected', { timestamp: Date.now() });
|
|
141
|
+
|
|
141
142
|
// Handle client disconnect
|
|
142
143
|
const abortController = new AbortController();
|
|
143
144
|
request.signal?.addEventListener('abort', () => {
|
|
@@ -194,11 +195,11 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
|
|
|
194
195
|
);
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
// Handle the request
|
|
198
|
-
await manager.handleRequest(body);
|
|
198
|
+
// Handle the request and return response directly (bypasses SSE latency)
|
|
199
|
+
const response = await manager.handleRequest(body);
|
|
199
200
|
|
|
200
|
-
// Return
|
|
201
|
-
return Response.json(
|
|
201
|
+
// Return the actual RPC response for immediate use by client
|
|
202
|
+
return Response.json(response);
|
|
202
203
|
} catch (error) {
|
|
203
204
|
return Response.json(
|
|
204
205
|
{
|