@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.
Files changed (103) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +398 -404
  3. package/dist/adapters/agui-adapter.d.mts +1 -1
  4. package/dist/adapters/agui-adapter.d.ts +1 -1
  5. package/dist/adapters/agui-adapter.js +2 -2
  6. package/dist/adapters/agui-adapter.js.map +1 -1
  7. package/dist/adapters/agui-adapter.mjs +2 -2
  8. package/dist/adapters/agui-adapter.mjs.map +1 -1
  9. package/dist/adapters/agui-middleware.d.mts +1 -1
  10. package/dist/adapters/agui-middleware.d.ts +1 -1
  11. package/dist/adapters/agui-middleware.js.map +1 -1
  12. package/dist/adapters/agui-middleware.mjs.map +1 -1
  13. package/dist/adapters/ai-adapter.d.mts +1 -1
  14. package/dist/adapters/ai-adapter.d.ts +1 -1
  15. package/dist/adapters/ai-adapter.js +1 -1
  16. package/dist/adapters/ai-adapter.js.map +1 -1
  17. package/dist/adapters/ai-adapter.mjs +1 -1
  18. package/dist/adapters/ai-adapter.mjs.map +1 -1
  19. package/dist/adapters/langchain-adapter.d.mts +1 -1
  20. package/dist/adapters/langchain-adapter.d.ts +1 -1
  21. package/dist/adapters/langchain-adapter.js +1 -1
  22. package/dist/adapters/langchain-adapter.js.map +1 -1
  23. package/dist/adapters/langchain-adapter.mjs +1 -1
  24. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  25. package/dist/adapters/mastra-adapter.d.mts +1 -1
  26. package/dist/adapters/mastra-adapter.d.ts +1 -1
  27. package/dist/adapters/mastra-adapter.js +1 -1
  28. package/dist/adapters/mastra-adapter.js.map +1 -1
  29. package/dist/adapters/mastra-adapter.mjs +1 -1
  30. package/dist/adapters/mastra-adapter.mjs.map +1 -1
  31. package/dist/bin/mcp-ts.js +0 -0
  32. package/dist/bin/mcp-ts.js.map +1 -1
  33. package/dist/bin/mcp-ts.mjs +0 -0
  34. package/dist/bin/mcp-ts.mjs.map +1 -1
  35. package/dist/client/index.js.map +1 -1
  36. package/dist/client/index.mjs.map +1 -1
  37. package/dist/client/react.d.mts +2 -2
  38. package/dist/client/react.d.ts +2 -2
  39. package/dist/client/react.js +25 -2
  40. package/dist/client/react.js.map +1 -1
  41. package/dist/client/react.mjs +26 -3
  42. package/dist/client/react.mjs.map +1 -1
  43. package/dist/client/vue.js.map +1 -1
  44. package/dist/client/vue.mjs.map +1 -1
  45. package/dist/index.d.mts +1 -1
  46. package/dist/index.d.ts +1 -1
  47. package/dist/index.js +134 -71
  48. package/dist/index.js.map +1 -1
  49. package/dist/index.mjs +134 -71
  50. package/dist/index.mjs.map +1 -1
  51. package/dist/{multi-session-client-BYLarghq.d.ts → multi-session-client-CHE8QpVE.d.ts} +75 -5
  52. package/dist/{multi-session-client-CzhMkE0k.d.mts → multi-session-client-CQsRbxYI.d.mts} +75 -5
  53. package/dist/server/index.d.mts +1 -1
  54. package/dist/server/index.d.ts +1 -1
  55. package/dist/server/index.js +134 -71
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/index.mjs +134 -71
  58. package/dist/server/index.mjs.map +1 -1
  59. package/dist/shared/index.js +10 -2
  60. package/dist/shared/index.js.map +1 -1
  61. package/dist/shared/index.mjs +10 -2
  62. package/dist/shared/index.mjs.map +1 -1
  63. package/package.json +185 -185
  64. package/src/adapters/agui-adapter.ts +222 -222
  65. package/src/adapters/agui-middleware.ts +382 -382
  66. package/src/adapters/ai-adapter.ts +115 -115
  67. package/src/adapters/langchain-adapter.ts +127 -127
  68. package/src/adapters/mastra-adapter.ts +126 -126
  69. package/src/bin/mcp-ts.ts +102 -102
  70. package/src/client/core/app-host.ts +417 -417
  71. package/src/client/core/sse-client.ts +371 -371
  72. package/src/client/core/types.ts +31 -31
  73. package/src/client/index.ts +27 -27
  74. package/src/client/react/index.ts +16 -16
  75. package/src/client/react/use-app-host.ts +73 -73
  76. package/src/client/react/use-mcp-apps.tsx +247 -214
  77. package/src/client/react/use-mcp.ts +641 -641
  78. package/src/client/vue/index.ts +10 -10
  79. package/src/client/vue/use-mcp.ts +617 -617
  80. package/src/index.ts +11 -11
  81. package/src/server/handlers/nextjs-handler.ts +204 -204
  82. package/src/server/handlers/sse-handler.ts +631 -631
  83. package/src/server/index.ts +57 -57
  84. package/src/server/mcp/multi-session-client.ts +228 -132
  85. package/src/server/mcp/oauth-client.ts +1188 -1188
  86. package/src/server/mcp/storage-oauth-provider.ts +272 -272
  87. package/src/server/storage/file-backend.ts +157 -170
  88. package/src/server/storage/index.ts +176 -175
  89. package/src/server/storage/memory-backend.ts +123 -136
  90. package/src/server/storage/redis-backend.ts +276 -289
  91. package/src/server/storage/redis.ts +160 -160
  92. package/src/server/storage/sqlite-backend.ts +182 -186
  93. package/src/server/storage/supabase-backend.ts +228 -227
  94. package/src/server/storage/types.ts +116 -116
  95. package/src/shared/constants.ts +29 -29
  96. package/src/shared/errors.ts +133 -133
  97. package/src/shared/event-routing.ts +28 -28
  98. package/src/shared/events.ts +180 -180
  99. package/src/shared/index.ts +75 -75
  100. package/src/shared/tool-utils.ts +61 -61
  101. package/src/shared/types.ts +282 -282
  102. package/src/shared/utils.ts +38 -16
  103. package/supabase/migrations/20260330195700_install_mcp_sessions.sql +84 -84
