@mcp-ts/sdk 1.3.2 → 1.3.4

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 (58) hide show
  1. package/README.md +400 -406
  2. package/dist/adapters/agui-adapter.d.mts +1 -1
  3. package/dist/adapters/agui-adapter.d.ts +1 -1
  4. package/dist/adapters/agui-middleware.d.mts +1 -1
  5. package/dist/adapters/agui-middleware.d.ts +1 -1
  6. package/dist/adapters/ai-adapter.d.mts +1 -1
  7. package/dist/adapters/ai-adapter.d.ts +1 -1
  8. package/dist/adapters/langchain-adapter.d.mts +1 -1
  9. package/dist/adapters/langchain-adapter.d.ts +1 -1
  10. package/dist/adapters/mastra-adapter.d.mts +1 -1
  11. package/dist/adapters/mastra-adapter.d.ts +1 -1
  12. package/dist/client/index.d.mts +8 -64
  13. package/dist/client/index.d.ts +8 -64
  14. package/dist/client/index.js +91 -173
  15. package/dist/client/index.js.map +1 -1
  16. package/dist/client/index.mjs +91 -173
  17. package/dist/client/index.mjs.map +1 -1
  18. package/dist/client/react.d.mts +12 -2
  19. package/dist/client/react.d.ts +12 -2
  20. package/dist/client/react.js +119 -182
  21. package/dist/client/react.js.map +1 -1
  22. package/dist/client/react.mjs +119 -182
  23. package/dist/client/react.mjs.map +1 -1
  24. package/dist/client/vue.d.mts +24 -4
  25. package/dist/client/vue.d.ts +24 -4
  26. package/dist/client/vue.js +121 -182
  27. package/dist/client/vue.js.map +1 -1
  28. package/dist/client/vue.mjs +121 -182
  29. package/dist/client/vue.mjs.map +1 -1
  30. package/dist/index.d.mts +2 -2
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +215 -250
  33. package/dist/index.js.map +1 -1
  34. package/dist/index.mjs +215 -250
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/{multi-session-client-B1DBx5yR.d.mts → multi-session-client-DzjmT7FX.d.mts} +1 -0
  37. package/dist/{multi-session-client-DyFzyJUx.d.ts → multi-session-client-FAFpUzZ4.d.ts} +1 -0
  38. package/dist/server/index.d.mts +16 -21
  39. package/dist/server/index.d.ts +16 -21
  40. package/dist/server/index.js +124 -77
  41. package/dist/server/index.js.map +1 -1
  42. package/dist/server/index.mjs +124 -77
  43. package/dist/server/index.mjs.map +1 -1
  44. package/dist/shared/index.d.mts +2 -2
  45. package/dist/shared/index.d.ts +2 -2
  46. package/dist/shared/index.js.map +1 -1
  47. package/dist/shared/index.mjs.map +1 -1
  48. package/dist/{types-PjM1W07s.d.mts → types-CW6lghof.d.mts} +5 -0
  49. package/dist/{types-PjM1W07s.d.ts → types-CW6lghof.d.ts} +5 -0
  50. package/package.json +1 -1
  51. package/src/client/core/sse-client.ts +354 -493
  52. package/src/client/react/use-mcp.ts +75 -23
  53. package/src/client/vue/use-mcp.ts +111 -48
  54. package/src/server/handlers/nextjs-handler.ts +207 -217
  55. package/src/server/handlers/sse-handler.ts +10 -0
  56. package/src/server/mcp/oauth-client.ts +41 -32
  57. package/src/server/storage/types.ts +12 -5
  58. package/src/shared/types.ts +5 -0
package/dist/index.js CHANGED
@@ -1333,7 +1333,8 @@ var MCPClient = class _MCPClient {
1333
1333
  serverUrl: this.serverUrl,
1334
1334
  callbackUrl: this.callbackUrl,
1335
1335
  transportType: this.transportType || "streamable_http",
1336
- createdAt: this.createdAt
1336
+ createdAt: this.createdAt,
1337
+ active: false
1337
1338
  }, Math.floor(STATE_EXPIRATION_MS / 1e3));
