@mcp-ts/sdk 1.6.2 → 2.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.
Files changed (113) hide show
  1. package/README.md +12 -6
  2. package/dist/adapters/agui-adapter.d.mts +3 -3
  3. package/dist/adapters/agui-adapter.d.ts +3 -3
  4. package/dist/adapters/agui-adapter.js +4 -5
  5. package/dist/adapters/agui-adapter.js.map +1 -1
  6. package/dist/adapters/agui-adapter.mjs +4 -5
  7. package/dist/adapters/agui-adapter.mjs.map +1 -1
  8. package/dist/adapters/agui-middleware.d.mts +3 -3
  9. package/dist/adapters/agui-middleware.d.ts +3 -3
  10. package/dist/adapters/ai-adapter.d.mts +9 -3
  11. package/dist/adapters/ai-adapter.d.ts +9 -3
  12. package/dist/adapters/ai-adapter.js +20 -6
  13. package/dist/adapters/ai-adapter.js.map +1 -1
  14. package/dist/adapters/ai-adapter.mjs +20 -6
  15. package/dist/adapters/ai-adapter.mjs.map +1 -1
  16. package/dist/adapters/langchain-adapter.d.mts +3 -3
  17. package/dist/adapters/langchain-adapter.d.ts +3 -3
  18. package/dist/adapters/langchain-adapter.js +9 -6
  19. package/dist/adapters/langchain-adapter.js.map +1 -1
  20. package/dist/adapters/langchain-adapter.mjs +9 -6
  21. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  22. package/dist/adapters/mastra-adapter.d.mts +1 -1
  23. package/dist/adapters/mastra-adapter.d.ts +1 -1
  24. package/dist/adapters/mastra-adapter.js +5 -1
  25. package/dist/adapters/mastra-adapter.js.map +1 -1
  26. package/dist/adapters/mastra-adapter.mjs +5 -1
  27. package/dist/adapters/mastra-adapter.mjs.map +1 -1
  28. package/dist/bin/mcp-ts.js +7 -1
  29. package/dist/bin/mcp-ts.js.map +1 -1
  30. package/dist/bin/mcp-ts.mjs +7 -1
  31. package/dist/bin/mcp-ts.mjs.map +1 -1
  32. package/dist/client/index.d.mts +2 -2
  33. package/dist/client/index.d.ts +2 -2
  34. package/dist/client/index.js +9 -13
  35. package/dist/client/index.js.map +1 -1
  36. package/dist/client/index.mjs +9 -13
  37. package/dist/client/index.mjs.map +1 -1
  38. package/dist/client/react.d.mts +7 -7
  39. package/dist/client/react.d.ts +7 -7
  40. package/dist/client/react.js +15 -19
  41. package/dist/client/react.js.map +1 -1
  42. package/dist/client/react.mjs +15 -19
  43. package/dist/client/react.mjs.map +1 -1
  44. package/dist/client/vue.d.mts +7 -7
  45. package/dist/client/vue.d.ts +7 -7
  46. package/dist/client/vue.js +14 -18
  47. package/dist/client/vue.js.map +1 -1
  48. package/dist/client/vue.mjs +14 -18
  49. package/dist/client/vue.mjs.map +1 -1
  50. package/dist/{index-DhA-OEAe.d.ts → index-C9gvpxy5.d.ts} +5 -5
  51. package/dist/{index-bFL4ZF2N.d.mts → index-eaH14_5u.d.mts} +5 -5
  52. package/dist/index.d.mts +6 -6
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +616 -370
  55. package/dist/index.js.map +1 -1
  56. package/dist/index.mjs +615 -370
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/{multi-session-client-CHE8QpVE.d.ts → multi-session-client-BYtguGJm.d.ts} +22 -22
  59. package/dist/{multi-session-client-CQsRbxYI.d.mts → multi-session-client-DYNe6az3.d.mts} +22 -22
  60. package/dist/server/index.d.mts +31 -34
  61. package/dist/server/index.d.ts +31 -34
  62. package/dist/server/index.js +531 -256
  63. package/dist/server/index.js.map +1 -1
  64. package/dist/server/index.mjs +530 -256
  65. package/dist/server/index.mjs.map +1 -1
  66. package/dist/shared/index.d.mts +5 -5
  67. package/dist/shared/index.d.ts +5 -5
  68. package/dist/shared/index.js +76 -101
  69. package/dist/shared/index.js.map +1 -1
  70. package/dist/shared/index.mjs +76 -101
  71. package/dist/shared/index.mjs.map +1 -1
  72. package/dist/{tool-router-Dh2804tM.d.ts → tool-router-Ddtybmr0.d.ts} +71 -73
  73. package/dist/{tool-router-BVaV1udm.d.mts → tool-router-Dnd6IOKC.d.mts} +71 -73
  74. package/dist/{types-rIuN1CQi.d.mts → types-BCAG20P6.d.mts} +4 -4
  75. package/dist/{types-rIuN1CQi.d.ts → types-BCAG20P6.d.ts} +4 -4
  76. package/dist/{utils-0qmYrqoa.d.mts → utils-DELRKQPU.d.mts} +1 -1
  77. package/dist/{utils-0qmYrqoa.d.ts → utils-DELRKQPU.d.ts} +1 -1
  78. package/migrations/neon/20260513010000_install_mcp_sessions.sql +69 -0
  79. package/migrations/neon/20260513020000_add_session_cleanup_cron.sql +35 -0
  80. package/{supabase/migrations → migrations/supabase}/20260330195700_install_mcp_sessions.sql +7 -9
  81. package/package.json +14 -5
  82. package/src/adapters/ai-adapter.ts +30 -1
  83. package/src/adapters/langchain-adapter.ts +6 -2
  84. package/src/adapters/mastra-adapter.ts +6 -2
  85. package/src/bin/mcp-ts.ts +8 -1
  86. package/src/client/core/app-host.ts +1 -1
  87. package/src/client/core/sse-client.ts +12 -14
  88. package/src/client/core/types.ts +1 -1
  89. package/src/client/react/use-mcp-apps.tsx +1 -1
  90. package/src/client/react/use-mcp.ts +11 -11
  91. package/src/client/vue/use-mcp.ts +10 -10
  92. package/src/server/handlers/nextjs-handler.ts +18 -15
  93. package/src/server/handlers/sse-handler.ts +29 -29
  94. package/src/server/index.ts +1 -1
  95. package/src/server/mcp/multi-session-client.ts +17 -17
  96. package/src/server/mcp/oauth-client.ts +37 -37
  97. package/src/server/mcp/storage-oauth-provider.ts +17 -17
  98. package/src/server/storage/file-backend.ts +25 -25
  99. package/src/server/storage/index.ts +67 -10
  100. package/src/server/storage/memory-backend.ts +34 -34
  101. package/src/server/storage/neon-backend.ts +281 -0
  102. package/src/server/storage/redis-backend.ts +64 -64
  103. package/src/server/storage/sqlite-backend.ts +33 -33
  104. package/src/server/storage/supabase-backend.ts +23 -24
  105. package/src/server/storage/types.ts +18 -21
  106. package/src/shared/errors.ts +1 -1
  107. package/src/shared/index.ts +1 -2
  108. package/src/shared/meta-tools.ts +4 -6
  109. package/src/shared/schema-compressor.ts +2 -42
  110. package/src/shared/tool-index.ts +89 -84
  111. package/src/shared/tool-router.ts +0 -24
  112. package/src/shared/types.ts +4 -4
  113. /package/{supabase/migrations → migrations/supabase}/20260421010000_add_session_cleanup_cron.sql +0 -0
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@mcp-ts/sdk",
3
- "version": "1.6.2",
3
+ "version": "2.0.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "description": "A lightweight MCP (Model Context Protocol) client library for JavaScript and cross-runtime environments, supporting MCP Apps in host applications and multiple storage backends (Memory, File, Redis, Supabase).",
7
+ "description": "A lightweight MCP (Model Context Protocol) client library for JavaScript and cross-runtime environments, supporting MCP Apps in host applications and multiple storage backends (Memory, File, Redis, Supabase, Neon).",
8
8
  "main": "./dist/index.js",