package/src/index.ts CHANGED
@@ -1,11 +1,11 @@
1
- /**
2
- * MCP Redis
3
- * Redis-backed MCP client with OAuth 2.1 and real-time SSE connections
4
- *
5
- * @packageDocumentation
6
- */
7
-
8
- // Re-export everything from subpackages
9
- export * from './server';
10
- export * from './client';
11
- export * from './shared';
1
+ /**
2
+ * MCP Redis
3
+ * Redis-backed MCP client with OAuth 2.1 and real-time SSE connections
4
+ *
5
+ * @packageDocumentation
6
+ */
7
+
8
+ // Re-export everything from subpackages
9
+ export * from './server';
10
+ export * from './client';
11
+ export * from './shared';
@@ -1,204 +1,204 @@
1
- /**
2
- * Next.js App Router Handler for MCP
3
- * Stateless transport for serverless environments:
4
- * - POST + `Accept: text/event-stream` streams progress + rpc-response
5
- * - POST + JSON accepts direct RPC result response
6
- */
7
-
8
- import { SSEConnectionManager, type ClientMetadata } from './sse-handler.js';
9
- import type { McpConnectionEvent, McpObservabilityEvent } from '../../shared/events.js';
10
- import { isConnectionEvent, isRpcResponseEvent } from '../../shared/event-routing.js';
11
- import type { McpRpcResponse } from '../../shared/types.js';
12
-
13
- export interface NextMcpHandlerOptions {
14
- /**
15
- * Extract identity from request (default: from 'identity' query param)
16
- */
17
- getIdentity?: (request: Request) => string | null;
18
-
19
- /**
20
- * Extract auth token from request (default: from 'token' query param or Authorization header)
21
- */
22
- getAuthToken?: (request: Request) => string | null;
23
-
24
- /**
25
- * Authenticate user and verify access (optional)
26
- * Return true if user is authenticated, false otherwise
27
- */
28
- authenticate?: (identity: string, token: string | null) => Promise<boolean> | boolean;
29
-
30
- /**
31
- * Heartbeat interval in milliseconds (default: 30000)
32
- */
33
- heartbeatInterval?: number;
34
-
35
- /**
36
- * Static OAuth client metadata defaults (for all connections)
37
- */
38
- clientDefaults?: ClientMetadata;
39
-
40
- /**
41
- * Dynamic OAuth client metadata getter (per-request)
42
- */
43
- getClientMetadata?: (request: Request) => ClientMetadata | Promise<ClientMetadata>;
44
- }
45
-
46
- export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
47
- const {
48
- getIdentity = (request: Request) => new URL(request.url).searchParams.get('identity'),
49
- getAuthToken = (request: Request) => {
50
- const url = new URL(request.url);
51
- return url.searchParams.get('token') || request.headers.get('authorization');
52
- },
53
- authenticate = () => true,
54
- heartbeatInterval = 30000,
55
- clientDefaults,
56
- getClientMetadata,
57
- } = options;
58
-
59
- const toManagerOptions = (identity: string, resolvedClientMetadata?: ClientMetadata) => ({
60
- identity,
61
- heartbeatInterval,
62
- clientDefaults: resolvedClientMetadata,
63
- });
64
-
65
- async function resolveClientMetadata(request: Request): Promise<ClientMetadata | undefined> {
66
- return getClientMetadata ? await getClientMetadata(request) : clientDefaults;
67
- }
68
-
69
- async function GET(): Promise<Response> {
70
- return Response.json(
71
- {
72
- error: {
73
- code: 'METHOD_NOT_ALLOWED',
74
- message: 'Use POST /api/mcp. For streaming use Accept: text/event-stream.',
75
- },
76
- },
77
- { status: 405 }
78
- );
79
- }
80
-
81
- async function POST(request: Request): Promise<Response> {
82
- const identity = getIdentity(request);
83
- const authToken = getAuthToken(request);
84
- const acceptsEventStream = (request.headers.get('accept') || '').toLowerCase().includes('text/event-stream');
85
-
86
- if (!identity) {
87
- return Response.json({ error: { code: 'MISSING_IDENTITY', message: 'Missing identity' } }, { status: 400 });
88
- }
89
-
90
- const isAuthorized = await authenticate(identity, authToken);
91
- if (!isAuthorized) {
92
- return Response.json({ error: { code: 'UNAUTHORIZED', message: 'Unauthorized' } }, { status: 401 });
93
- }
94
-
95
- let rawBody = '';
96
- try {
97
- rawBody = await request.text();
98
- const body = rawBody ? JSON.parse(rawBody) : null;
99
-
100
- if (!body || typeof body !== 'object') {
101
- return Response.json(
102
- {
103
- error: {
104
- code: 'INVALID_REQUEST',
105
- message: 'Invalid JSON-RPC request body',
106
- },
107
- },
108
- { status: 400 }
109
- );
110
- }
111
-
112
- const resolvedClientMetadata = await resolveClientMetadata(request);
113
-
114
- if (!acceptsEventStream) {
115
- const manager = new SSEConnectionManager(
116
- toManagerOptions(identity, resolvedClientMetadata),
117
- () => { }
118
- );
119
- try {
120
- const response = await manager.handleRequest(body as any);
121
- return Response.json(response);
122
- } finally {
123
- manager.dispose();
124
- }
125
- }
126
-
127
- const stream = new TransformStream();
128
- const writer = stream.writable.getWriter();
129
- const encoder = new TextEncoder();
130
- let streamWritable = true;
131
-
132
- const sendSSE = (event: string, data: unknown) => {
133
- if (!streamWritable) return;
134
- const message = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
135
- writer.write(encoder.encode(message)).catch(() => {
136
- streamWritable = false;
137
- });
138
- };
139
-
140
- const manager = new SSEConnectionManager(
141
- toManagerOptions(identity, resolvedClientMetadata),
142
- (event: McpConnectionEvent | McpObservabilityEvent | McpRpcResponse) => {
143
- if (isRpcResponseEvent(event)) {
144
- sendSSE('rpc-response', event);
145
- } else if (isConnectionEvent(event)) {
146
- sendSSE('connection', event);
147
- } else {
148
- sendSSE('observability', event);
149
- }
150
- }
151
- );
152
-
153
- sendSSE('connected', { timestamp: Date.now() });
154
-
155
- void (async () => {
156
- try {
157
- await manager.handleRequest(body as any);
158
- } catch (error) {
159
- const err = error instanceof Error ? error : new Error('Unknown error');
160
- sendSSE('rpc-response', {
161
- id: (body as any).id || 'unknown',
162
- error: {
163
- code: 'EXECUTION_ERROR',
164
- message: err.message,
165
- },
166
- } satisfies McpRpcResponse);
167
- } finally {
168
- streamWritable = false;
169
- manager.dispose();
170
- writer.close().catch(() => { });
171
- }
172
- })();
173
-
174
- return new Response(stream.readable, {
175
- status: 200,
176
- headers: {
177
- 'Content-Type': 'text/event-stream',
178
- 'Cache-Control': 'no-cache, no-transform',
179
- 'Connection': 'keep-alive',
180
- 'X-Accel-Buffering': 'no',
181
- },
182
- });
183
- } catch (error) {
184
- const err = error instanceof Error ? error : new Error('Unknown error');
185
- console.error('[MCP Next Handler] Failed to handle RPC', {
186
- identity,
187
- message: err.message,
188
- stack: err.stack,
189
- rawBody: rawBody.slice(0, 500),
190
- });
191
- return Response.json(
192
- {
193
- error: {
194
- code: 'EXECUTION_ERROR',
195
- message: err.message,
196
- },
197
- },
198
- { status: 500 }
199
- );
200
- }
201
- }
202
-
203
- return { GET, POST };
204
- }
1
+ /**
2
+ * Next.js App Router Handler for MCP
3
+ * Stateless transport for serverless environments:
4
+ * - POST + `Accept: text/event-stream` streams progress + rpc-response
5
+ * - POST + JSON accepts direct RPC result response
6
+ */
7
+
8
+ import { SSEConnectionManager, type ClientMetadata } from './sse-handler.js';
9
+ import type { McpConnectionEvent, McpObservabilityEvent } from '../../shared/events.js';
10
+ import { isConnectionEvent, isRpcResponseEvent } from '../../shared/event-routing.js';
11
+ import type { McpRpcResponse } from '../../shared/types.js';
12
+
13
+ export interface NextMcpHandlerOptions {
14
+ /**
15
+ * Extract identity from request (default: from 'identity' query param)
16
+ */
17
+ getIdentity?: (request: Request) => string | null;
18
+
19
+ /**
20
+ * Extract auth token from request (default: from 'token' query param or Authorization header)
21
+ */
22
+ getAuthToken?: (request: Request) => string | null;
23
+
24
+ /**
25
+ * Authenticate user and verify access (optional)
26
+ * Return true if user is authenticated, false otherwise
27
+ */
28
+ authenticate?: (identity: string, token: string | null) => Promise<boolean> | boolean;
29
+
30
+ /**
31
+ * Heartbeat interval in milliseconds (default: 30000)
32
+ */
33
+ heartbeatInterval?: number;
34
+
35
+ /**
36
+ * Static OAuth client metadata defaults (for all connections)
37
+ */
38
+ clientDefaults?: ClientMetadata;
39
+
40
+ /**
41
+ * Dynamic OAuth client metadata getter (per-request)
42
+ */
43
+ getClientMetadata?: (request: Request) => ClientMetadata | Promise<ClientMetadata>;
44
+ }
45
+
46
+ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
47
+ const {
48
+ getIdentity = (request: Request) => new URL(request.url).searchParams.get('identity'),
49
+ getAuthToken = (request: Request) => {
50
+ const url = new URL(request.url);
51
+ return url.searchParams.get('token') || request.headers.get('authorization');
52
+ },
53
+ authenticate = () => true,
54
+ heartbeatInterval = 30000,
55
+ clientDefaults,
56
+ getClientMetadata,
57
+ } = options;
58
+
59
+ const toManagerOptions = (identity: string, resolvedClientMetadata?: ClientMetadata) => ({
60
+ identity,
61
+ heartbeatInterval,
62
+ clientDefaults: resolvedClientMetadata,
63
+ });
64
+
65
+ async function resolveClientMetadata(request: Request): Promise<ClientMetadata | undefined> {
66
+ return getClientMetadata ? await getClientMetadata(request) : clientDefaults;
67
+ }
68
+
69
+ async function GET(): Promise<Response> {
70
+ return Response.json(
71
+ {
72
+ error: {
73
+ code: 'METHOD_NOT_ALLOWED',
74
+ message: 'Use POST /api/mcp. For streaming use Accept: text/event-stream.',
75
+ },
76
+ },
77
+ { status: 405 }
78
+ );
79
+ }
80
+
81
+ async function POST(request: Request): Promise<Response> {
82
+ const identity = getIdentity(request);
83
+ const authToken = getAuthToken(request);
84
+ const acceptsEventStream = (request.headers.get('accept') || '').toLowerCase().includes('text/event-stream');
85
+
86
+ if (!identity) {
87
+ return Response.json({ error: { code: 'MISSING_IDENTITY', message: 'Missing identity' } }, { status: 400 });
88
+ }
89
+
90
+ const isAuthorized = await authenticate(identity, authToken);
91
+ if (!isAuthorized) {
92
+ return Response.json({ error: { code: 'UNAUTHORIZED', message: 'Unauthorized' } }, { status: 401 });
93
+ }
94
+
95
+ let rawBody = '';
96
+ try {
97
+ rawBody = await request.text();
98
+ const body = rawBody ? JSON.parse(rawBody) : null;
99
+
100
+ if (!body || typeof body !== 'object') {
101
+ return Response.json(
102
+ {
103
+ error: {
104
+ code: 'INVALID_REQUEST',
105
+ message: 'Invalid JSON-RPC request body',
106
+ },
107
+ },
108
+ { status: 400 }
109
+ );
110
+ }
111
+
112
+ const resolvedClientMetadata = await resolveClientMetadata(request);
113
+
114
+ if (!acceptsEventStream) {
115
+ const manager = new SSEConnectionManager(
116
+ toManagerOptions(identity, resolvedClientMetadata),
117
+ () => { }
118
+ );
119
+ try {
120
+ const response = await manager.handleRequest(body as any);
121
+ return Response.json(response);
122
+ } finally {
123
+ manager.dispose();
124
+ }
125
+ }
126
+
127
+ const stream = new TransformStream();
128
+ const writer = stream.writable.getWriter();
129
+ const encoder = new TextEncoder();
130
+ let streamWritable = true;
131
+
132
+ const sendSSE = (event: string, data: unknown) => {
133
+ if (!streamWritable) return;
134
+ const message = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
135
+ writer.write(encoder.encode(message)).catch(() => {
136
+ streamWritable = false;
137
+ });
138
+ };
139
+
140
+ const manager = new SSEConnectionManager(
141
+ toManagerOptions(identity, resolvedClientMetadata),
142
+ (event: McpConnectionEvent | McpObservabilityEvent | McpRpcResponse) => {
143
+ if (isRpcResponseEvent(event)) {
144
+ sendSSE('rpc-response', event);
145
+ } else if (isConnectionEvent(event)) {
146
+ sendSSE('connection', event);
147
+ } else {
148
+ sendSSE('observability', event);
149
+ }
150
+ }
151
+ );
152
+
153
+ sendSSE('connected', { timestamp: Date.now() });
154
+
155
+ void (async () => {
156
+ try {
157
+ await manager.handleRequest(body as any);
158
+ } catch (error) {
159
+ const err = error instanceof Error ? error : new Error('Unknown error');
160
+ sendSSE('rpc-response', {
161
+ id: (body as any).id || 'unknown',
162
+ error: {
163
+ code: 'EXECUTION_ERROR',
164
+ message: err.message,
165
+ },
166
+ } satisfies McpRpcResponse);
167
+ } finally {
168
+ streamWritable = false;
169
+ manager.dispose();
170
+ writer.close().catch(() => { });
171
+ }
172
+ })();
173
+
174
+ return new Response(stream.readable, {
175
+ status: 200,
176
+ headers: {
177
+ 'Content-Type': 'text/event-stream',
178
+ 'Cache-Control': 'no-cache, no-transform',
179
+ 'Connection': 'keep-alive',
180
+ 'X-Accel-Buffering': 'no',
181
+ },
182
+ });
183
+ } catch (error) {
184
+ const err = error instanceof Error ? error : new Error('Unknown error');
185
+ console.error('[MCP Next Handler] Failed to handle RPC', {
186
+ identity,
187
+ message: err.message,
188
+ stack: err.stack,
189
+ rawBody: rawBody.slice(0, 500),
190
+ });
191
+ return Response.json(
192
+ {
193
+ error: {
194
+ code: 'EXECUTION_ERROR',
195
+ message: err.message,
196
+ },
197
+ },
198
+ { status: 500 }
199
+ );
200
+ }
201
+ }
202
+
203
+ return { GET, POST };
204
+ }