@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.
Files changed (86) hide show
  1. package/dist/adapters/agui-adapter.d.mts +3 -3
  2. package/dist/adapters/agui-adapter.d.ts +3 -3
  3. package/dist/adapters/agui-adapter.js.map +1 -1
  4. package/dist/adapters/agui-adapter.mjs.map +1 -1
  5. package/dist/adapters/agui-middleware.d.mts +3 -3
  6. package/dist/adapters/agui-middleware.d.ts +3 -3
  7. package/dist/adapters/agui-middleware.js.map +1 -1
  8. package/dist/adapters/agui-middleware.mjs.map +1 -1
  9. package/dist/adapters/ai-adapter.d.mts +3 -3
  10. package/dist/adapters/ai-adapter.d.ts +3 -3
  11. package/dist/adapters/ai-adapter.js.map +1 -1
  12. package/dist/adapters/ai-adapter.mjs.map +1 -1
  13. package/dist/adapters/langchain-adapter.d.mts +3 -3
  14. package/dist/adapters/langchain-adapter.d.ts +3 -3
  15. package/dist/adapters/langchain-adapter.js +2 -2
  16. package/dist/adapters/langchain-adapter.js.map +1 -1
  17. package/dist/adapters/langchain-adapter.mjs +2 -2
  18. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  19. package/dist/adapters/mastra-adapter.d.mts +2 -2
  20. package/dist/adapters/mastra-adapter.d.ts +2 -2
  21. package/dist/adapters/mastra-adapter.js +2 -2
  22. package/dist/adapters/mastra-adapter.js.map +1 -1
  23. package/dist/adapters/mastra-adapter.mjs +2 -2
  24. package/dist/adapters/mastra-adapter.mjs.map +1 -1
  25. package/dist/client/index.d.mts +2 -2
  26. package/dist/client/index.d.ts +2 -2
  27. package/dist/client/index.js +9 -0
  28. package/dist/client/index.js.map +1 -1
  29. package/dist/client/index.mjs +9 -0
  30. package/dist/client/index.mjs.map +1 -1
  31. package/dist/client/react.d.mts +15 -4
  32. package/dist/client/react.d.ts +15 -4
  33. package/dist/client/react.js +56 -37
  34. package/dist/client/react.js.map +1 -1
  35. package/dist/client/react.mjs +56 -37
  36. package/dist/client/react.mjs.map +1 -1
  37. package/dist/client/vue.d.mts +4 -4
  38. package/dist/client/vue.d.ts +4 -4
  39. package/dist/client/vue.js +9 -0
  40. package/dist/client/vue.js.map +1 -1
  41. package/dist/client/vue.mjs +9 -0
  42. package/dist/client/vue.mjs.map +1 -1
  43. package/dist/{index-CZk2gu2E.d.ts → index-BEdyuz1M.d.ts} +6 -1
  44. package/dist/{index-CkM3p0eE.d.mts → index-C99wE2Zf.d.mts} +6 -1
  45. package/dist/index.d.mts +4 -4
  46. package/dist/index.d.ts +4 -4
  47. package/dist/index.js +380 -82
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs +376 -82
  50. package/dist/index.mjs.map +1 -1
  51. package/dist/{multi-session-client-QOOPdEVp.d.ts → multi-session-client-CclWRxTD.d.mts} +14 -2
  52. package/dist/{multi-session-client-ChQrBZhF.d.mts → multi-session-client-DzvZD6Tt.d.ts} +14 -2
  53. package/dist/server/index.d.mts +18 -4
  54. package/dist/server/index.d.ts +18 -4
  55. package/dist/server/index.js +371 -82
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/index.mjs +367 -82
  58. package/dist/server/index.mjs.map +1 -1
  59. package/dist/shared/index.d.mts +4 -4
  60. package/dist/shared/index.d.ts +4 -4
  61. package/dist/shared/index.js.map +1 -1
  62. package/dist/shared/index.mjs.map +1 -1
  63. package/dist/{tool-router-CGs3IDOJ.d.mts → tool-router-C9ECn3FX.d.mts} +1 -1
  64. package/dist/{tool-router-DQ-HrD7W.d.ts → tool-router-CUSSk6lT.d.ts} +1 -1
  65. package/dist/{types-Bf-7GOLW.d.mts → types-CbFbPkfQ.d.mts} +38 -3
  66. package/dist/{types-Bf-7GOLW.d.ts → types-CbFbPkfQ.d.ts} +38 -3
  67. package/migrations/neon/20260513010000_install_mcp_sessions.sql +1 -0
  68. package/migrations/supabase/20260330195700_install_mcp_sessions.sql +1 -0
  69. package/package.json +2 -2
  70. package/src/adapters/agui-adapter.ts +6 -2
  71. package/src/adapters/ai-adapter.ts +3 -1
  72. package/src/adapters/langchain-adapter.ts +5 -3
  73. package/src/adapters/mastra-adapter.ts +5 -3
  74. package/src/client/core/sse-client.ts +21 -0
  75. package/src/client/react/oauth-popup.tsx +17 -24
  76. package/src/client/react/use-mcp.ts +69 -15
  77. package/src/server/handlers/sse-handler.ts +202 -9
  78. package/src/server/mcp/multi-session-client.ts +7 -3
  79. package/src/server/mcp/oauth-client.ts +25 -10
  80. package/src/server/mcp/tool-policy-gateway.ts +90 -0
  81. package/src/server/storage/neon-backend.ts +65 -60
  82. package/src/server/storage/session-lifecycle.ts +5 -0
  83. package/src/server/storage/supabase-backend.ts +27 -15
  84. package/src/server/storage/tool-policy.ts +89 -0
  85. package/src/server/storage/types.ts +11 -0
  86. 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
+
@@ -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
+