@mcp-ts/sdk 1.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 (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +297 -0
  3. package/dist/adapters/agui-adapter.d.mts +119 -0
  4. package/dist/adapters/agui-adapter.d.ts +119 -0
  5. package/dist/adapters/agui-adapter.js +109 -0
  6. package/dist/adapters/agui-adapter.js.map +1 -0
  7. package/dist/adapters/agui-adapter.mjs +107 -0
  8. package/dist/adapters/agui-adapter.mjs.map +1 -0
  9. package/dist/adapters/agui-middleware.d.mts +171 -0
  10. package/dist/adapters/agui-middleware.d.ts +171 -0
  11. package/dist/adapters/agui-middleware.js +429 -0
  12. package/dist/adapters/agui-middleware.js.map +1 -0
  13. package/dist/adapters/agui-middleware.mjs +417 -0
  14. package/dist/adapters/agui-middleware.mjs.map +1 -0
  15. package/dist/adapters/ai-adapter.d.mts +38 -0
  16. package/dist/adapters/ai-adapter.d.ts +38 -0
  17. package/dist/adapters/ai-adapter.js +82 -0
  18. package/dist/adapters/ai-adapter.js.map +1 -0
  19. package/dist/adapters/ai-adapter.mjs +80 -0
  20. package/dist/adapters/ai-adapter.mjs.map +1 -0
  21. package/dist/adapters/langchain-adapter.d.mts +46 -0
  22. package/dist/adapters/langchain-adapter.d.ts +46 -0
  23. package/dist/adapters/langchain-adapter.js +102 -0
  24. package/dist/adapters/langchain-adapter.js.map +1 -0
  25. package/dist/adapters/langchain-adapter.mjs +100 -0
  26. package/dist/adapters/langchain-adapter.mjs.map +1 -0
  27. package/dist/adapters/mastra-adapter.d.mts +49 -0
  28. package/dist/adapters/mastra-adapter.d.ts +49 -0
  29. package/dist/adapters/mastra-adapter.js +95 -0
  30. package/dist/adapters/mastra-adapter.js.map +1 -0
  31. package/dist/adapters/mastra-adapter.mjs +93 -0
  32. package/dist/adapters/mastra-adapter.mjs.map +1 -0
  33. package/dist/client/index.d.mts +119 -0
  34. package/dist/client/index.d.ts +119 -0
  35. package/dist/client/index.js +225 -0
  36. package/dist/client/index.js.map +1 -0
  37. package/dist/client/index.mjs +223 -0
  38. package/dist/client/index.mjs.map +1 -0
  39. package/dist/client/react.d.mts +151 -0
  40. package/dist/client/react.d.ts +151 -0
  41. package/dist/client/react.js +492 -0
  42. package/dist/client/react.js.map +1 -0
  43. package/dist/client/react.mjs +489 -0
  44. package/dist/client/react.mjs.map +1 -0
  45. package/dist/client/vue.d.mts +157 -0
  46. package/dist/client/vue.d.ts +157 -0
  47. package/dist/client/vue.js +474 -0
  48. package/dist/client/vue.js.map +1 -0
  49. package/dist/client/vue.mjs +471 -0
  50. package/dist/client/vue.mjs.map +1 -0
  51. package/dist/events-BP6WyRNh.d.mts +110 -0
  52. package/dist/events-BP6WyRNh.d.ts +110 -0
  53. package/dist/index.d.mts +10 -0
  54. package/dist/index.d.ts +10 -0
  55. package/dist/index.js +2784 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/index.mjs +2723 -0
  58. package/dist/index.mjs.map +1 -0
  59. package/dist/multi-session-client-BOFgPypS.d.ts +389 -0
  60. package/dist/multi-session-client-DMF3ED2O.d.mts +389 -0
  61. package/dist/server/index.d.mts +269 -0
  62. package/dist/server/index.d.ts +269 -0
  63. package/dist/server/index.js +2444 -0
  64. package/dist/server/index.js.map +1 -0
  65. package/dist/server/index.mjs +2414 -0
  66. package/dist/server/index.mjs.map +1 -0
  67. package/dist/shared/index.d.mts +24 -0
  68. package/dist/shared/index.d.ts +24 -0
  69. package/dist/shared/index.js +223 -0
  70. package/dist/shared/index.js.map +1 -0
  71. package/dist/shared/index.mjs +190 -0
  72. package/dist/shared/index.mjs.map +1 -0
  73. package/dist/types-SbDlA2VX.d.mts +153 -0
  74. package/dist/types-SbDlA2VX.d.ts +153 -0
  75. package/dist/utils-0qmYrqoa.d.mts +92 -0
  76. package/dist/utils-0qmYrqoa.d.ts +92 -0
  77. package/package.json +165 -0
  78. package/src/adapters/agui-adapter.ts +210 -0
  79. package/src/adapters/agui-middleware.ts +512 -0
  80. package/src/adapters/ai-adapter.ts +115 -0
  81. package/src/adapters/langchain-adapter.ts +127 -0
  82. package/src/adapters/mastra-adapter.ts +126 -0
  83. package/src/client/core/sse-client.ts +340 -0
  84. package/src/client/index.ts +26 -0
  85. package/src/client/react/index.ts +10 -0
  86. package/src/client/react/useMcp.ts +558 -0
  87. package/src/client/vue/index.ts +10 -0
  88. package/src/client/vue/useMcp.ts +542 -0
  89. package/src/index.ts +11 -0
  90. package/src/server/handlers/nextjs-handler.ts +216 -0
  91. package/src/server/handlers/sse-handler.ts +699 -0
  92. package/src/server/index.ts +57 -0
  93. package/src/server/mcp/multi-session-client.ts +132 -0
  94. package/src/server/mcp/oauth-client.ts +1168 -0
  95. package/src/server/mcp/storage-oauth-provider.ts +239 -0
  96. package/src/server/storage/file-backend.ts +169 -0
  97. package/src/server/storage/index.ts +115 -0
  98. package/src/server/storage/memory-backend.ts +132 -0
  99. package/src/server/storage/redis-backend.ts +210 -0
  100. package/src/server/storage/redis.ts +160 -0
  101. package/src/server/storage/types.ts +109 -0
  102. package/src/shared/constants.ts +29 -0
  103. package/src/shared/errors.ts +133 -0
  104. package/src/shared/events.ts +166 -0
  105. package/src/shared/index.ts +70 -0
  106. package/src/shared/types.ts +274 -0
  107. package/src/shared/utils.ts +16 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Next.js App Router Handler for MCP SSE
3
+ * Provides a clean, zero-boilerplate API for Next.js applications
4
+ */
5
+
6
+ import { SSEConnectionManager, type ClientMetadata } from './sse-handler.js';
7
+ import type { McpConnectionEvent, McpObservabilityEvent } from '../../shared/events.js';
8
+ import type { McpRpcResponse } from '../../shared/types.js';
9
+
10
+ export interface NextMcpHandlerOptions {
11
+ /**
12
+ * Extract identity from request (default: from 'identity' query param)
13
+ */
14
+ getIdentity?: (request: Request) => string | null;
15
+
16
+ /**
17
+ * Extract auth token from request (default: from 'token' query param or Authorization header)
18
+ */
19
+ getAuthToken?: (request: Request) => string | null;
20
+
21
+ /**
22
+ * Authenticate user and verify access (optional)
23
+ * Return true if user is authenticated, false otherwise
24
+ */
25
+ authenticate?: (identity: string, token: string | null) => Promise<boolean> | boolean;
26
+
27
+ /**
28
+ * Heartbeat interval in milliseconds (default: 30000)
29
+ */
30
+ heartbeatInterval?: number;
31
+
32
+ /**
33
+ * Static OAuth client metadata defaults (for all connections)
34
+ * Use this for single-tenant applications with fixed branding
35
+ */
36
+ clientDefaults?: ClientMetadata;
37
+
38
+ /**
39
+ * Dynamic OAuth client metadata getter (per-request, useful for multi-tenant)
40
+ * Use this when you need different branding based on request (tenant, domain, etc.)
41
+ * Takes precedence over clientDefaults
42
+ */
43
+ getClientMetadata?: (request: Request) => ClientMetadata | Promise<ClientMetadata>;
44
+ }
45
+
46
+ // Global manager store - shared across requests for the same user
47
+ const managers = new Map<string, SSEConnectionManager>();
48
+
49
+ /**
50
+ * Creates Next.js App Router handlers (GET and POST) for MCP SSE endpoint
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * // app/api/mcp/route.ts
55
+ * import { createNextMcpHandler } from '@mcp-ts/core/server';
56
+ *
57
+ * export const { GET, POST } = createNextMcpHandler();
58
+ * ```
59
+ */
60
+ export function createNextMcpHandler(options: NextMcpHandlerOptions = {}) {
61
+ const {
62
+ getIdentity = (request: Request) => new URL(request.url).searchParams.get('identity'),
63
+ getAuthToken = (request: Request) => {
64
+ const url = new URL(request.url);
65
+ return url.searchParams.get('token') || request.headers.get('authorization');
66
+ },
67
+ authenticate = () => true,
68
+ heartbeatInterval = 30000,
69
+ clientDefaults,
70
+ getClientMetadata,
71
+ } = options;
72
+
73
+ /**
74
+ * GET handler - Establishes SSE connection
75
+ */
76
+ async function GET(request: Request): Promise<Response> {
77
+ const identity = getIdentity(request);
78
+ const authToken = getAuthToken(request);
79
+
80
+ if (!identity) {
81
+ return new Response('Missing identity', { status: 400 });
82
+ }
83
+
84
+ // Validate auth
85
+ const isAuthorized = await authenticate(identity, authToken);
86
+ if (!isAuthorized) {
87
+ return new Response('Unauthorized', { status: 401 });
88
+ }
89
+
90
+ // Create TransformStream for SSE
91
+ const stream = new TransformStream();
92
+ const writer = stream.writable.getWriter();
93
+ const encoder = new TextEncoder();
94
+
95
+ // Helper to send SSE events
96
+ const sendSSE = (event: string, data: any) => {
97
+ const message = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
98
+ writer.write(encoder.encode(message)).catch(() => {
99
+ // Client disconnected, ignore write errors
100
+ });
101
+ };
102
+
103
+ // Send initial connection event
104
+ sendSSE('connected', { timestamp: Date.now() });
105
+
106
+ // Clean up previous manager if exists (prevents memory leaks on reconnect)
107
+ const previousManager = managers.get(identity);
108
+ if (previousManager) {
109
+ previousManager.dispose();
110
+ }
111
+
112
+ // Resolve client metadata (dynamic takes precedence over static)
113
+ const resolvedClientMetadata = getClientMetadata
114
+ ? await getClientMetadata(request)
115
+ : clientDefaults;
116
+
117
+ // Create new manager
118
+ const manager = new SSEConnectionManager(
119
+ {
120
+ identity,
121
+ heartbeatInterval,
122
+ clientDefaults: resolvedClientMetadata, // Pass resolved metadata
123
+ },
124
+ (event: McpConnectionEvent | McpObservabilityEvent | McpRpcResponse) => {
125
+ // Determine event type and send via SSE
126
+ if ('id' in event) {
127
+ // RPC response
128
+ sendSSE('rpc-response', event);
129
+ } else if ('type' in event && 'sessionId' in event) {
130
+ // Connection event
131
+ sendSSE('connection', event);
132
+ } else {
133
+ // Observability event
134
+ sendSSE('observability', event);
135
+ }
136
+ }
137
+ );
138
+
139
+ managers.set(identity, manager);
140
+
141
+ // Handle client disconnect
142
+ const abortController = new AbortController();
143
+ request.signal?.addEventListener('abort', () => {
144
+ manager.dispose();
145
+ managers.delete(identity);
146
+ writer.close().catch(() => { });
147
+ abortController.abort();
148
+ });
149
+
150
+ // Return SSE response
151
+ return new Response(stream.readable, {
152
+ status: 200,
153
+ headers: {
154
+ 'Content-Type': 'text/event-stream',
155
+ 'Cache-Control': 'no-cache, no-transform',
156
+ 'Connection': 'keep-alive',
157
+ 'X-Accel-Buffering': 'no',
158
+ },
159
+ });
160
+ }
161
+
162
+ /**
163
+ * POST handler - Handles RPC requests
164
+ */
165
+ async function POST(request: Request): Promise<Response> {
166
+ const identity = getIdentity(request);
167
+ const authToken = getAuthToken(request);
168
+
169
+ if (!identity) {
170
+ return Response.json({ error: { code: 'MISSING_IDENTITY', message: 'Missing identity' } }, { status: 400 });
171
+ }
172
+
173
+ // Validate auth
174
+ const isAuthorized = await authenticate(identity, authToken);
175
+ if (!isAuthorized) {
176
+ return Response.json({ error: { code: 'UNAUTHORIZED', message: 'Unauthorized' } }, { status: 401 });
177
+ }
178
+
179
+ try {
180
+ const body = await request.json();
181
+
182
+ // Get existing manager (created by GET endpoint)
183
+ const manager = managers.get(identity);
184
+
185
+ if (!manager) {
186
+ return Response.json(
187
+ {
188
+ error: {
189
+ code: 'NO_CONNECTION',
190
+ message: 'No SSE connection found. Please establish SSE connection first.',
191
+ },
192
+ },
193
+ { status: 400 }
194
+ );
195
+ }
196
+
197
+ // Handle the request - response will be sent via SSE
198
+ await manager.handleRequest(body);
199
+
200
+ // Return acknowledgment (actual response goes through SSE)
201
+ return Response.json({ acknowledged: true });
202
+ } catch (error) {
203
+ return Response.json(
204
+ {
205
+ error: {
206
+ code: 'EXECUTION_ERROR',
207
+ message: error instanceof Error ? error.message : 'Unknown error',
208
+ },
209
+ },
210
+ { status: 500 }
211
+ );
212
+ }
213
+ }
214
+
215
+ return { GET, POST };
216
+ }