9
9
  "module": "./dist/index.mjs",
10
10
  "types": "./dist/index.d.ts",
@@ -71,7 +71,7 @@
71
71
  "files": [
72
72
  "dist",
73
73
  "src",
74
- "supabase",
74
+ "migrations",
75
75
  "README.md",
76
76
  "LICENSE"
77
77
  ],
@@ -117,13 +117,15 @@
117
117
  "peerDependencies": {
118
118
  "@ag-ui/client": ">=0.0.40",
119
119
  "@langchain/core": "^1.1.39",
120
+ "@neondatabase/serverless": "^1.1.0",
120
121
  "@supabase/supabase-js": "^2.0.0",
121
122
  "ai": "^6.0.0",
122
123
  "better-sqlite3": "^12.0.0",
123
124
  "ioredis": "^5.0.0",
124
125
  "react": ">=18.0.0",
125
126
  "rxjs": ">=7.0.0",
126
- "zod": "^3.23.0"
127
+ "zod": "^3.23.0",
128
+ "json-schema-to-zod": "^2.7.0"
127
129
  },
128
130
  "peerDependenciesMeta": {
129
131
  "react": {
@@ -135,6 +137,9 @@
135
137
  "@langchain/core": {
136
138
  "optional": true
137
139
  },
140
+ "@neondatabase/serverless": {
141
+ "optional": true
142
+ },
138
143
  "zod": {
139
144
  "optional": true
140
145
  },
@@ -152,18 +157,21 @@
152
157
  },
153
158
  "@supabase/supabase-js": {
154
159
  "optional": true
160
+ },
161
+ "json-schema-to-zod": {
162
+ "optional": true
155
163
  }
156
164
  },
