@mcp-ts/sdk 1.3.6 → 1.3.9
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 -21
- package/README.md +398 -404
- package/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-adapter.js +2 -2
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +2 -2
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/ai-adapter.js +1 -1
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +1 -1
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.js +1 -1
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +1 -1
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.js +1 -1
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +1 -1
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/bin/mcp-ts.js +0 -0
- package/dist/bin/mcp-ts.js.map +1 -1
- package/dist/bin/mcp-ts.mjs +0 -0
- package/dist/bin/mcp-ts.mjs.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +2 -2
- package/dist/client/react.d.ts +2 -2
- package/dist/client/react.js +25 -2
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +26 -3
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.js.map +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 +134 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -71
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-BYLarghq.d.ts → multi-session-client-CHE8QpVE.d.ts} +75 -5
- package/dist/{multi-session-client-CzhMkE0k.d.mts → multi-session-client-CQsRbxYI.d.mts} +75 -5
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +134 -71
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +134 -71
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.js +10 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +10 -2
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +185 -185
- package/src/adapters/agui-adapter.ts +222 -222
- package/src/adapters/agui-middleware.ts +382 -382
- package/src/adapters/ai-adapter.ts +115 -115
- package/src/adapters/langchain-adapter.ts +127 -127
- package/src/adapters/mastra-adapter.ts +126 -126
- package/src/bin/mcp-ts.ts +102 -102
- package/src/client/core/app-host.ts +417 -417
- package/src/client/core/sse-client.ts +371 -371
- package/src/client/core/types.ts +31 -31
- package/src/client/index.ts +27 -27
- package/src/client/react/index.ts +16 -16
- package/src/client/react/use-app-host.ts +73 -73
- package/src/client/react/use-mcp-apps.tsx +247 -214
- package/src/client/react/use-mcp.ts +641 -641
- package/src/client/vue/index.ts +10 -10
- package/src/client/vue/use-mcp.ts +617 -617
- package/src/index.ts +11 -11
- package/src/server/handlers/nextjs-handler.ts +204 -204
- package/src/server/handlers/sse-handler.ts +631 -631
- package/src/server/index.ts +57 -57
- package/src/server/mcp/multi-session-client.ts +228 -132
- package/src/server/mcp/oauth-client.ts +1188 -1188
- package/src/server/mcp/storage-oauth-provider.ts +272 -272
- package/src/server/storage/file-backend.ts +157 -170
- package/src/server/storage/index.ts +176 -175
- package/src/server/storage/memory-backend.ts +123 -136
- package/src/server/storage/redis-backend.ts +276 -289
- package/src/server/storage/redis.ts +160 -160
- package/src/server/storage/sqlite-backend.ts +182 -186
- package/src/server/storage/supabase-backend.ts +228 -227
- package/src/server/storage/types.ts +116 -116
- package/src/shared/constants.ts +29 -29
- package/src/shared/errors.ts +133 -133
- package/src/shared/event-routing.ts +28 -28
- package/src/shared/events.ts +180 -180
- package/src/shared/index.ts +75 -75
- package/src/shared/tool-utils.ts +61 -61
- package/src/shared/types.ts +282 -282
- package/src/shared/utils.ts +38 -16
- package/supabase/migrations/20260330195700_install_mcp_sessions.sql +84 -84
|
@@ -1,214 +1,247 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Apps Hook
|
|
3
|
-
*
|
|
4
|
-
* Provides utilities for rendering interactive UI components from MCP servers.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React, { useState, useEffect, useCallback, useRef, memo } from 'react';
|
|
8
|
-
import { useAppHost } from './use-app-host.js';
|
|
9
|
-
import type { SSEClient } from '../core/sse-client.js';
|
|
10
|
-
|
|
11
|
-
export interface McpClient {
|
|
12
|
-
connections: Array<{
|
|
13
|
-
sessionId: string;
|
|
14
|
-
tools: Array<{
|
|
15
|
-
name: string;
|
|
16
|
-
mcpApp?: {
|
|
17
|
-
resourceUri: string;
|
|
18
|
-
};
|
|
19
|
-
_meta?: {
|
|
20
|
-
ui?: {
|
|
21
|
-
resourceUri?: string;
|
|
22
|
-
};
|
|
23
|
-
'ui/resourceUri'?: string;
|
|
24
|
-
};
|
|
25
|
-
}>;
|
|
26
|
-
}>;
|
|
27
|
-
sseClient?: SSEClient | null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface McpAppMetadata {
|
|
31
|
-
toolName: string;
|
|
32
|
-
resourceUri: string;
|
|
33
|
-
sessionId: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface McpAppRendererProps {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
/** Custom CSS class for the container */
|
|
43
|
-
className?: string;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
1
|
+
/**
|
|
2
|
+
* MCP Apps Hook
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for rendering interactive UI components from MCP servers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useState, useEffect, useCallback, useRef, memo } from 'react';
|
|
8
|
+
import { useAppHost } from './use-app-host.js';
|
|
9
|
+
import type { SSEClient } from '../core/sse-client.js';
|
|
10
|
+
|
|
11
|
+
export interface McpClient {
|
|
12
|
+
connections: Array<{
|
|
13
|
+
sessionId: string;
|
|
14
|
+
tools: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
mcpApp?: {
|
|
17
|
+
resourceUri: string;
|
|
18
|
+
};
|
|
19
|
+
_meta?: {
|
|
20
|
+
ui?: {
|
|
21
|
+
resourceUri?: string;
|
|
22
|
+
};
|
|
23
|
+
'ui/resourceUri'?: string;
|
|
24
|
+
};
|
|
25
|
+
}>;
|
|
26
|
+
}>;
|
|
27
|
+
sseClient?: SSEClient | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface McpAppMetadata {
|
|
31
|
+
toolName: string;
|
|
32
|
+
resourceUri: string;
|
|
33
|
+
sessionId: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface McpAppRendererProps {
|
|
37
|
+
mcpClient: McpClient | null;
|
|
38
|
+
name: string;
|
|
39
|
+
input?: Record<string, unknown>;
|
|
40
|
+
result?: unknown;
|
|
41
|
+
status: 'executing' | 'inProgress' | 'complete' | 'idle';
|
|
42
|
+
/** Custom CSS class for the container */
|
|
43
|
+
className?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Simplified MCP App renderer - users just pass tool name and data
|
|
48
|
+
* Internal hook handles metadata lookup and SSE client retrieval
|
|
49
|
+
*/
|
|
50
|
+
const McpAppRenderer = memo(function McpAppRenderer({
|
|
51
|
+
mcpClient,
|
|
52
|
+
name,
|
|
53
|
+
input,
|
|
54
|
+
result,
|
|
55
|
+
status,
|
|
56
|
+
className,
|
|
57
|
+
}: McpAppRendererProps) {
|
|
58
|
+
const getAppMetadata = useCallback((): McpAppMetadata | undefined => {
|
|
59
|
+
if (!mcpClient) return undefined;
|
|
60
|
+
|
|
61
|
+
const extractedName = extractToolName(name);
|
|
62
|
+
|
|
63
|
+
for (const conn of mcpClient.connections) {
|
|
64
|
+
for (const tool of conn.tools) {
|
|
65
|
+
const candidateName = extractToolName(tool.name);
|
|
66
|
+
const resourceUri =
|
|
67
|
+
tool.mcpApp?.resourceUri ??
|
|
68
|
+
tool._meta?.ui?.resourceUri ??
|
|
69
|
+
tool._meta?.['ui/resourceUri'];
|
|
70
|
+
|
|
71
|
+
if (resourceUri && candidateName === extractedName) {
|
|
72
|
+
return {
|
|
73
|
+
toolName: candidateName,
|
|
74
|
+
resourceUri,
|
|
75
|
+
sessionId: conn.sessionId,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return undefined;
|
|
82
|
+
}, [mcpClient, name]);
|
|
83
|
+
|
|
84
|
+
const metadata = getAppMetadata();
|
|
85
|
+
const sseClient = mcpClient?.sseClient ?? null;
|
|
86
|
+
|
|
87
|
+
if (!metadata || !sseClient) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const iframeRef = useRef<HTMLIFrameElement>(null);
|
|
91
|
+
const { host, error: hostError } = useAppHost(sseClient as SSEClient, iframeRef);
|
|
92
|
+
const [isLaunched, setIsLaunched] = useState(false);
|
|
93
|
+
const [error, setError] = useState<Error | null>(null);
|
|
94
|
+
|
|
95
|
+
// Track which data has been sent to prevent duplicates
|
|
96
|
+
const sentInputRef = useRef(false);
|
|
97
|
+
const sentResultRef = useRef(false);
|
|
98
|
+
const lastInputRef = useRef(input);
|
|
99
|
+
const lastResultRef = useRef(result);
|
|
100
|
+
const lastStatusRef = useRef(status);
|
|
101
|
+
|
|
102
|
+
// Launch the app when host is ready
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!host || !metadata.resourceUri || !metadata.sessionId) return;
|
|
105
|
+
|
|
106
|
+
host
|
|
107
|
+
.launch(metadata.resourceUri, metadata.sessionId)
|
|
108
|
+
.then(() => setIsLaunched(true))
|
|
109
|
+
.catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
|
|
110
|
+
}, [host, metadata.resourceUri, metadata.sessionId]);
|
|
111
|
+
|
|
112
|
+
// Send tool input when available or when it changes
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (!host || !isLaunched || !input) return;
|
|
115
|
+
|
|
116
|
+
// Send if never sent, or if input changed
|
|
117
|
+
if (!sentInputRef.current || JSON.stringify(input) !== JSON.stringify(lastInputRef.current)) {
|
|
118
|
+
sentInputRef.current = true;
|
|
119
|
+
lastInputRef.current = input;
|
|
120
|
+
host.sendToolInput(input);
|
|
121
|
+
}
|
|
122
|
+
}, [host, isLaunched, input]);
|
|
123
|
+
|
|
124
|
+
// Send tool result when complete or when it changes
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
if (!host || !isLaunched || result === undefined) return;
|
|
127
|
+
if (status !== 'complete') return;
|
|
128
|
+
|
|
129
|
+
// Send if never sent, or if result changed
|
|
130
|
+
if (!sentResultRef.current || JSON.stringify(result) !== JSON.stringify(lastResultRef.current)) {
|
|
131
|
+
sentResultRef.current = true;
|
|
132
|
+
lastResultRef.current = result;
|
|
133
|
+
const formattedResult =
|
|
134
|
+
typeof result === 'string'
|
|
135
|
+
? { content: [{ type: 'text', text: result }] }
|
|
136
|
+
: result;
|
|
137
|
+
host.sendToolResult(formattedResult);
|
|
138
|
+
}
|
|
139
|
+
}, [host, isLaunched, result, status]);
|
|
140
|
+
|
|
141
|
+
// Reset sent flags when tool status resets to executing (new tool call)
|
|
142
|
+
useEffect(() => {
|
|
143
|
+
if (status === 'executing' && lastStatusRef.current !== 'executing') {
|
|
144
|
+
sentInputRef.current = false;
|
|
145
|
+
sentResultRef.current = false;
|
|
146
|
+
}
|
|
147
|
+
lastStatusRef.current = status;
|
|
148
|
+
}, [status]);
|
|
149
|
+
|
|
150
|
+
// Display errors
|
|
151
|
+
const displayError = error || hostError;
|
|
152
|
+
if (displayError) {
|
|
153
|
+
return (
|
|
154
|
+
<div className={`p-4 bg-red-900/20 border border-red-700 rounded text-red-200 ${className || ''}`}>
|
|
155
|
+
Error: {displayError.message || String(displayError)}
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div className={`w-full border border-gray-700 rounded overflow-hidden bg-white min-h-96 my-2 relative ${className || ''}`}>
|
|
162
|
+
<iframe
|
|
163
|
+
ref={iframeRef}
|
|
164
|
+
sandbox="allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads"
|
|
165
|
+
className="w-full h-full min-h-96"
|
|
166
|
+
style={{ height: 'auto' }}
|
|
167
|
+
title="MCP App"
|
|
168
|
+
/>
|
|
169
|
+
{!isLaunched && (
|
|
170
|
+
<div className="absolute inset-0 bg-gray-900/50 flex items-center justify-center pointer-events-none">
|
|
171
|
+
<div className="w-6 h-6 border-2 border-blue-500 border-t-transparent rounded-full animate-spin" />
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Simple hook to get MCP app metadata
|
|
180
|
+
*
|
|
181
|
+
* @param mcpClient - The MCP client from useMcp() or context
|
|
182
|
+
* @returns Object with getAppMetadata function and McpAppRenderer component
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```tsx
|
|
186
|
+
* function ToolRenderer(props) {
|
|
187
|
+
* const { getAppMetadata, McpAppRenderer } = useMcpApps(mcpClient);
|
|
188
|
+
* const metadata = getAppMetadata(props.name);
|
|
189
|
+
*
|
|
190
|
+
* if (!metadata) return null;
|
|
191
|
+
* return (
|
|
192
|
+
* <McpAppRenderer
|
|
193
|
+
* metadata={metadata}
|
|
194
|
+
* input={props.args}
|
|
195
|
+
* result={props.result}
|
|
196
|
+
* status={props.status}
|
|
197
|
+
* />
|
|
198
|
+
* );
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export function useMcpApps(mcpClient: McpClient | null) {
|
|
203
|
+
/**
|
|
204
|
+
* Get MCP app metadata for a tool name
|
|
205
|
+
* This is fast and can be called on every render
|
|
206
|
+
*/
|
|
207
|
+
const getAppMetadata = useCallback(
|
|
208
|
+
(toolName: string): McpAppMetadata | undefined => {
|
|
209
|
+
if (!mcpClient) return undefined;
|
|
210
|
+
|
|
211
|
+
const extractedName = extractToolName(toolName);
|
|
212
|
+
|
|
213
|
+
for (const conn of mcpClient.connections) {
|
|
214
|
+
for (const tool of conn.tools) {
|
|
215
|
+
const candidateName = extractToolName(tool.name);
|
|
216
|
+
// Check both locations: direct mcpApp or _meta.ui
|
|
217
|
+
const resourceUri =
|
|
218
|
+
tool.mcpApp?.resourceUri ??
|
|
219
|
+
tool._meta?.ui?.resourceUri ??
|
|
220
|
+
tool._meta?.['ui/resourceUri'];
|
|
221
|
+
|
|
222
|
+
if (resourceUri && candidateName === extractedName) {
|
|
223
|
+
return {
|
|
224
|
+
toolName: candidateName,
|
|
225
|
+
resourceUri,
|
|
226
|
+
sessionId: conn.sessionId,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return undefined;
|
|
233
|
+
},
|
|
234
|
+
[mcpClient]
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
return { getAppMetadata, McpAppRenderer };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Extract the base tool name, removing any prefixes
|
|
242
|
+
*/
|
|
243
|
+
function extractToolName(fullName: string): string {
|
|
244
|
+
// Handle patterns like "tool_abc123_get-time" -> "get-time"
|
|
245
|
+
const match = fullName.match(/(?:tool_[^_]+_)?(.+)$/);
|
|
246
|
+
return match?.[1] || fullName;
|
|
247
|
+
}
|