@mcp-ts/sdk 2.4.5 → 2.5.1
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/dist/adapters/agui-adapter.d.mts +3 -3
- package/dist/adapters/agui-adapter.d.ts +3 -3
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +3 -3
- package/dist/adapters/agui-middleware.d.ts +3 -3
- 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 +3 -3
- package/dist/adapters/ai-adapter.d.ts +3 -3
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +3 -3
- package/dist/adapters/langchain-adapter.d.ts +3 -3
- package/dist/adapters/langchain-adapter.js +2 -2
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +2 -2
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +2 -2
- package/dist/adapters/mastra-adapter.d.ts +2 -2
- package/dist/adapters/mastra-adapter.js +2 -2
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +2 -2
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +9 -0
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +15 -4
- package/dist/client/react.d.ts +15 -4
- package/dist/client/react.js +56 -37
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +56 -37
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +4 -4
- package/dist/client/vue.d.ts +4 -4
- package/dist/client/vue.js +9 -0
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +9 -0
- package/dist/client/vue.mjs.map +1 -1
- package/dist/{index-CZk2gu2E.d.ts → index-BEdyuz1M.d.ts} +6 -1
- package/dist/{index-CkM3p0eE.d.mts → index-C99wE2Zf.d.mts} +6 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +380 -82
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +376 -82
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-QOOPdEVp.d.ts → multi-session-client-CclWRxTD.d.mts} +14 -2
- package/dist/{multi-session-client-ChQrBZhF.d.mts → multi-session-client-DzvZD6Tt.d.ts} +14 -2
- package/dist/server/index.d.mts +18 -4
- package/dist/server/index.d.ts +18 -4
- package/dist/server/index.js +371 -82
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +367 -82
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +4 -4
- package/dist/shared/index.d.ts +4 -4
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{tool-router-CGs3IDOJ.d.mts → tool-router-C9ECn3FX.d.mts} +1 -1
- package/dist/{tool-router-DQ-HrD7W.d.ts → tool-router-CUSSk6lT.d.ts} +1 -1
- package/dist/{types-Bf-7GOLW.d.mts → types-CbFbPkfQ.d.mts} +38 -3
- package/dist/{types-Bf-7GOLW.d.ts → types-CbFbPkfQ.d.ts} +38 -3
- package/migrations/neon/20260513010000_install_mcp_sessions.sql +1 -0
- package/migrations/supabase/20260330195700_install_mcp_sessions.sql +1 -0
- package/package.json +2 -2
- package/src/adapters/agui-adapter.ts +6 -2
- package/src/adapters/ai-adapter.ts +3 -1
- package/src/adapters/langchain-adapter.ts +5 -3
- package/src/adapters/mastra-adapter.ts +5 -3
- package/src/client/core/sse-client.ts +21 -0
- package/src/client/react/oauth-popup.tsx +17 -24
- package/src/client/react/use-mcp.ts +69 -15
- package/src/server/handlers/sse-handler.ts +202 -9
- package/src/server/mcp/multi-session-client.ts +7 -3
- package/src/server/mcp/oauth-client.ts +25 -10
- package/src/server/mcp/tool-policy-gateway.ts +90 -0
- package/src/server/storage/neon-backend.ts +65 -60
- package/src/server/storage/session-lifecycle.ts +5 -0
- package/src/server/storage/supabase-backend.ts +27 -15
- package/src/server/storage/tool-policy.ts +89 -0
- package/src/server/storage/types.ts +11 -0
- package/src/shared/types.ts +52 -1
|
@@ -3,6 +3,7 @@ import type { SessionStore, Session, SessionCredentials } from './types.js';
|
|
|
3
3
|
import { generateSessionId } from '../../shared/utils.js';
|
|
4
4
|
import { encryptObject, decryptObject } from './crypto.js';
|
|
5
5
|
import { resolveSessionExpiresAt } from './session-lifecycle.js';
|
|
6
|
+
import { normalizeToolPolicy } from './tool-policy.js';
|
|
6
7
|
import { DORMANT_SESSION_EXPIRATION_MS } from '../../shared/constants.js';
|
|
7
8
|
|
|
8
9
|
export class SupabaseStorageBackend implements SessionStore {
|
|
@@ -51,6 +52,7 @@ export class SupabaseStorageBackend implements SessionStore {
|
|
|
51
52
|
headers: decryptObject(row.headers),
|
|
52
53
|
authUrl: row.auth_url,
|
|
53
54
|
status: row.status ?? 'pending',
|
|
55
|
+
toolPolicy: normalizeToolPolicy(row.tool_policy),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -85,23 +87,30 @@ export class SupabaseStorageBackend implements SessionStore {
|
|
|
85
87
|
const updatedAt = new Date(session.updatedAt ?? session.createdAt ?? Date.now()).toISOString();
|
|
86
88
|
const expiresAt = resolveSessionExpiresAt(status, new Date(createdAt).getTime());
|
|
87
89
|
|
|
90
|
+
const insertData: Record<string, unknown> = {
|
|
91
|
+
session_id: sessionId,
|
|
92
|
+
user_id: userId,
|
|
93
|
+
server_id: session.serverId,
|
|
94
|
+
server_name: session.serverName,
|
|
95
|
+
server_url: session.serverUrl,
|
|
96
|
+
transport_type: session.transportType,
|
|
97
|
+
callback_url: session.callbackUrl,
|
|
98
|
+
created_at: createdAt,
|
|
99
|
+
updated_at: updatedAt,
|
|
100
|
+
headers: encryptObject(session.headers),
|
|
101
|
+
auth_url: session.authUrl ?? null,
|
|
102
|
+
status,
|
|
103
|
+
expires_at: expiresAt === null ? null : new Date(expiresAt).toISOString(),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const toolPolicy = normalizeToolPolicy(session.toolPolicy);
|
|
107
|
+
if (toolPolicy) {
|
|
108
|
+
insertData.tool_policy = toolPolicy;
|
|
109
|
+
}
|
|
110
|
+
|
|
88
111
|
const { error } = await this.supabase
|
|
89
112
|
.from('mcp_sessions')
|
|
90
|
-
.insert(
|
|
91
|
-
session_id: sessionId,
|
|
92
|
-
user_id: userId,
|
|
93
|
-
server_id: session.serverId,
|
|
94
|
-
server_name: session.serverName,
|
|
95
|
-
server_url: session.serverUrl,
|
|
96
|
-
transport_type: session.transportType,
|
|
97
|
-
callback_url: session.callbackUrl,
|
|
98
|
-
created_at: createdAt,
|
|
99
|
-
updated_at: updatedAt,
|
|
100
|
-
headers: encryptObject(session.headers),
|
|
101
|
-
auth_url: session.authUrl ?? null,
|
|
102
|
-
status,
|
|
103
|
-
expires_at: expiresAt === null ? null : new Date(expiresAt).toISOString(),
|
|
104
|
-
});
|
|
113
|
+
.insert(insertData);
|
|
105
114
|
|
|
106
115
|
if (error) {
|
|
107
116
|
if (error.code === '23505') {
|
|
@@ -130,6 +139,7 @@ export class SupabaseStorageBackend implements SessionStore {
|
|
|
130
139
|
}
|
|
131
140
|
if ('headers' in data) updateData.headers = encryptObject(data.headers);
|
|
132
141
|
if ('authUrl' in data) updateData.auth_url = data.authUrl ?? null;
|
|
142
|
+
if ('toolPolicy' in data) updateData.tool_policy = normalizeToolPolicy(data.toolPolicy);
|
|
133
143
|
|
|
134
144
|
const shouldUpdateSession = Object.keys(updateData).some((key) => key !== 'updated_at');
|
|
135
145
|
|
|
@@ -351,3 +361,5 @@ export class SupabaseStorageBackend implements SessionStore {
|
|
|
351
361
|
// Supabase client handles its own connection pooling over HTTP.
|
|
352
362
|
}
|
|
353
363
|
}
|
|
364
|
+
|
|
365
|
+
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import type { ToolPolicy } from './types.js';
|
|
3
|
+
|
|
4
|
+
export type ToolPolicyInput = {
|
|
5
|
+
mode?: unknown;
|
|
6
|
+
toolIds?: unknown;
|
|
7
|
+
updatedAt?: unknown;
|
|
8
|
+
} | null | undefined;
|
|
9
|
+
|
|
10
|
+
export function createToolId(serverId: string, toolName: string): string {
|
|
11
|
+
return `${serverId}::${toolName}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function normalizeToolIds(input?: unknown): string[] {
|
|
15
|
+
if (!Array.isArray(input)) return [];
|
|
16
|
+
|
|
17
|
+
return Array.from(new Set(
|
|
18
|
+
input
|
|
19
|
+
.filter((id): id is string => typeof id === 'string')
|
|
20
|
+
.map((id) => id.trim())
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function normalizeToolPolicy(input?: ToolPolicyInput, now = Date.now()): ToolPolicy | undefined {
|
|
26
|
+
if (!input || typeof input !== 'object') {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const mode = input.mode === 'allowlist' || input.mode === 'denylist'
|
|
31
|
+
? input.mode
|
|
32
|
+
: 'all';
|
|
33
|
+
const updatedAt = typeof input.updatedAt === 'number' && Number.isFinite(input.updatedAt)
|
|
34
|
+
? input.updatedAt
|
|
35
|
+
: now;
|
|
36
|
+
|
|
37
|
+
if (mode === 'all') {
|
|
38
|
+
return { mode: 'all', toolIds: [], updatedAt };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return { mode, toolIds: normalizeToolIds(input.toolIds), updatedAt };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function normalizeToolPolicyForUpdate(input: ToolPolicyInput, now = Date.now()): ToolPolicy {
|
|
45
|
+
return normalizeToolPolicy(input, now) ?? { mode: 'all', toolIds: [], updatedAt: now };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isToolAllowed(policy: ToolPolicy | undefined, toolName: string, serverId?: string): boolean {
|
|
49
|
+
if (!policy || policy.mode === 'all') return true;
|
|
50
|
+
if (!serverId) return false;
|
|
51
|
+
|
|
52
|
+
const toolId = createToolId(serverId, toolName);
|
|
53
|
+
if (policy.mode === 'allowlist') {
|
|
54
|
+
return policy.toolIds.includes(toolId);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return !policy.toolIds.includes(toolId);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function assertToolAllowed(policy: ToolPolicy | undefined, toolName: string, serverId?: string): void {
|
|
61
|
+
if (isToolAllowed(policy, toolName, serverId)) return;
|
|
62
|
+
throw new Error(`Tool "${toolName}" is not allowed for this MCP session`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function filterToolsByPolicy<T extends Pick<Tool, 'name'>>(
|
|
66
|
+
tools: T[],
|
|
67
|
+
policy: ToolPolicy | undefined,
|
|
68
|
+
serverId?: string
|
|
69
|
+
): T[] {
|
|
70
|
+
if (!policy || policy.mode === 'all') return tools;
|
|
71
|
+
return tools.filter((tool) => isToolAllowed(policy, tool.name, serverId));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function validateToolPolicyAgainstTools(
|
|
75
|
+
policy: ToolPolicy,
|
|
76
|
+
tools: Array<Pick<Tool, 'name'>>,
|
|
77
|
+
serverId?: string
|
|
78
|
+
): void {
|
|
79
|
+
if (policy.mode === 'all') return;
|
|
80
|
+
if (!serverId) {
|
|
81
|
+
throw new Error('Cannot validate MCP tool policy without a serverId');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const availableIds = new Set(tools.map((tool) => createToolId(serverId, tool.name)));
|
|
85
|
+
const unknownIds = policy.toolIds.filter((id) => !availableIds.has(id));
|
|
86
|
+
if (unknownIds.length > 0) {
|
|
87
|
+
throw new Error(`Unknown tool id(s) for this MCP session: ${unknownIds.join(', ')}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -14,6 +14,14 @@ export interface OAuthState {
|
|
|
14
14
|
|
|
15
15
|
export type SessionStatus = 'pending' | 'active';
|
|
16
16
|
|
|
17
|
+
export type ToolPolicyMode = 'all' | 'allowlist' | 'denylist';
|
|
18
|
+
|
|
19
|
+
export interface ToolPolicy {
|
|
20
|
+
mode: ToolPolicyMode;
|
|
21
|
+
toolIds: string[];
|
|
22
|
+
updatedAt: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
export interface Session {
|
|
18
26
|
sessionId: string;
|
|
19
27
|
serverId?: string; // Database server ID for mapping
|
|
@@ -37,6 +45,7 @@ export interface Session {
|
|
|
37
45
|
* - active: restorable session after successful connection/auth completion
|
|
38
46
|
*/
|
|
39
47
|
status?: SessionStatus;
|
|
48
|
+
toolPolicy?: ToolPolicy;
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
export interface SessionCredentials {
|
|
@@ -158,3 +167,5 @@ export interface SessionStore {
|
|
|
158
167
|
*/
|
|
159
168
|
disconnect(): Promise<void>;
|
|
160
169
|
}
|
|
170
|
+
|
|
171
|
+
|
package/src/shared/types.ts
CHANGED
|
@@ -21,6 +21,7 @@ export interface ToolClient {
|
|
|
21
21
|
callTool(name: string, args: Record<string, unknown>): Promise<any>;
|
|
22
22
|
getServerId?(): string | undefined;
|
|
23
23
|
getServerName?(): string | undefined;
|
|
24
|
+
getServerUrl?(): string | undefined;
|
|
24
25
|
getSessionId?(): string;
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -169,11 +170,19 @@ export type ToolInfo = {
|
|
|
169
170
|
// Transport type
|
|
170
171
|
export type TransportType = 'sse' | 'streamable-http';
|
|
171
172
|
export type SessionStatus = 'pending' | 'active';
|
|
173
|
+
export type ToolPolicyMode = 'all' | 'allowlist' | 'denylist';
|
|
174
|
+
|
|
175
|
+
export interface ToolPolicy {
|
|
176
|
+
mode: ToolPolicyMode;
|
|
177
|
+
toolIds: string[];
|
|
178
|
+
updatedAt: number;
|
|
179
|
+
}
|
|
172
180
|
|
|
173
181
|
// SSE/RPC types
|
|
174
182
|
export type McpRpcMethod =
|
|
175
183
|
| 'connect'
|
|
176
184
|
| 'disconnect'
|
|
185
|
+
| 'reconnect'
|
|
177
186
|
| 'listTools'
|
|
178
187
|
| 'callTool'
|
|
179
188
|
| 'listSessions'
|
|
@@ -182,7 +191,9 @@ export type McpRpcMethod =
|
|
|
182
191
|
| 'listPrompts'
|
|
183
192
|
| 'getPrompt'
|
|
184
193
|
| 'listResources'
|
|
185
|
-
| 'readResource'
|
|
194
|
+
| 'readResource'
|
|
195
|
+
| 'setToolPolicy'
|
|
196
|
+
| 'getToolPolicy';
|
|
186
197
|
|
|
187
198
|
export interface McpRpcRequest {
|
|
188
199
|
id: string;
|
|
@@ -213,6 +224,8 @@ export interface DisconnectParams {
|
|
|
213
224
|
sessionId: string;
|
|
214
225
|
}
|
|
215
226
|
|
|
227
|
+
export type ReconnectParams = ConnectParams;
|
|
228
|
+
|
|
216
229
|
export interface SessionParams {
|
|
217
230
|
sessionId: string;
|
|
218
231
|
}
|
|
@@ -239,14 +252,29 @@ export interface FinishAuthParams {
|
|
|
239
252
|
code: string;
|
|
240
253
|
}
|
|
241
254
|
|
|
255
|
+
export interface SetToolPolicyParams {
|
|
256
|
+
sessionId: string;
|
|
257
|
+
toolPolicy: {
|
|
258
|
+
mode: ToolPolicyMode;
|
|
259
|
+
toolIds?: string[];
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface GetToolPolicyParams {
|
|
264
|
+
sessionId: string;
|
|
265
|
+
}
|
|
266
|
+
|
|
242
267
|
export type McpRpcParams =
|
|
243
268
|
| ConnectParams
|
|
244
269
|
| DisconnectParams
|
|
270
|
+
| ReconnectParams
|
|
245
271
|
| SessionParams
|
|
246
272
|
| CallToolParams
|
|
247
273
|
| GetPromptParams
|
|
248
274
|
| ReadResourceParams
|
|
249
275
|
| FinishAuthParams
|
|
276
|
+
| SetToolPolicyParams
|
|
277
|
+
| GetToolPolicyParams
|
|
250
278
|
| undefined;
|
|
251
279
|
|
|
252
280
|
// RPC Result Types
|
|
@@ -263,6 +291,7 @@ export interface SessionInfo {
|
|
|
263
291
|
* `pending` means auth is in progress and should be resumed explicitly by user action.
|
|
264
292
|
*/
|
|
265
293
|
status: SessionStatus;
|
|
294
|
+
toolPolicy?: ToolPolicy;
|
|
266
295
|
}
|
|
267
296
|
|
|
268
297
|
export interface SessionListResult {
|
|
@@ -292,6 +321,25 @@ export interface ListToolsRpcResult {
|
|
|
292
321
|
tools: Tool[];
|
|
293
322
|
}
|
|
294
323
|
|
|
324
|
+
export interface SetToolPolicyResult {
|
|
325
|
+
success: boolean;
|
|
326
|
+
toolPolicy: ToolPolicy;
|
|
327
|
+
tools: Tool[];
|
|
328
|
+
toolCount: number;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export type ToolAccessInfo = Tool & {
|
|
332
|
+
toolId: string;
|
|
333
|
+
allowed: boolean;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
export interface GetToolPolicyResult {
|
|
337
|
+
toolPolicy: ToolPolicy;
|
|
338
|
+
tools: ToolAccessInfo[];
|
|
339
|
+
toolCount: number;
|
|
340
|
+
allowedToolCount: number;
|
|
341
|
+
}
|
|
342
|
+
|
|
295
343
|
export interface ListPromptsResult {
|
|
296
344
|
prompts: Array<{
|
|
297
345
|
name: string;
|
|
@@ -314,3 +362,6 @@ export interface ListResourcesResult {
|
|
|
314
362
|
}
|
|
315
363
|
|
|
316
364
|
export type { CallToolResult };
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|