1338
1339
  }
1339
1340
  }
@@ -1341,9 +1342,10 @@ var MCPClient = class _MCPClient {
1341
1342
  * Saves current session state to storage
1342
1343
  * Creates new session if it doesn't exist, updates if it does
1343
1344
  * @param ttl - Time-to-live in seconds (defaults to 12hr for connected sessions)
1345
+ * @param active - Session status marker used to avoid unnecessary TTL rewrites
1344
1346
  * @private
1345
1347
  */
1346
- async saveSession(ttl = SESSION_TTL_SECONDS) {
1348
+ async saveSession(ttl = SESSION_TTL_SECONDS, active = true) {
1347
1349
  if (!this.sessionId || !this.serverId || !this.serverUrl || !this.callbackUrl) {
1348
1350
  return;
1349
1351
  }
@@ -1355,7 +1357,8 @@ var MCPClient = class _MCPClient {
1355
1357
  serverUrl: this.serverUrl,
1356
1358
  callbackUrl: this.callbackUrl,
1357
1359
  transportType: this.transportType || "streamable_http",
1358
- createdAt: this.createdAt || Date.now()
1360
+ createdAt: this.createdAt || Date.now(),
1361
+ active
1359
1362
  };
1360
1363
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1361
1364
  if (existingSession) {
@@ -1429,15 +1432,17 @@ var MCPClient = class _MCPClient {
1429
1432
  this.emitStateChange("CONNECTED");
1430
1433
  this.emitProgress("Connected successfully");
1431
1434
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1432
- if (!existingSession || existingSession.transportType !== this.transportType) {
1433
- console.log(`[MCPClient] Saving session ${this.sessionId} (new or transport changed)`);
1434
- await this.saveSession(SESSION_TTL_SECONDS);
1435
+ const needsTransportUpdate = !existingSession || existingSession.transportType !== this.transportType;
1436
+ const needsTtlPromotion = !existingSession || existingSession.active !== true;
1437
+ if (needsTransportUpdate || needsTtlPromotion) {
1438
+ console.log(`[MCPClient] Saving session ${this.sessionId} with 12hr TTL (connect success)`);
1439
+ await this.saveSession(SESSION_TTL_SECONDS, true);
1435
1440
  }
1436
1441
  } catch (error) {
1437
1442
  if (error instanceof auth_js.UnauthorizedError || error instanceof Error && error.message.toLowerCase().includes("unauthorized")) {
1438
1443
  this.emitStateChange("AUTHENTICATING");
1439
1444
  console.log(`[MCPClient] Saving session ${this.sessionId} with 10min TTL (OAuth pending)`);
1440
- await this.saveSession(Math.floor(STATE_EXPIRATION_MS / 1e3));
1445
+ await this.saveSession(Math.floor(STATE_EXPIRATION_MS / 1e3), false);
1441
1446
  let authUrl = "";
1442
1447
  if (this.oauthProvider) {
1443
1448
  authUrl = this.oauthProvider.authUrl || "";
@@ -1515,7 +1520,7 @@ var MCPClient = class _MCPClient {
1515
1520
  await this.client.connect(this.transport);
1516
1521
  this.emitStateChange("CONNECTED");
1517
1522
  console.log(`[MCPClient] Updating session ${this.sessionId} to 12hr TTL (OAuth complete)`);
1518
- await this.saveSession(SESSION_TTL_SECONDS);
1523
+ await this.saveSession(SESSION_TTL_SECONDS, true);
1519
1524
  return;
1520
1525
  } catch (error) {
1521
1526
  lastError = error;
@@ -2180,7 +2185,8 @@ var SSEConnectionManager = class {
2180
2185
  serverName: s.serverName,
2181
2186
  serverUrl: s.serverUrl,
2182
2187
  transport: s.transportType,
2183
- createdAt: s.createdAt
2188
+ createdAt: s.createdAt,
2189
+ active: s.active !== false
2184
2190
  }))
2185
2191
  };
2186
2192
  }
@@ -2195,6 +2201,13 @@ var SSEConnectionManager = class {
2195
2201
  (s) => s.serverId === serverId || s.serverUrl === serverUrl
2196
2202
  );
2197
2203
  if (duplicate) {
2204
+ if (duplicate.active === false) {
2205
+ await this.restoreSession({ sessionId: duplicate.sessionId });
2206
+ return {
2207
+ sessionId: duplicate.sessionId,
2208
+ success: true
2209
+ };
2210
+ }
2198
2211
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2199
2212
  }
2200
2213
  const sessionId = await storage.generateSessionId();
@@ -2520,7 +2533,9 @@ function writeSSEEvent(res, event, data) {
2520
2533
  }
2521
2534
 
2522
2535
  // src/server/handlers/nextjs-handler.ts
2523
- var managers = /* @__PURE__ */ new Map();
2536
+ function isRpcResponseEvent(event) {
2537
+ return "id" in event && ("result" in event || "error" in event);
2538
+ }
2524
2539
  function createNextMcpHandler(options = {}) {
2525
2540
  const {
2526
2541
  getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
@@ -2533,72 +2548,29 @@ function createNextMcpHandler(options = {}) {
2533
2548
  clientDefaults,
2534
2549
  getClientMetadata
2535
2550
  } = options;
2536
- async function GET(request) {
2537
- const identity = getIdentity(request);
2538
- const authToken = getAuthToken(request);
2539
- if (!identity) {
2540
- return new Response("Missing identity", { status: 400 });
2541
- }
2542
- const isAuthorized = await authenticate(identity, authToken);
2543
- if (!isAuthorized) {
2544
- return new Response("Unauthorized", { status: 401 });
2545
- }
2546
- const stream = new TransformStream();
2547
- const writer = stream.writable.getWriter();
2548
- const encoder = new TextEncoder();
2549
- const sendSSE = (event, data) => {
2550
- const message = `event: ${event}
2551
- data: ${JSON.stringify(data)}
2552
-
2553
- `;
2554
- writer.write(encoder.encode(message)).catch(() => {
2555
- });
2556
- };
2557
- const previousManager = managers.get(identity);
2558
- if (previousManager) {
2559
- previousManager.dispose();
2560
- }
2561
- const resolvedClientMetadata = getClientMetadata ? await getClientMetadata(request) : clientDefaults;
2562
- const manager = new SSEConnectionManager(
2551
+ const toManagerOptions = (identity, resolvedClientMetadata) => ({
2552
+ identity,
2553
+ heartbeatInterval,
2554
+ clientDefaults: resolvedClientMetadata
2555
+ });
2556
+ async function resolveClientMetadata(request) {
2557
+ return getClientMetadata ? await getClientMetadata(request) : clientDefaults;
2558
+ }
2559
+ async function GET() {
2560
+ return Response.json(
2563
2561
  {
2564
- identity,
2565
- heartbeatInterval,
2566
- clientDefaults: resolvedClientMetadata
2567
- // Pass resolved metadata
2568
- },
2569
- (event) => {
2570
- if ("id" in event) {
2571
- sendSSE("rpc-response", event);
2572
- } else if ("type" in event && "sessionId" in event) {
2573
- sendSSE("connection", event);
2574
- } else {
2575
- sendSSE("observability", event);
2562
+ error: {
2563
+ code: "METHOD_NOT_ALLOWED",
2564
+ message: "Use POST /api/mcp. For streaming use Accept: text/event-stream."
2576
2565
  }
2577
- }
2566
+ },
2567
+ { status: 405 }
2578
2568
  );
2579
- managers.set(identity, manager);
2580
- sendSSE("connected", { timestamp: Date.now() });
2581
- const abortController = new AbortController();
2582
- request.signal?.addEventListener("abort", () => {
2583
- manager.dispose();
2584
- managers.delete(identity);
2585
- writer.close().catch(() => {
2586
- });
2587
- abortController.abort();
2588
- });
2589
- return new Response(stream.readable, {
2590
- status: 200,
2591
- headers: {
2592
- "Content-Type": "text/event-stream",
2593
- "Cache-Control": "no-cache, no-transform",
2594
- "Connection": "keep-alive",
2595
- "X-Accel-Buffering": "no"
2596
- }
2597
- });
2598
2569
  }
2599
2570
  async function POST(request) {
2600
2571
  const identity = getIdentity(request);
2601
2572
  const authToken = getAuthToken(request);
2573
+ const acceptsEventStream = (request.headers.get("accept") || "").toLowerCase().includes("text/event-stream");
2602
2574
  if (!identity) {
2603
2575
  return Response.json({ error: { code: "MISSING_IDENTITY", message: "Missing identity" } }, { status: 400 });
2604
2576
  }
@@ -2606,28 +2578,103 @@ data: ${JSON.stringify(data)}
2606
2578
  if (!isAuthorized) {
2607
2579
  return Response.json({ error: { code: "UNAUTHORIZED", message: "Unauthorized" } }, { status: 401 });
2608
2580
  }
2581
+ let rawBody = "";
2609
2582
  try {
2610
- const body = await request.json();
2611
- const manager = managers.get(identity);
2612
- if (!manager) {
2583
+ rawBody = await request.text();
2584
+ const body = rawBody ? JSON.parse(rawBody) : null;
2585
+ if (!body || typeof body !== "object") {
2613
2586
  return Response.json(
2614
2587
  {
2615
2588
  error: {
2616
- code: "NO_CONNECTION",
2617
- message: "No SSE connection found. Please establish SSE connection first."
2589
+ code: "INVALID_REQUEST",
2590
+ message: "Invalid JSON-RPC request body"
2618
2591
  }
2619
2592
  },
2620
2593
  { status: 400 }
2621
2594
  );
2622
2595
  }
2623
- const response = await manager.handleRequest(body);
2624
- return Response.json(response);
2596
+ const resolvedClientMetadata = await resolveClientMetadata(request);
2597
+ if (!acceptsEventStream) {
2598
+ const manager2 = new SSEConnectionManager(
2599
+ toManagerOptions(identity, resolvedClientMetadata),
2600
+ () => {
2601
+ }
2602
+ );
2603
+ try {
2604
+ const response = await manager2.handleRequest(body);
2605
+ return Response.json(response);
2606
+ } finally {
2607
+ manager2.dispose();
2608
+ }
2609
+ }
2610
+ const stream = new TransformStream();
2611
+ const writer = stream.writable.getWriter();
2612
+ const encoder = new TextEncoder();
2613
+ let streamWritable = true;
2614
+ const sendSSE = (event, data) => {
2615
+ if (!streamWritable) return;
2616
+ const message = `event: ${event}
2617
+ data: ${JSON.stringify(data)}
2618
+
2619
+ `;
2620
+ writer.write(encoder.encode(message)).catch(() => {
2621
+ streamWritable = false;
2622
+ });
2623
+ };
2624
+ const manager = new SSEConnectionManager(
2625
+ toManagerOptions(identity, resolvedClientMetadata),
2626
+ (event) => {
2627
+ if (isRpcResponseEvent(event)) {
2628
+ sendSSE("rpc-response", event);
2629
+ } else if ("type" in event && "sessionId" in event) {
2630
+ sendSSE("connection", event);
2631
+ } else {
2632
+ sendSSE("observability", event);
2633
+ }
2634
+ }
2635
+ );
2636
+ sendSSE("connected", { timestamp: Date.now() });
2637
+ void (async () => {
2638
+ try {
2639
+ await manager.handleRequest(body);
2640
+ } catch (error) {
2641
+ const err = error instanceof Error ? error : new Error("Unknown error");
2642
+ sendSSE("rpc-response", {
2643
+ id: body.id || "unknown",
2644
+ error: {
2645
+ code: "EXECUTION_ERROR",
2646
+ message: err.message
2647
+ }
2648
+ });
2649
+ } finally {
2650
+ streamWritable = false;
2651
+ manager.dispose();
2652
+ writer.close().catch(() => {
2653
+ });
2654
+ }
2655
+ })();
2656
+ return new Response(stream.readable, {
2657
+ status: 200,
2658
+ headers: {
2659
+ "Content-Type": "text/event-stream",
2660
+ "Cache-Control": "no-cache, no-transform",
2661
+ "Connection": "keep-alive",
2662
+ "X-Accel-Buffering": "no"
2663
+ }
2664
+ });
2625
2665
  } catch (error) {
2666
+ const err = error instanceof Error ? error : new Error("Unknown error");
2667
+ console.error("[MCP Next Handler] Failed to handle RPC", {
2668
+ identity,
2669
+ message: err.message,
2670
+ stack: err.stack,
2671
+ rawBody: rawBody.slice(0, 500)
2672
+ });
2626
2673
  return Response.json(
2627
2674
  {
2628
2675
  error: {
2629
2676
  code: "EXECUTION_ERROR",
2630
- message: error instanceof Error ? error.message : "Unknown error"
2677
+ message: err.message
2631
2678
  }
2632
2679
  },
2633
2680
  { status: 500 }
@@ -2636,62 +2683,27 @@ data: ${JSON.stringify(data)}
2636
2683
  }
2637
2684
  return { GET, POST };
2638
2685
  }
2639
- var DEFAULT_REQUEST_TIMEOUT = 6e4;
2640
- var MAX_RECONNECT_ATTEMPTS = 5;
2641
- var BASE_RECONNECT_DELAY = 1e3;
2642
2686
  var SSEClient = class {
2643
2687
  constructor(options) {
2644
2688
  this.options = options;
2645
- __publicField(this, "eventSource", null);
2646
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
2647
2689
  __publicField(this, "resourceCache", /* @__PURE__ */ new Map());
2648
- __publicField(this, "reconnectAttempts", 0);
2649
- __publicField(this, "isManuallyDisconnected", false);
2650
- __publicField(this, "connectionPromise", null);
2651
- __publicField(this, "connectionResolver", null);
2690
+ __publicField(this, "connected", false);
2652
2691
  }
2653
- // ============================================
2654
- // Connection Management
2655
- // ============================================
2656
- /**
2657
- * Connect to the SSE endpoint
2658
- */
2659
2692
  connect() {
2660
- if (this.eventSource) {
2693
+ if (this.connected) {
2661
2694
  return;
2662
2695
  }
2663
- this.isManuallyDisconnected = false;
2664
- this.options.onStatusChange?.("connecting");
2665
- this.connectionPromise = new Promise((resolve) => {
2666
- this.connectionResolver = resolve;
2667
- });
2668
- const url = this.buildUrl();
2669
- this.eventSource = new EventSource(url);
2670
- this.setupEventListeners();
2696
+ this.connected = true;
2697
+ this.options.onStatusChange?.("connected");
2698
+ this.log("RPC mode: post_stream");
2671
2699
  }
2672
- /**
2673
- * Disconnect from the SSE endpoint
2674
- */
2675
2700
  disconnect() {
2676
- this.isManuallyDisconnected = true;
2677
- if (this.eventSource) {
2678
- this.eventSource.close();
2679
- this.eventSource = null;
2680
- }
2681
- this.connectionPromise = null;
2682
- this.connectionResolver = null;
2683
- this.rejectAllPendingRequests(new Error("Connection closed"));
2701
+ this.connected = false;
2684
2702
  this.options.onStatusChange?.("disconnected");
2685
2703
  }
2686
- /**
2687
- * Check if connected to the SSE endpoint
2688
- */
2689
2704
  isConnected() {
2690
- return this.eventSource?.readyState === EventSource.OPEN;
2705
+ return this.connected;
2691
2706
  }
2692
- // ============================================
2693
- // RPC Methods
2694
- // ============================================
2695
2707
  async getSessions() {
2696
2708
  return this.sendRequest("getSessions");
2697
2709
  }
@@ -2727,22 +2739,10 @@ var SSEClient = class {
2727
2739
  async readResource(sessionId, uri) {
2728
2740
  return this.sendRequest("readResource", { sessionId, uri });
2729
2741
  }
2730
- // ============================================
2731
- // Resource Preloading (for instant UI loading)
2732
- // ============================================
2733
- /**
2734
- * Preload UI resources for tools that have UI metadata.
2735
- * Call this when tools are discovered to enable instant MCP App UI loading.
2736
- */
2737
2742
  preloadToolUiResources(sessionId, tools) {
2738
2743
  for (const tool of tools) {
2739
2744
  const uri = this.extractUiResourceUri(tool);
2740
- if (!uri) continue;
2741
- if (this.resourceCache.has(uri)) {
2742
- this.log(`Resource already cached: ${uri}`);
2743
- continue;
2744
- }
2745
- this.log(`Preloading UI resource for tool "${tool.name}": ${uri}`);
2745
+ if (!uri || this.resourceCache.has(uri)) continue;
2746
2746
  const promise = this.sendRequest("readResource", { sessionId, uri }).catch((err) => {
2747
2747
  this.log(`Failed to preload resource ${uri}: ${err.message}`, "warn");
2748
2748
  this.resourceCache.delete(uri);
@@ -2751,43 +2751,24 @@ var SSEClient = class {
2751
2751
  this.resourceCache.set(uri, promise);
2752
2752
  }
2753
2753
  }
2754
- /**
2755
- * Get a preloaded resource from cache, or fetch if not cached.
2756
- */
2757
2754
  getOrFetchResource(sessionId, uri) {
2758
2755
  const cached = this.resourceCache.get(uri);
2759
- if (cached) {
2760
- this.log(`Cache hit for resource: ${uri}`);
2761
- return cached;
2762
- }
2763
- this.log(`Cache miss, fetching resource: ${uri}`);
2756
+ if (cached) return cached;
2764
2757
  const promise = this.sendRequest("readResource", { sessionId, uri });
2765
2758
  this.resourceCache.set(uri, promise);
2766
2759
  return promise;
2767
2760
  }
2768
- /**
2769
- * Check if a resource is already cached
2770
- */
2771
2761
  hasPreloadedResource(uri) {
2772
2762
  return this.resourceCache.has(uri);
2773
2763
  }
2774
- /**
2775
- * Clear the resource cache
2776
- */
2777
2764
  clearResourceCache() {
2778
2765
  this.resourceCache.clear();
2779
2766
  }
2780
- // ============================================
2781
- // Private: Request Handling
2782
- // ============================================
2783
- /**
2784
- * Send an RPC request and return the response directly from HTTP.
2785
- * This bypasses SSE latency by returning results in the HTTP response body.
2786
- */
2787
2767
  async sendRequest(method, params) {
2788
- if (this.connectionPromise) {
2789
- await this.connectionPromise;
2768
+ if (!this.connected) {
2769
+ this.connect();
2790
2770
  }
2771
+ this.log(`RPC request via post_stream: ${method}`);
2791
2772
  const request = {
2792
2773
  id: `rpc_${nanoid.nanoid(10)}`,
2793
2774
  method,
@@ -2801,103 +2782,93 @@ var SSEClient = class {
2801
2782
  if (!response.ok) {
2802
2783
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2803
2784
  }
2804
- const data = await response.json();
2805
- return this.parseRpcResponse(data, request.id);
2785
+ const contentType = (response.headers.get("content-type") || "").toLowerCase();
2786
+ if (!contentType.includes("text/event-stream")) {
2787
+ const data2 = await response.json();
2788
+ return this.parseRpcResponse(data2);
2789
+ }
2790
+ const data = await this.readRpcResponseFromStream(response);
2791
+ return this.parseRpcResponse(data);
2792
+ }
2793
+ async readRpcResponseFromStream(response) {
2794
+ if (!response.body) {
2795
+ throw new Error("Streaming response body is missing");
2796
+ }
2797
+ const reader = response.body.getReader();
2798
+ const decoder = new TextDecoder();
2799
+ let buffer = "";
2800
+ let rpcResponse = null;
2801
+ const dispatchBlock = (block) => {
2802
+ const lines = block.split("\n");
2803
+ let eventName = "message";
2804
+ const dataLines = [];
2805
+ for (const rawLine of lines) {
2806
+ const line = rawLine.replace(/\r$/, "");
2807
+ if (!line || line.startsWith(":")) continue;
2808
+ if (line.startsWith("event:")) {
2809
+ eventName = line.slice("event:".length).trim();
2810
+ continue;
2811
+ }
2812
+ if (line.startsWith("data:")) {
2813
+ dataLines.push(line.slice("data:".length).trimStart());
2814
+ }
2815
+ }
2816
+ if (!dataLines.length) return;
2817
+ const payloadText = dataLines.join("\n");
2818
+ let payload = payloadText;
2819
+ try {
2820
+ payload = JSON.parse(payloadText);
2821
+ } catch {
2822
+ }
2823
+ switch (eventName) {
2824
+ case "connected":
2825
+ this.options.onStatusChange?.("connected");
2826
+ break;
2827
+ case "connection":
2828
+ this.options.onConnectionEvent?.(payload);
2829
+ break;
2830
+ case "observability":
2831
+ this.options.onObservabilityEvent?.(payload);
2832
+ break;
2833
+ case "rpc-response":
2834
+ rpcResponse = payload;
2835
+ break;
2836
+ }
2837
+ };
2838
+ while (true) {
2839
+ const { value, done } = await reader.read();
2840
+ if (done) break;
2841
+ buffer += decoder.decode(value, { stream: true });
2842
+ let separatorMatch = buffer.match(/\r?\n\r?\n/);
2843
+ while (separatorMatch && separatorMatch.index !== void 0) {
2844
+ const separatorIndex = separatorMatch.index;
2845
+ const separatorLength = separatorMatch[0].length;
2846
+ const block = buffer.slice(0, separatorIndex);
2847
+ buffer = buffer.slice(separatorIndex + separatorLength);
2848
+ dispatchBlock(block);
2849
+ separatorMatch = buffer.match(/\r?\n\r?\n/);
2850
+ }
2851
+ }
2852
+ if (buffer.trim()) {
2853
+ dispatchBlock(buffer);
2854
+ }
2855
+ if (!rpcResponse) {
2856
+ throw new Error("Missing rpc-response event in streamed RPC result");
2857
+ }
2858
+ return rpcResponse;
2806
2859
  }
2807
- /**
2808
- * Parse RPC response and handle different response formats
2809
- */
2810
- parseRpcResponse(data, requestId) {
2860
+ parseRpcResponse(data) {
2811
2861
  if ("result" in data) {
2812
2862
  return data.result;
2813
2863
  }
2814
2864
  if ("error" in data && data.error) {
2815
2865
  throw new Error(data.error.message || "Unknown RPC error");
2816
2866
  }
2817
- if ("acknowledged" in data) {
2818
- return this.waitForSseResponse(requestId);
2867
+ if (data && typeof data === "object" && "id" in data) {
2868
+ return void 0;
2819
2869
  }
2820
2870
  throw new Error("Invalid RPC response format");
2821
2871
  }
2822
- /**
2823
- * Wait for RPC response via SSE (legacy fallback)
2824
- */
2825
- waitForSseResponse(requestId) {
2826
- const timeoutMs = this.options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
2827
- return new Promise((resolve, reject) => {
2828
- const timeoutId = setTimeout(() => {
2829
- this.pendingRequests.delete(requestId);
2830
- reject(new Error(`Request timeout after ${timeoutMs}ms`));
2831
- }, timeoutMs);
2832
- this.pendingRequests.set(requestId, {
2833
- resolve,
2834
- reject,
2835
- timeoutId
2836
- });
2837
- });
2838
- }
2839
- /**
2840
- * Handle RPC response received via SSE (legacy)
2841
- */
2842
- handleRpcResponse(response) {
2843
- const pending = this.pendingRequests.get(response.id);
2844
- if (!pending) return;
2845
- clearTimeout(pending.timeoutId);
2846
- this.pendingRequests.delete(response.id);
2847
- if (response.error) {
2848
- pending.reject(new Error(response.error.message));
2849
- } else {
2850
- pending.resolve(response.result);
2851
- }
2852
- }
2853
- // ============================================
2854
- // Private: Event Handling
2855
- // ============================================
2856
- setupEventListeners() {
2857
- if (!this.eventSource) return;
2858
- this.eventSource.addEventListener("open", () => {
2859
- this.log("Connected");
2860
- this.reconnectAttempts = 0;
2861
- this.options.onStatusChange?.("connected");
2862
- });
2863
- this.eventSource.addEventListener("connected", () => {
2864
- this.log("Server ready");
2865
- this.connectionResolver?.();
2866
- this.connectionResolver = null;
2867
- });
2868
- this.eventSource.addEventListener("connection", (e) => {
2869
- const event = JSON.parse(e.data);
2870
- this.options.onConnectionEvent?.(event);
2871
- });
2872
- this.eventSource.addEventListener("observability", (e) => {
2873
- const event = JSON.parse(e.data);
2874
- this.options.onObservabilityEvent?.(event);
2875
- });
2876
- this.eventSource.addEventListener("rpc-response", (e) => {
2877
- const response = JSON.parse(e.data);
2878
- this.handleRpcResponse(response);
2879
- });
2880
- this.eventSource.addEventListener("error", () => {
2881
- this.log("Connection error", "error");
2882
- this.options.onStatusChange?.("error");
2883
- this.attemptReconnect();
2884
- });
2885
- }
2886
- attemptReconnect() {
2887
- if (this.isManuallyDisconnected || this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
2888
- return;
2889
- }
2890
- this.reconnectAttempts++;
2891
- const delay = BASE_RECONNECT_DELAY * this.reconnectAttempts;
2892
- this.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
2893
- setTimeout(() => {
2894
- this.disconnect();
2895
- this.connect();
2896
- }, delay);
2897
- }
2898
- // ============================================
2899
- // Private: Utilities
2900
- // ============================================
2901
2872
  buildUrl() {
2902
2873
  const url = new URL(this.options.url, globalThis.location?.origin);
2903
2874
  url.searchParams.set("identity", this.options.identity);
@@ -2908,20 +2879,14 @@ var SSEClient = class {
2908
2879
  }
2909
2880
  buildHeaders() {
2910
2881
  const headers = {
2911
- "Content-Type": "application/json"
2882
+ "Content-Type": "application/json",
2883
+ "Accept": "text/event-stream"
2912
2884
  };
2913
2885
  if (this.options.authToken) {
2914
2886
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
2915
2887
  }
2916
2888
  return headers;
2917
2889
  }
2918
- rejectAllPendingRequests(error) {
2919
- for (const [, pending] of this.pendingRequests) {
2920
- clearTimeout(pending.timeoutId);
2921
- pending.reject(error);
2922
- }
2923
- this.pendingRequests.clear();
2924
- }
2925
2890
  extractUiResourceUri(tool) {
2926
2891
  const meta = tool._meta?.ui;
2927
2892
  if (!meta || typeof meta !== "object") return void 0;