157
165
  "dependencies": {
158
166
  "@modelcontextprotocol/ext-apps": "^1.5.0",
159
167
  "@modelcontextprotocol/sdk": "^1.29.0",
160
168
  "json-schema": "^0.4.0",
161
- "json-schema-to-zod": "^2.7.0",
162
169
  "nanoid": "^5.1.6"
163
170
  },
164
171
  "devDependencies": {
165
172
  "@ag-ui/client": "^0.0.52",
166
173
  "@langchain/core": "^1.1.39",
174
+ "@neondatabase/serverless": "^1.1.0",
167
175
  "@playwright/test": "^1.58.0",
168
176
  "@supabase/supabase-js": "^2.48.0",
169
177
  "@types/better-sqlite3": "^7.6.13",
@@ -175,6 +183,7 @@
175
183
  "better-sqlite3": "^12.6.2",
176
184
  "ioredis": "^5.9.2",
177
185
  "ioredis-mock": "^8.13.1",
186
+ "json-schema-to-zod": "^2.7.0",
178
187
  "playwright": "^1.58.0",
179
188
  "react": "^18.3.1",
180
189
  "react-dom": "^18.3.1",
@@ -22,6 +22,13 @@ export interface AIAdapterOptions {
22
22
  * When not provided, all tools are returned as before (backward-compatible).
23
23
  */
24
24
  toolRouter?: ToolRouter;
25
+
26
+ /**
27
+ * Optional custom callback to determine if a tool requires user approval.
28
+ * Can return a boolean or a Promise<boolean>.
29
+ * If not provided, defaults to checking the tool's `destructiveHint` annotation.
30
+ */
31
+ needsApproval?: (tool: any, args: any) => boolean | Promise<boolean>;
25
32
  }
26
33
 
27
34
  /**
@@ -80,7 +87,12 @@ export class AIAdapter {
80
87
  const errorMessage = error instanceof Error ? error.message : String(error);
81
88
  throw new Error(`Tool execution failed: ${errorMessage}`);
82
89
  }
83
- }
90
+ },
91
+ needsApproval: this.options.needsApproval
92
+ ? (args: any) => this.options.needsApproval!(tool, args)
93
+ : (tool.annotations as any)?.destructiveHint === true
94
+ ? () => true
95
+ : undefined
84
96
  }
85
97
  ];
86
98
  })
@@ -166,6 +178,23 @@ export class AIAdapter {
166
178
  // route directly to the correct MCP client
167
179
  return await router.callTool(tool.name, args, namespace);
168
180
  },
181
+ needsApproval: this.options.needsApproval
182
+ ? (args: any) => this.options.needsApproval!(tool, args)
183
+ : (args: any) => {
184
+ // Default HITL logic using annotations
185
+ if (tool.name === 'mcp_execute_tool') {
186
+ const targetToolName = String(args?.toolName ?? "");
187
+ const targetNamespace = String(args?.serverId ?? "") || undefined;
188
+ if (!targetToolName) return false;
189
+ try {
190
+ const targetTool = router.getToolSchema(targetToolName, targetNamespace);
191
+ return (targetTool as any)?.annotations?.destructiveHint === true;
192
+ } catch {
193
+ return false;
194
+ }
195
+ }
196
+ return (tool.annotations as any)?.destructiveHint === true;
197
+ }
169
198
  },
170
199
  ];
171
200
  })
@@ -96,9 +96,13 @@ export class LangChainAdapter {
96
96
  const zodSchemaString = parseSchema(schema);
97
97
  // eslint-disable-next-line
98
98
  return new Function('z', 'return ' + zodSchemaString)(this.z);
99
- } catch (error) {
99
+ } catch (error: any) {
100
100
  // Fallback: Accept any object if conversion fails
101
- console.warn('[LangChainAdapter] Failed to convert JSON Schema to Zod, using fallback:', error);
101
+ if (error.code === 'MODULE_NOT_FOUND') {
102
+ console.warn('[LangChainAdapter] json-schema-to-zod is not installed. To improve type checking, install it with: npm install json-schema-to-zod');
103
+ } else {
104
+ console.warn('[LangChainAdapter] Failed to convert JSON Schema to Zod, using fallback:', error);
105
+ }
102
106
  return this.z!.record(this.z!.any()).optional().describe("Dynamic Input");
103
107
  }
104
108
  }
@@ -87,9 +87,13 @@ export class MastraAdapter {
87
87
  const zodSchemaString = parseSchema(schema);
88
88
  // eslint-disable-next-line
89
89
  return new Function('z', 'return ' + zodSchemaString)(this.z);
90
- } catch (error) {
90
+ } catch (error: any) {
91
91
  // Fallback: Accept any object if conversion fails
92
- console.warn('[MastraAdapter] Failed to convert JSON Schema to Zod, using fallback:', error);
92
+ if (error.code === 'MODULE_NOT_FOUND') {
93
+ console.warn('[MastraAdapter] json-schema-to-zod is not installed. To improve type checking, install it with: npm install json-schema-to-zod');
94
+ } else {
95
+ console.warn('[MastraAdapter] Failed to convert JSON Schema to Zod, using fallback:', error);
96
+ }
93
97
  return this.z!.record(this.z!.any()).optional().describe("Dynamic Input");
94
98
  }
95
99
  }
package/src/bin/mcp-ts.ts CHANGED
@@ -35,7 +35,10 @@ async function initSupabase() {
35
35
  // The supabase/ migrations are at the root of the package.
36
36
  // We need to look up two levels to find 'supabase' folder in the package.
37
37
  const pkgRoot = path.resolve(__dirname, '../..');
38
- const sourceDir = path.join(pkgRoot, 'supabase', 'migrations');
38
+ const sourceDir = resolveFirstExistingPath([
39
+ path.join(pkgRoot, 'migrations', 'supabase'),
40
+ path.join(pkgRoot, 'supabase', 'migrations'),
41
+ ]);
39
42
 
40
43
  if (!fs.existsSync(sourceDir)) {
41
44
  console.error(`❌ Error: Could not find migration files in package at: ${sourceDir}`);
@@ -96,6 +99,10 @@ async function initSupabase() {
96
99
  }
97
100
  }
98
101
 
102
+ function resolveFirstExistingPath(paths: string[]): string {
103
+ return paths.find(candidate => fs.existsSync(candidate)) || paths[0];
104
+ }
105
+
99
106
  run().catch(err => {
100
107
  console.error(err);
101
108
  process.exit(1);
@@ -559,7 +559,7 @@ export class AppHost {
559
559
  private async getSessionId(): Promise<string | undefined> {
560
560
  if (this.sessionId) return this.sessionId;
561
561
  if (!this.client) return undefined;
562
- const result = await this.client.getSessions();
562
+ const result = await this.client.listSessions();
563
563
  return result.sessions?.[0]?.sessionId;
564
564
  }
565
565
 
@@ -20,7 +20,7 @@ import type {
20
20
  SessionListResult,
21
21
  ConnectResult,
22
22
  DisconnectResult,
23
- RestoreSessionResult,
23
+ GetSessionResult,
24
24
  FinishAuthResult,
25
25
  ListToolsRpcResult,
26
26
  ListPromptsResult,
@@ -32,7 +32,7 @@ export interface SSEClientOptions {
32
32
  url: string;
33
33
 
34
34
  /** User/Client identifier */
35
- identity: string;
35
+ userId: string;
36
36
 
37
37
  /** Optional auth token for authenticated requests */
38
38
  authToken?: string;
@@ -87,8 +87,8 @@ export class SSEClient {
87
87
  return this.connected;
88
88
  }
89
89
 
90
- async getSessions(): Promise<SessionListResult> {
91
- return this.sendRequest<SessionListResult>('getSessions');
90
+ async listSessions(): Promise<SessionListResult> {
91
+ return this.sendRequest<SessionListResult>('listSessions');
92
92
  }
93
93
 
94
94
  async connectToServer(params: ConnectParams): Promise<ConnectResult> {
@@ -113,8 +113,8 @@ export class SSEClient {
113
113
  return result;
114
114
  }
115
115
 
116
- async restoreSession(sessionId: string): Promise<RestoreSessionResult> {
117
- return this.sendRequest<RestoreSessionResult>('restoreSession', { sessionId });
116
+ async getSession(sessionId: string): Promise<GetSessionResult> {
117
+ return this.sendRequest<GetSessionResult>('getSession', { sessionId });
118
118
  }
119
119
 
120
120
  async finishAuth(sessionId: string, code: string): Promise<FinishAuthResult> {
@@ -198,7 +198,7 @@ export class SSEClient {
198
198
  const data = await this.readRpcResponseFromStream(response, {
199
199
  delayConnectionEvents:
200
200
  method === 'connect' ||
201
- method === 'restoreSession' ||
201
+ method === 'getSession' ||
202
202
  method === 'finishAuth',
203
203
  });
204
204
  return this.parseRpcResponse<T>(data);
@@ -311,22 +311,20 @@ export class SSEClient {
311
311
  }
312
312
 
313
313
  private buildUrl(): string {
314
- const url = new URL(this.options.url, globalThis.location?.origin);
315
- url.searchParams.set('identity', this.options.identity);
316
- if (this.options.authToken) {
317
- url.searchParams.set('token', this.options.authToken);
318
- }
319
- return url.toString();
314
+ return new URL(this.options.url, globalThis.location?.origin).toString();
320
315
  }
321
316
 
322
317
  private buildHeaders(): HeadersInit {
323
- const headers: HeadersInit = {
318
+ const headers: Record<string, string> = {
324
319
  'Content-Type': 'application/json',
325
320
  'Accept': 'text/event-stream',
321
+ 'x-mcp-user-id': this.options.userId,
326
322
  };
323
+
327
324
  if (this.options.authToken) {
328
325
  headers['Authorization'] = `Bearer ${this.options.authToken}`;
329
326
  }
327
+
330
328
  return headers;
331
329
  }
332
330
 
@@ -17,7 +17,7 @@ export interface AppHostClient {
17
17
  /**
18
18
  * Get list of active sessions
19
19
  */
20
- getSessions(): Promise<SessionListResult>;
20
+ listSessions(): Promise<SessionListResult>;
21
21
 
22
22
  /**
23
23
  * Call a tool on a specific session
@@ -72,7 +72,7 @@ export interface McpAppRendererProps extends Pick<UseAppHostOptions, 'sandbox' |
72
72
 
73
73
  type McpAppViewProps = McpAppRendererProps & {
74
74
  /**
75
- * Ref avoids tying `McpAppRenderer` identity to `mcpClient`: when `connections` updates, `useMcp()` still
75
+ * Ref avoids tying `McpAppRenderer` userId to `mcpClient`: when `connections` updates, `useMcp()` still
76
76
  * returns a new object (correct for `useEffect` deps), but the iframe must not remount.
77
77
  */
78
78
  clientRef: MutableRefObject<McpClient | null>;
@@ -25,7 +25,7 @@ export interface UseMcpOptions {
25
25
  /**
26
26
  * User/Client identifier
27
27
  */
28
- identity: string;
28
+ userId: string;
29
29
 
30
30
  /**
31
31
  * Optional auth token
@@ -110,7 +110,7 @@ export interface McpClient {
110
110
  serverName: string;
111
111
  serverUrl: string;
112
112
  callbackUrl: string;
113
- transportType?: 'sse' | 'streamable_http';
113
+ transportType?: 'sse' | 'streamable-http';
114
114
  }) => Promise<string>;
115
115
 
116
116
  /**
@@ -126,7 +126,7 @@ export interface McpClient {
126
126
  serverName: string;
127
127
  serverUrl: string;
128
128
  callbackUrl: string;
129
- transportType?: 'sse' | 'streamable_http';
129
+ transportType?: 'sse' | 'streamable-http';
130
130
  }) => Promise<string>;
131
131
 
132
132
  /**
@@ -220,7 +220,7 @@ export interface McpClient {
220
220
  export function useMcp(options: UseMcpOptions): McpClient {
221
221
  const {
222
222
  url,
223
- identity,
223
+ userId,
224
224
  authToken,
225
225
  autoConnect = true,
226
226
  autoInitialize = true,
@@ -249,7 +249,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
249
249
 
250
250
  const clientOptions: SSEClientOptions = {
251
251
  url,
252
- identity,
252
+ userId,
253
253
  authToken,
254
254
  onConnectionEvent: (event) => {
255
255
  // Update local state based on event
@@ -285,7 +285,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
285
285
  isMountedRef.current = false;
286
286
  client.disconnect();
287
287
  };
288
- }, [url, identity, authToken, autoConnect, autoInitialize]);
288
+ }, [url, userId, authToken, autoConnect, autoInitialize]);
289
289
 
290
290
  /**
291
291
  * Update connections based on event
@@ -441,7 +441,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
441
441
  try {
442
442
  setIsInitializing(true);
443
443
 
444
- const result = await clientRef.current.getSessions();
444
+ const result = await clientRef.current.listSessions();
445
445
  const sessions = result.sessions || [];
446
446
 
447
447
  // Initialize connections
@@ -470,7 +470,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
470
470
  return;
471
471
  }
472
472
  suppressAuthRedirectSessionsRef.current.add(session.sessionId);
473
- await clientRef.current.restoreSession(session.sessionId);
473
+ await clientRef.current.getSession(session.sessionId);
474
474
  } catch (error) {
475
475
  console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);
476
476
  } finally {
@@ -498,7 +498,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
498
498
  serverName: string;
499
499
  serverUrl: string;
500
500
  callbackUrl: string;
501
- transportType?: 'sse' | 'streamable_http';
501
+ transportType?: 'sse' | 'streamable-http';
502
502
  }): Promise<string> => {
503
503
  if (!clientRef.current) {
504
504
  throw new Error('SSE client not initialized');
@@ -519,7 +519,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
519
519
  serverName: string;
520
520
  serverUrl: string;
521
521
  callbackUrl: string;
522
- transportType?: 'sse' | 'streamable_http';
522
+ transportType?: 'sse' | 'streamable-http';
523
523
  }): Promise<string> => {
524
524
  if (!clientRef.current) {
525
525
  throw new Error('SSE client not initialized');
@@ -602,7 +602,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
602
602
  }
603
603
  // Ensure this attempt is not suppressed as background restore.
604
604
  suppressAuthRedirectSessionsRef.current.delete(sessionId);
605
- await clientRef.current.restoreSession(sessionId);
605
+ await clientRef.current.getSession(sessionId);
606
606
  }, []);
607
607
 
608
608
  /**
@@ -25,7 +25,7 @@ export interface UseMcpOptions {
25
25
  /**
26
26
  * User/Client identifier
27
27
  */
28
- identity: string;
28
+ userId: string;
29
29
 
30
30
  /**
31
31
  * Optional auth token
@@ -109,7 +109,7 @@ export interface McpClient {
109
109
  serverName: string;
110
110
  serverUrl: string;
111
111
  callbackUrl: string;
112
- transportType?: 'sse' | 'streamable_http';
112
+ transportType?: 'sse' | 'streamable-http';
113
113
  }) => Promise<string>;
114
114
 
115
115
  /**
@@ -125,7 +125,7 @@ export interface McpClient {
125
125
  serverName: string;
126
126
  serverUrl: string;
127
127
  callbackUrl: string;
128
- transportType?: 'sse' | 'streamable_http';
128
+ transportType?: 'sse' | 'streamable-http';
129
129
  }) => Promise<string>;
130
130
 
131
131
  /**
@@ -219,7 +219,7 @@ export interface McpClient {
219
219
  export function useMcp(options: UseMcpOptions): McpClient {
220
220
  const {
221
221
  url,
222
- identity,
222
+ userId,
223
223
  authToken,
224
224
  autoConnect = true,
225
225
  autoInitialize = true,
@@ -386,7 +386,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
386
386
  try {
387
387
  isInitializing.value = true;
388
388
 
389
- const result = await clientRef.value.getSessions();
389
+ const result = await clientRef.value.listSessions();
390
390
  const sessions = result.sessions || [];
391
391
 
392
392
  // Initialize connections
@@ -413,7 +413,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
413
413
  return;
414
414
  }
415
415
  suppressAuthRedirectSessions.value.add(session.sessionId);
416
- await clientRef.value.restoreSession(session.sessionId);
416
+ await clientRef.value.getSession(session.sessionId);
417
417
  } catch (error) {
418
418
  console.error(`[useMcp] Failed to validate session ${session.sessionId}:`, error);
419
419
  } finally {
@@ -443,7 +443,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
443
443
 
444
444
  const clientOptions: SSEClientOptions = {
445
445
  url,
446
- identity,
446
+ userId,
447
447
  authToken,
448
448
  onConnectionEvent: (event) => {
449
449
  // Update local state based on event
@@ -493,7 +493,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
493
493
  serverName: string;
494
494
  serverUrl: string;
495
495
  callbackUrl: string;
496
- transportType?: 'sse' | 'streamable_http';
496
+ transportType?: 'sse' | 'streamable-http';
497
497
  }): Promise<string> => {
498
498
  if (!clientRef.value) {
499
499
  throw new Error('SSE client not initialized');
@@ -511,7 +511,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
511
511
  serverName: string;
512
512
  serverUrl: string;
513
513
  callbackUrl: string;
514
- transportType?: 'sse' | 'streamable_http';
514
+ transportType?: 'sse' | 'streamable-http';
515
515
  }): Promise<string> => {
516
516
  if (!clientRef.value) {
517
517
  throw new Error('SSE client not initialized');
@@ -589,7 +589,7 @@ export function useMcp(options: UseMcpOptions): McpClient {
589
589
  throw new Error('SSE client not initialized');
590
590
  }
591
591
  suppressAuthRedirectSessions.value.delete(sessionId);
592
- await clientRef.value.restoreSession(sessionId);
592
+ await clientRef.value.getSession(sessionId);
593
593
  };
594
594
 
595
595
  /**
@@ -12,9 +12,9 @@ import type { McpRpcResponse } from '../../shared/types.js';
12
12
 
13
13
  export interface NextMcpHandlerOptions {
14
14
  /**
15
- * Extract identity from request (default: from 'identity' query param)
15
+ * Extract userId from request (default: from 'userId' query param)
16
16
  */
17
- getIdentity?: (request: Request) => string | null;
17
+ getUserId?: (request: Request) => string | null;
18
18
 
19
19
  /**
20
20
  * Extract auth token from request (default: from 'token' query param or Authorization header)
@@ -25,7 +25,7 @@ export interface NextMcpHandlerOptions {
25
25
  * Authenticate user and verify access (optional)
26
26
  * Return true if user is authenticated, false otherwise
27
27
  */
28
- authenticate?: (identity: string, token: string | null) => Promise<boolean> | boolean;
28
+ authenticate?: (userId: string, token: string | null) => Promise<boolean> | boolean;
29
29
 
30
30
  /**
31
31
  * Heartbeat interval in milliseconds (default: 30000)
@@ -45,10 +45,13 @@ export interface NextMcpHandlerOptions {
45
45
 
46
46
  export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
47
47
  const {
48
- getIdentity = (request: Request) => new URL(request.url).searchParams.get('identity'),
48
+ getUserId = (request: Request) => request.headers.get('x-mcp-user-id'),
49
49
  getAuthToken = (request: Request) => {
50
- const url = new URL(request.url);
51
- return url.searchParams.get('token') || request.headers.get('authorization');
50
+ const authHeader = request.headers.get('authorization');
51
+ if (authHeader?.toLowerCase().startsWith('bearer ')) {
52
+ return authHeader.slice(7);
53
+ }
54
+ return authHeader;
52
55
  },
53
56
  authenticate = () => true,
54
57
  heartbeatInterval = 30000,
@@ -56,8 +59,8 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
56
59
  getClientMetadata,
57
60
  } = options;
58
61
 
59
- const toManagerOptions = (identity: string, resolvedClientMetadata?: ClientMetadata) => ({
60
- identity,
62
+ const toManagerOptions = (userId: string, resolvedClientMetadata?: ClientMetadata) => ({
63
+ userId,
61
64
  heartbeatInterval,
62
65
  clientDefaults: resolvedClientMetadata,
63
66
  });
@@ -79,15 +82,15 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
79
82
  }
80
83
 
81
84
  async function POST(request: Request): Promise<Response> {
82
- const identity = getIdentity(request);
85
+ const userId = getUserId(request);
83
86
  const authToken = getAuthToken(request);
84
87
  const acceptsEventStream = (request.headers.get('accept') || '').toLowerCase().includes('text/event-stream');
85
88
 
86
- if (!identity) {
87
- return Response.json({ error: { code: 'MISSING_IDENTITY', message: 'Missing identity' } }, { status: 400 });
89
+ if (!userId) {
90
+ return Response.json({ error: { code: 'MISSING_userId', message: 'Missing userId' } }, { status: 400 });
88
91
  }
89
92
 
90
- const isAuthorized = await authenticate(identity, authToken);
93
+ const isAuthorized = await authenticate(userId, authToken);
91
94
  if (!isAuthorized) {
92
95
  return Response.json({ error: { code: 'UNAUTHORIZED', message: 'Unauthorized' } }, { status: 401 });
93
96
  }
@@ -113,7 +116,7 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
113
116
 
114
117
  if (!acceptsEventStream) {
115
118
  const manager = new SSEConnectionManager(
116
- toManagerOptions(identity, resolvedClientMetadata),
119
+ toManagerOptions(userId, resolvedClientMetadata),
117
120
  () => { }
118
121
  );
119
122
  try {
@@ -138,7 +141,7 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
138
141
  };
139
142
 
140
143
  const manager = new SSEConnectionManager(
141
- toManagerOptions(identity, resolvedClientMetadata),
144
+ toManagerOptions(userId, resolvedClientMetadata),
142
145
  (event: McpConnectionEvent | McpObservabilityEvent | McpRpcResponse) => {
143
146
  if (isRpcResponseEvent(event)) {
144
147
  sendSSE('rpc-response', event);
@@ -183,7 +186,7 @@ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
183
186
  } catch (error) {
184
187
  const err = error instanceof Error ? error : new Error('Unknown error');
185
188
  console.error('[MCP Next Handler] Failed to handle RPC', {
186
- identity,
189
+ userId,
187
190
  message: err.message,
188
191
  stack: err.stack,
189
192
  rawBody: rawBody.slice(0, 500),