@mcp-ts/sdk 1.3.1 → 1.3.3

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 (63) hide show
  1. package/README.md +371 -290
  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-middleware.d.mts +3 -3
  5. package/dist/adapters/agui-middleware.d.ts +3 -3
  6. package/dist/adapters/ai-adapter.d.mts +3 -3
  7. package/dist/adapters/ai-adapter.d.ts +3 -3
  8. package/dist/adapters/langchain-adapter.d.mts +3 -3
  9. package/dist/adapters/langchain-adapter.d.ts +3 -3
  10. package/dist/adapters/mastra-adapter.d.mts +3 -3
  11. package/dist/adapters/mastra-adapter.d.ts +3 -3
  12. package/dist/client/index.d.mts +10 -66
  13. package/dist/client/index.d.ts +10 -66
  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 +15 -5
  19. package/dist/client/react.d.ts +15 -5
  20. package/dist/client/react.js +130 -182
  21. package/dist/client/react.js.map +1 -1
  22. package/dist/client/react.mjs +130 -182
  23. package/dist/client/react.mjs.map +1 -1
  24. package/dist/client/vue.d.mts +27 -7
  25. package/dist/client/vue.d.ts +27 -7
  26. package/dist/client/vue.js +131 -182
  27. package/dist/client/vue.js.map +1 -1
  28. package/dist/client/vue.mjs +131 -182
  29. package/dist/client/vue.mjs.map +1 -1
  30. package/dist/{events-BgeztGYZ.d.mts → events-CK3N--3g.d.mts} +2 -0
  31. package/dist/{events-BgeztGYZ.d.ts → events-CK3N--3g.d.ts} +2 -0
  32. package/dist/index.d.mts +3 -3
  33. package/dist/index.d.ts +3 -3
  34. package/dist/index.js +224 -258
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +224 -258
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/{multi-session-client-CxogNckF.d.mts → multi-session-client-DzjmT7FX.d.mts} +4 -10
  39. package/dist/{multi-session-client-cox_WXUj.d.ts → multi-session-client-FAFpUzZ4.d.ts} +4 -10
  40. package/dist/server/index.d.mts +18 -23
  41. package/dist/server/index.d.ts +18 -23
  42. package/dist/server/index.js +133 -85
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/index.mjs +133 -85
  45. package/dist/server/index.mjs.map +1 -1
  46. package/dist/shared/index.d.mts +3 -3
  47. package/dist/shared/index.d.ts +3 -3
  48. package/dist/shared/index.js.map +1 -1
  49. package/dist/shared/index.mjs.map +1 -1
  50. package/dist/{types-CLccx9wW.d.mts → types-CW6lghof.d.mts} +6 -0
  51. package/dist/{types-CLccx9wW.d.ts → types-CW6lghof.d.ts} +6 -0
  52. package/package.json +1 -1
  53. package/src/client/core/sse-client.ts +354 -493
  54. package/src/client/react/index.ts +16 -16
  55. package/src/client/react/use-mcp-apps.tsx +214 -214
  56. package/src/client/react/use-mcp.ts +84 -19
  57. package/src/client/vue/use-mcp.ts +119 -44
  58. package/src/server/handlers/nextjs-handler.ts +207 -217
  59. package/src/server/handlers/sse-handler.ts +14 -0
  60. package/src/server/mcp/oauth-client.ts +48 -46
  61. package/src/server/storage/types.ts +12 -5
  62. package/src/shared/events.ts +2 -0
  63. package/src/shared/types.ts +6 -0
package/dist/index.mjs CHANGED
@@ -1081,18 +1081,15 @@ var MCPClient = class _MCPClient {
1081
1081
  __publicField(this, "serverUrl");
1082
1082
  __publicField(this, "callbackUrl");
1083
1083
  __publicField(this, "onRedirect");
1084
- __publicField(this, "tokens");
1085
- __publicField(this, "tokenExpiresAt");
1086
- __publicField(this, "clientInformation");
1087
1084
  __publicField(this, "clientId");
1088
1085
  __publicField(this, "clientSecret");
1089
- __publicField(this, "onSaveTokens");
1090
1086
  __publicField(this, "headers");
1091
1087
  /** OAuth Client Metadata */
1092
1088
  __publicField(this, "clientName");
1093
1089
  __publicField(this, "clientUri");
1094
1090
  __publicField(this, "logoUri");
1095
1091
  __publicField(this, "policyUri");
1092
+ __publicField(this, "createdAt");
1096
1093
  /** Event emitters for connection lifecycle */
1097
1094
  __publicField(this, "_onConnectionEvent", new Emitter());
1098
1095
  __publicField(this, "onConnectionEvent", this._onConnectionEvent.event);
@@ -1107,12 +1104,8 @@ var MCPClient = class _MCPClient {
1107
1104
  this.serverId = options.serverId;
1108
1105
  this.sessionId = options.sessionId;
1109
1106
  this.transportType = options.transportType;
1110
- this.tokens = options.tokens;
1111
- this.tokenExpiresAt = options.tokenExpiresAt;
1112
- this.clientInformation = options.clientInformation;
1113
1107
  this.clientId = options.clientId;
1114
1108
  this.clientSecret = options.clientSecret;
1115
- this.onSaveTokens = options.onSaveTokens;
1116
1109
  this.headers = options.headers;
1117
1110
  this.clientName = options.clientName;
1118
1111
  this.clientUri = options.clientUri;
@@ -1132,6 +1125,8 @@ var MCPClient = class _MCPClient {
1132
1125
  sessionId: this.sessionId,
1133
1126
  serverId: this.serverId,
1134
1127
  serverName: this.serverName || this.serverId,
1128
+ serverUrl: this.serverUrl || "",
1129
+ createdAt: this.createdAt,
1135
1130
  state: newState,
1136
1131
  previousState,
1137
1132
  timestamp: Date.now()
@@ -1252,6 +1247,7 @@ var MCPClient = class _MCPClient {
1252
1247
  this.serverName = this.serverName || sessionData.serverName;
1253
1248
  this.serverId = this.serverId || sessionData.serverId || "unknown";
1254
1249
  this.headers = this.headers || sessionData.headers;
1250
+ this.createdAt = sessionData.createdAt;
1255
1251
  }
1256
1252
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1257
1253
  throw new Error("Missing required connection metadata");
@@ -1305,6 +1301,7 @@ var MCPClient = class _MCPClient {
1305
1301
  }
1306
1302
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1307
1303
  if (!existingSession && this.serverId && this.serverUrl && this.callbackUrl) {
1304
+ this.createdAt = Date.now();
1308
1305
  console.log(`[MCPClient] Creating initial session ${this.sessionId} for OAuth flow`);
1309
1306
  await storage.createSession({
1310
1307
  sessionId: this.sessionId,
@@ -1314,7 +1311,8 @@ var MCPClient = class _MCPClient {
1314
1311
  serverUrl: this.serverUrl,
1315
1312
  callbackUrl: this.callbackUrl,
1316
1313
  transportType: this.transportType || "streamable_http",
1317
- createdAt: Date.now()
1314
+ createdAt: this.createdAt,
1315
+ active: false
1318
1316
  }, Math.floor(STATE_EXPIRATION_MS / 1e3));
1319
1317
  }
1320
1318
  }
@@ -1322,9 +1320,10 @@ var MCPClient = class _MCPClient {
1322
1320
  * Saves current session state to storage
1323
1321
  * Creates new session if it doesn't exist, updates if it does
1324
1322
  * @param ttl - Time-to-live in seconds (defaults to 12hr for connected sessions)
1323
+ * @param active - Session status marker used to avoid unnecessary TTL rewrites
1325
1324
  * @private
1326
1325
  */
1327
- async saveSession(ttl = SESSION_TTL_SECONDS) {
1326
+ async saveSession(ttl = SESSION_TTL_SECONDS, active = true) {
1328
1327
  if (!this.sessionId || !this.serverId || !this.serverUrl || !this.callbackUrl) {
1329
1328
  return;
1330
1329
  }
@@ -1336,7 +1335,8 @@ var MCPClient = class _MCPClient {
1336
1335
  serverUrl: this.serverUrl,
1337
1336
  callbackUrl: this.callbackUrl,
1338
1337
  transportType: this.transportType || "streamable_http",
1339
- createdAt: Date.now()
1338
+ createdAt: this.createdAt || Date.now(),
1339
+ active
1340
1340
  };
1341
1341
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1342
1342
  if (existingSession) {
@@ -1410,15 +1410,17 @@ var MCPClient = class _MCPClient {
1410
1410
  this.emitStateChange("CONNECTED");
1411
1411
  this.emitProgress("Connected successfully");
1412
1412
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1413
- if (!existingSession || existingSession.transportType !== this.transportType) {
1414
- console.log(`[MCPClient] Saving session ${this.sessionId} (new or transport changed)`);
1415
- await this.saveSession(SESSION_TTL_SECONDS);
1413
+ const needsTransportUpdate = !existingSession || existingSession.transportType !== this.transportType;
1414
+ const needsTtlPromotion = !existingSession || existingSession.active !== true;
1415
+ if (needsTransportUpdate || needsTtlPromotion) {
1416
+ console.log(`[MCPClient] Saving session ${this.sessionId} with 12hr TTL (connect success)`);
1417
+ await this.saveSession(SESSION_TTL_SECONDS, true);
1416
1418
  }
1417
1419
  } catch (error) {
1418
1420
  if (error instanceof UnauthorizedError$1 || error instanceof Error && error.message.toLowerCase().includes("unauthorized")) {
1419
1421
  this.emitStateChange("AUTHENTICATING");
1420
1422
  console.log(`[MCPClient] Saving session ${this.sessionId} with 10min TTL (OAuth pending)`);
1421
- await this.saveSession(Math.floor(STATE_EXPIRATION_MS / 1e3));
1423
+ await this.saveSession(Math.floor(STATE_EXPIRATION_MS / 1e3), false);
1422
1424
  let authUrl = "";
1423
1425
  if (this.oauthProvider) {
1424
1426
  authUrl = this.oauthProvider.authUrl || "";
@@ -1496,7 +1498,7 @@ var MCPClient = class _MCPClient {
1496
1498
  await this.client.connect(this.transport);
1497
1499
  this.emitStateChange("CONNECTED");
1498
1500
  console.log(`[MCPClient] Updating session ${this.sessionId} to 12hr TTL (OAuth complete)`);
1499
- await this.saveSession(SESSION_TTL_SECONDS);
1501
+ await this.saveSession(SESSION_TTL_SECONDS, true);
1500
1502
  return;
1501
1503
  } catch (error) {
1502
1504
  lastError = error;
@@ -2160,7 +2162,9 @@ var SSEConnectionManager = class {
2160
2162
  serverId: s.serverId,
2161
2163
  serverName: s.serverName,
2162
2164
  serverUrl: s.serverUrl,
2163
- transport: s.transportType
2165
+ transport: s.transportType,
2166
+ createdAt: s.createdAt,
2167
+ active: s.active !== false
2164
2168
  }))
2165
2169
  };
2166
2170
  }
@@ -2175,6 +2179,13 @@ var SSEConnectionManager = class {
2175
2179
  (s) => s.serverId === serverId || s.serverUrl === serverUrl
2176
2180
  );
2177
2181
  if (duplicate) {
2182
+ if (duplicate.active === false) {
2183
+ await this.restoreSession({ sessionId: duplicate.sessionId });
2184
+ return {
2185
+ sessionId: duplicate.sessionId,
2186
+ success: true
2187
+ };
2188
+ }
2178
2189
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2179
2190
  }
2180
2191
  const sessionId = await storage.generateSessionId();
@@ -2183,6 +2194,7 @@ var SSEConnectionManager = class {
2183
2194
  sessionId,
2184
2195
  serverId,
2185
2196
  serverName,
2197
+ serverUrl,
2186
2198
  state: "CONNECTING",
2187
2199
  previousState: "DISCONNECTED",
2188
2200
  timestamp: Date.now()
@@ -2315,6 +2327,7 @@ var SSEConnectionManager = class {
2315
2327
  sessionId,
2316
2328
  serverId: session.serverId ?? "unknown",
2317
2329
  serverName: session.serverName ?? "Unknown",
2330
+ serverUrl: session.serverUrl,
2318
2331
  state: "VALIDATING",
2319
2332
  previousState: "DISCONNECTED",
2320
2333
  timestamp: Date.now()
@@ -2366,6 +2379,7 @@ var SSEConnectionManager = class {
2366
2379
  sessionId,
2367
2380
  serverId: session.serverId ?? "unknown",
2368
2381
  serverName: session.serverName ?? "Unknown",
2382
+ serverUrl: session.serverUrl,
2369
2383
  state: "AUTHENTICATING",
2370
2384
  previousState: "DISCONNECTED",
2371
2385
  timestamp: Date.now()
@@ -2497,7 +2511,9 @@ function writeSSEEvent(res, event, data) {
2497
2511
  }
2498
2512
 
2499
2513
  // src/server/handlers/nextjs-handler.ts
2500
- var managers = /* @__PURE__ */ new Map();
2514
+ function isRpcResponseEvent(event) {
2515
+ return "id" in event && ("result" in event || "error" in event);
2516
+ }
2501
2517
  function createNextMcpHandler(options = {}) {
2502
2518
  const {
2503
2519
  getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
@@ -2510,72 +2526,29 @@ function createNextMcpHandler(options = {}) {
2510
2526
  clientDefaults,
2511
2527
  getClientMetadata
2512
2528
  } = options;
2513
- async function GET(request) {
2514
- const identity = getIdentity(request);
2515
- const authToken = getAuthToken(request);
2516
- if (!identity) {
2517
- return new Response("Missing identity", { status: 400 });
2518
- }
2519
- const isAuthorized = await authenticate(identity, authToken);
2520
- if (!isAuthorized) {
2521
- return new Response("Unauthorized", { status: 401 });
2522
- }
2523
- const stream = new TransformStream();
2524
- const writer = stream.writable.getWriter();
2525
- const encoder = new TextEncoder();
2526
- const sendSSE = (event, data) => {
2527
- const message = `event: ${event}
2528
- data: ${JSON.stringify(data)}
2529
-
2530
- `;
2531
- writer.write(encoder.encode(message)).catch(() => {
2532
- });
2533
- };
2534
- const previousManager = managers.get(identity);
2535
- if (previousManager) {
2536
- previousManager.dispose();
2537
- }
2538
- const resolvedClientMetadata = getClientMetadata ? await getClientMetadata(request) : clientDefaults;
2539
- const manager = new SSEConnectionManager(
2529
+ const toManagerOptions = (identity, resolvedClientMetadata) => ({
2530
+ identity,
2531
+ heartbeatInterval,
2532
+ clientDefaults: resolvedClientMetadata
2533
+ });
2534
+ async function resolveClientMetadata(request) {
2535
+ return getClientMetadata ? await getClientMetadata(request) : clientDefaults;
2536
+ }
2537
+ async function GET() {
2538
+ return Response.json(
2540
2539
  {
2541
- identity,
2542
- heartbeatInterval,
2543
- clientDefaults: resolvedClientMetadata
2544
- // Pass resolved metadata
2545
- },
2546
- (event) => {
2547
- if ("id" in event) {
2548
- sendSSE("rpc-response", event);
2549
- } else if ("type" in event && "sessionId" in event) {
2550
- sendSSE("connection", event);
2551
- } else {
2552
- sendSSE("observability", event);
2540
+ error: {
2541
+ code: "METHOD_NOT_ALLOWED",
2542
+ message: "Use POST /api/mcp. For streaming use Accept: text/event-stream."
2553
2543
  }
2554
- }
2544
+ },
2545
+ { status: 405 }
2555
2546
  );
2556
- managers.set(identity, manager);
2557
- sendSSE("connected", { timestamp: Date.now() });
2558
- const abortController = new AbortController();
2559
- request.signal?.addEventListener("abort", () => {
2560
- manager.dispose();
2561
- managers.delete(identity);
2562
- writer.close().catch(() => {
2563
- });
2564
- abortController.abort();
2565
- });
2566
- return new Response(stream.readable, {
2567
- status: 200,
2568
- headers: {
2569
- "Content-Type": "text/event-stream",
2570
- "Cache-Control": "no-cache, no-transform",
2571
- "Connection": "keep-alive",
2572
- "X-Accel-Buffering": "no"
2573
- }
2574
- });
2575
2547
  }
2576
2548
  async function POST(request) {
2577
2549
  const identity = getIdentity(request);
2578
2550
  const authToken = getAuthToken(request);
2551
+ const acceptsEventStream = (request.headers.get("accept") || "").toLowerCase().includes("text/event-stream");
2579
2552
  if (!identity) {
2580
2553
  return Response.json({ error: { code: "MISSING_IDENTITY", message: "Missing identity" } }, { status: 400 });
2581
2554
  }
@@ -2583,28 +2556,103 @@ data: ${JSON.stringify(data)}
2583
2556
  if (!isAuthorized) {
2584
2557
  return Response.json({ error: { code: "UNAUTHORIZED", message: "Unauthorized" } }, { status: 401 });
2585
2558
  }
2559
+ let rawBody = "";
2586
2560
  try {
2587
- const body = await request.json();
2588
- const manager = managers.get(identity);
2589
- if (!manager) {
2561
+ rawBody = await request.text();
2562
+ const body = rawBody ? JSON.parse(rawBody) : null;
2563
+ if (!body || typeof body !== "object") {
2590
2564
  return Response.json(
2591
2565
  {
2592
2566
  error: {
2593
- code: "NO_CONNECTION",
2594
- message: "No SSE connection found. Please establish SSE connection first."
2567
+ code: "INVALID_REQUEST",
2568
+ message: "Invalid JSON-RPC request body"
2595
2569
  }
2596
2570
  },
2597
2571
  { status: 400 }
2598
2572
  );
2599
2573
  }
2600
- const response = await manager.handleRequest(body);
2601
- return Response.json(response);
2574
+ const resolvedClientMetadata = await resolveClientMetadata(request);
2575
+ if (!acceptsEventStream) {
2576
+ const manager2 = new SSEConnectionManager(
2577
+ toManagerOptions(identity, resolvedClientMetadata),
2578
+ () => {
2579
+ }
2580
+ );
2581
+ try {
2582
+ const response = await manager2.handleRequest(body);
2583
+ return Response.json(response);
2584
+ } finally {
2585
+ manager2.dispose();
2586
+ }
2587
+ }
2588
+ const stream = new TransformStream();
2589
+ const writer = stream.writable.getWriter();
2590
+ const encoder = new TextEncoder();
2591
+ let streamWritable = true;
2592
+ const sendSSE = (event, data) => {
2593
+ if (!streamWritable) return;
2594
+ const message = `event: ${event}
2595
+ data: ${JSON.stringify(data)}
2596
+
2597
+ `;
2598
+ writer.write(encoder.encode(message)).catch(() => {
2599
+ streamWritable = false;
2600
+ });
2601
+ };
2602
+ const manager = new SSEConnectionManager(
2603
+ toManagerOptions(identity, resolvedClientMetadata),
2604
+ (event) => {
2605
+ if (isRpcResponseEvent(event)) {
2606
+ sendSSE("rpc-response", event);
2607
+ } else if ("type" in event && "sessionId" in event) {
2608
+ sendSSE("connection", event);
2609
+ } else {
2610
+ sendSSE("observability", event);
2611
+ }
2612
+ }
2613
+ );
2614
+ sendSSE("connected", { timestamp: Date.now() });
2615
+ void (async () => {
2616
+ try {
2617
+ await manager.handleRequest(body);
2618
+ } catch (error) {
2619
+ const err = error instanceof Error ? error : new Error("Unknown error");
2620
+ sendSSE("rpc-response", {
2621
+ id: body.id || "unknown",
2622
+ error: {
2623
+ code: "EXECUTION_ERROR",
2624
+ message: err.message
2625
+ }
2626
+ });
2627
+ } finally {
2628
+ streamWritable = false;
2629
+ manager.dispose();
2630
+ writer.close().catch(() => {
2631
+ });
2632
+ }
2633
+ })();
2634
+ return new Response(stream.readable, {
2635
+ status: 200,
2636
+ headers: {
2637
+ "Content-Type": "text/event-stream",
2638
+ "Cache-Control": "no-cache, no-transform",
2639
+ "Connection": "keep-alive",
2640
+ "X-Accel-Buffering": "no"
2641
+ }
2642
+ });
2602
2643
  } catch (error) {
2644
+ const err = error instanceof Error ? error : new Error("Unknown error");
2645
+ console.error("[MCP Next Handler] Failed to handle RPC", {
2646
+ identity,
2647
+ message: err.message,
2648
+ stack: err.stack,
2649
+ rawBody: rawBody.slice(0, 500)
2650
+ });
2603
2651
  return Response.json(
2604
2652
  {
2605
2653
  error: {
2606
2654
  code: "EXECUTION_ERROR",
2607
- message: error instanceof Error ? error.message : "Unknown error"
2655
+ message: err.message
2608
2656
  }
2609
2657
  },
2610
2658
  { status: 500 }
@@ -2613,62 +2661,27 @@ data: ${JSON.stringify(data)}
2613
2661
  }
2614
2662
  return { GET, POST };
2615
2663
  }
2616
- var DEFAULT_REQUEST_TIMEOUT = 6e4;
2617
- var MAX_RECONNECT_ATTEMPTS = 5;
2618
- var BASE_RECONNECT_DELAY = 1e3;
2619
2664
  var SSEClient = class {
2620
2665
  constructor(options) {
2621
2666
  this.options = options;
2622
- __publicField(this, "eventSource", null);
2623
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
2624
2667
  __publicField(this, "resourceCache", /* @__PURE__ */ new Map());
2625
- __publicField(this, "reconnectAttempts", 0);
2626
- __publicField(this, "isManuallyDisconnected", false);
2627
- __publicField(this, "connectionPromise", null);
2628
- __publicField(this, "connectionResolver", null);
2668
+ __publicField(this, "connected", false);
2629
2669
  }
2630
- // ============================================
2631
- // Connection Management
2632
- // ============================================
2633
- /**
2634
- * Connect to the SSE endpoint
2635
- */
2636
2670
  connect() {
2637
- if (this.eventSource) {
2671
+ if (this.connected) {
2638
2672
  return;
2639
2673
  }
2640
- this.isManuallyDisconnected = false;
2641
- this.options.onStatusChange?.("connecting");
2642
- this.connectionPromise = new Promise((resolve) => {
2643
- this.connectionResolver = resolve;
2644
- });
2645
- const url = this.buildUrl();
2646
- this.eventSource = new EventSource(url);
2647
- this.setupEventListeners();
2674
+ this.connected = true;
2675
+ this.options.onStatusChange?.("connected");
2676
+ this.log("RPC mode: post_stream");
2648
2677
  }
2649
- /**
2650
- * Disconnect from the SSE endpoint
2651
- */
2652
2678
  disconnect() {
2653
- this.isManuallyDisconnected = true;
2654
- if (this.eventSource) {
2655
- this.eventSource.close();
2656
- this.eventSource = null;
2657
- }
2658
- this.connectionPromise = null;
2659
- this.connectionResolver = null;
2660
- this.rejectAllPendingRequests(new Error("Connection closed"));
2679
+ this.connected = false;
2661
2680
  this.options.onStatusChange?.("disconnected");
2662
2681
  }
2663
- /**
2664
- * Check if connected to the SSE endpoint
2665
- */
2666
2682
  isConnected() {
2667
- return this.eventSource?.readyState === EventSource.OPEN;
2683
+ return this.connected;
2668
2684
  }
2669
- // ============================================
2670
- // RPC Methods
2671
- // ============================================
2672
2685
  async getSessions() {
2673
2686
  return this.sendRequest("getSessions");
2674
2687
  }
@@ -2704,22 +2717,10 @@ var SSEClient = class {
2704
2717
  async readResource(sessionId, uri) {
2705
2718
  return this.sendRequest("readResource", { sessionId, uri });
2706
2719
  }
2707
- // ============================================
2708
- // Resource Preloading (for instant UI loading)
2709
- // ============================================
2710
- /**
2711
- * Preload UI resources for tools that have UI metadata.
2712
- * Call this when tools are discovered to enable instant MCP App UI loading.
2713
- */
2714
2720
  preloadToolUiResources(sessionId, tools) {
2715
2721
  for (const tool of tools) {
2716
2722
  const uri = this.extractUiResourceUri(tool);
2717
- if (!uri) continue;
2718
- if (this.resourceCache.has(uri)) {
2719
- this.log(`Resource already cached: ${uri}`);
2720
- continue;
2721
- }
2722
- this.log(`Preloading UI resource for tool "${tool.name}": ${uri}`);
2723
+ if (!uri || this.resourceCache.has(uri)) continue;
2723
2724
  const promise = this.sendRequest("readResource", { sessionId, uri }).catch((err) => {
2724
2725
  this.log(`Failed to preload resource ${uri}: ${err.message}`, "warn");
2725
2726
  this.resourceCache.delete(uri);
@@ -2728,43 +2729,24 @@ var SSEClient = class {
2728
2729
  this.resourceCache.set(uri, promise);
2729
2730
  }
2730
2731
  }
2731
- /**
2732
- * Get a preloaded resource from cache, or fetch if not cached.
2733
- */
2734
2732
  getOrFetchResource(sessionId, uri) {
2735
2733
  const cached = this.resourceCache.get(uri);
2736
- if (cached) {
2737
- this.log(`Cache hit for resource: ${uri}`);
2738
- return cached;
2739
- }
2740
- this.log(`Cache miss, fetching resource: ${uri}`);
2734
+ if (cached) return cached;
2741
2735
  const promise = this.sendRequest("readResource", { sessionId, uri });
2742
2736
  this.resourceCache.set(uri, promise);
2743
2737
  return promise;
2744
2738
  }
2745
- /**
2746
- * Check if a resource is already cached
2747
- */
2748
2739
  hasPreloadedResource(uri) {
2749
2740
  return this.resourceCache.has(uri);
2750
2741
  }
2751
- /**
2752
- * Clear the resource cache
2753
- */
2754
2742
  clearResourceCache() {
2755
2743
  this.resourceCache.clear();
2756
2744
  }
2757
- // ============================================
2758
- // Private: Request Handling
2759
- // ============================================
2760
- /**
2761
- * Send an RPC request and return the response directly from HTTP.
2762
- * This bypasses SSE latency by returning results in the HTTP response body.
2763
- */
2764
2745
  async sendRequest(method, params) {
2765
- if (this.connectionPromise) {
2766
- await this.connectionPromise;
2746
+ if (!this.connected) {
2747
+ this.connect();
2767
2748
  }
2749
+ this.log(`RPC request via post_stream: ${method}`);
2768
2750
  const request = {
2769
2751
  id: `rpc_${nanoid(10)}`,
2770
2752
  method,
@@ -2778,103 +2760,93 @@ var SSEClient = class {
2778
2760
  if (!response.ok) {
2779
2761
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2780
2762
  }
2781
- const data = await response.json();
2782
- return this.parseRpcResponse(data, request.id);
2763
+ const contentType = (response.headers.get("content-type") || "").toLowerCase();
2764
+ if (!contentType.includes("text/event-stream")) {
2765
+ const data2 = await response.json();
2766
+ return this.parseRpcResponse(data2);
2767
+ }
2768
+ const data = await this.readRpcResponseFromStream(response);
2769
+ return this.parseRpcResponse(data);
2770
+ }
2771
+ async readRpcResponseFromStream(response) {
2772
+ if (!response.body) {
2773
+ throw new Error("Streaming response body is missing");
2774
+ }
2775
+ const reader = response.body.getReader();
2776
+ const decoder = new TextDecoder();
2777
+ let buffer = "";
2778
+ let rpcResponse = null;
2779
+ const dispatchBlock = (block) => {
2780
+ const lines = block.split("\n");
2781
+ let eventName = "message";
2782
+ const dataLines = [];
2783
+ for (const rawLine of lines) {
2784
+ const line = rawLine.replace(/\r$/, "");
2785
+ if (!line || line.startsWith(":")) continue;
2786
+ if (line.startsWith("event:")) {
2787
+ eventName = line.slice("event:".length).trim();
2788
+ continue;
2789
+ }
2790
+ if (line.startsWith("data:")) {
2791
+ dataLines.push(line.slice("data:".length).trimStart());
2792
+ }
2793
+ }
2794
+ if (!dataLines.length) return;
2795
+ const payloadText = dataLines.join("\n");
2796
+ let payload = payloadText;
2797
+ try {
2798
+ payload = JSON.parse(payloadText);
2799
+ } catch {
2800
+ }
2801
+ switch (eventName) {
2802
+ case "connected":
2803
+ this.options.onStatusChange?.("connected");
2804
+ break;
2805
+ case "connection":
2806
+ this.options.onConnectionEvent?.(payload);
2807
+ break;
2808
+ case "observability":
2809
+ this.options.onObservabilityEvent?.(payload);
2810
+ break;
2811
+ case "rpc-response":
2812
+ rpcResponse = payload;
2813
+ break;
2814
+ }
2815
+ };
2816
+ while (true) {
2817
+ const { value, done } = await reader.read();
2818
+ if (done) break;
2819
+ buffer += decoder.decode(value, { stream: true });
2820
+ let separatorMatch = buffer.match(/\r?\n\r?\n/);
2821
+ while (separatorMatch && separatorMatch.index !== void 0) {
2822
+ const separatorIndex = separatorMatch.index;
2823
+ const separatorLength = separatorMatch[0].length;
2824
+ const block = buffer.slice(0, separatorIndex);
2825
+ buffer = buffer.slice(separatorIndex + separatorLength);
2826
+ dispatchBlock(block);
2827
+ separatorMatch = buffer.match(/\r?\n\r?\n/);
2828
+ }
2829
+ }
2830
+ if (buffer.trim()) {
2831
+ dispatchBlock(buffer);
2832
+ }
2833
+ if (!rpcResponse) {
2834
+ throw new Error("Missing rpc-response event in streamed RPC result");
2835
+ }
2836
+ return rpcResponse;
2783
2837
  }
2784
- /**
2785
- * Parse RPC response and handle different response formats
2786
- */
2787
- parseRpcResponse(data, requestId) {
2838
+ parseRpcResponse(data) {
2788
2839
  if ("result" in data) {
2789
2840
  return data.result;
2790
2841
  }
2791
2842
  if ("error" in data && data.error) {
2792
2843
  throw new Error(data.error.message || "Unknown RPC error");
2793
2844
  }
2794
- if ("acknowledged" in data) {
2795
- return this.waitForSseResponse(requestId);
2845
+ if (data && typeof data === "object" && "id" in data) {
2846
+ return void 0;
2796
2847
  }
2797
2848
  throw new Error("Invalid RPC response format");
2798
2849
  }
2799
- /**
2800
- * Wait for RPC response via SSE (legacy fallback)
2801
- */
2802
- waitForSseResponse(requestId) {
2803
- const timeoutMs = this.options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
2804
- return new Promise((resolve, reject) => {
2805
- const timeoutId = setTimeout(() => {
2806
- this.pendingRequests.delete(requestId);
2807
- reject(new Error(`Request timeout after ${timeoutMs}ms`));
2808
- }, timeoutMs);
2809
- this.pendingRequests.set(requestId, {
2810
- resolve,
2811
- reject,
2812
- timeoutId
2813
- });
2814
- });
2815
- }
2816
- /**
2817
- * Handle RPC response received via SSE (legacy)
2818
- */
2819
- handleRpcResponse(response) {
2820
- const pending = this.pendingRequests.get(response.id);
2821
- if (!pending) return;
2822
- clearTimeout(pending.timeoutId);
2823
- this.pendingRequests.delete(response.id);
2824
- if (response.error) {
2825
- pending.reject(new Error(response.error.message));
2826
- } else {
2827
- pending.resolve(response.result);
2828
- }
2829
- }
2830
- // ============================================
2831
- // Private: Event Handling
2832
- // ============================================
2833
- setupEventListeners() {
2834
- if (!this.eventSource) return;
2835
- this.eventSource.addEventListener("open", () => {
2836
- this.log("Connected");
2837
- this.reconnectAttempts = 0;
2838
- this.options.onStatusChange?.("connected");
2839
- });
2840
- this.eventSource.addEventListener("connected", () => {
2841
- this.log("Server ready");
2842
- this.connectionResolver?.();
2843
- this.connectionResolver = null;
2844
- });
2845
- this.eventSource.addEventListener("connection", (e) => {
2846
- const event = JSON.parse(e.data);
2847
- this.options.onConnectionEvent?.(event);
2848
- });
2849
- this.eventSource.addEventListener("observability", (e) => {
2850
- const event = JSON.parse(e.data);
2851
- this.options.onObservabilityEvent?.(event);
2852
- });
2853
- this.eventSource.addEventListener("rpc-response", (e) => {
2854
- const response = JSON.parse(e.data);
2855
- this.handleRpcResponse(response);
2856
- });
2857
- this.eventSource.addEventListener("error", () => {
2858
- this.log("Connection error", "error");
2859
- this.options.onStatusChange?.("error");
2860
- this.attemptReconnect();
2861
- });
2862
- }
2863
- attemptReconnect() {
2864
- if (this.isManuallyDisconnected || this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
2865
- return;
2866
- }
2867
- this.reconnectAttempts++;
2868
- const delay = BASE_RECONNECT_DELAY * this.reconnectAttempts;
2869
- this.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
2870
- setTimeout(() => {
2871
- this.disconnect();
2872
- this.connect();
2873
- }, delay);
2874
- }
2875
- // ============================================
2876
- // Private: Utilities
2877
- // ============================================
2878
2850
  buildUrl() {
2879
2851
  const url = new URL(this.options.url, globalThis.location?.origin);
2880
2852
  url.searchParams.set("identity", this.options.identity);
@@ -2885,20 +2857,14 @@ var SSEClient = class {
2885
2857
  }
2886
2858
  buildHeaders() {
2887
2859
  const headers = {
2888
- "Content-Type": "application/json"
2860
+ "Content-Type": "application/json",
2861
+ "Accept": "text/event-stream"
2889
2862
  };
2890
2863
  if (this.options.authToken) {
2891
2864
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
2892
2865
  }
2893
2866
  return headers;
2894
2867
  }
2895
- rejectAllPendingRequests(error) {
2896
- for (const [, pending] of this.pendingRequests) {
2897
- clearTimeout(pending.timeoutId);
2898
- pending.reject(error);
2899
- }
2900
- this.pendingRequests.clear();
2901
- }
2902
2868
  extractUiResourceUri(tool) {
2903
2869
  const meta = tool._meta?.ui;
2904
2870
  if (!meta || typeof meta !== "object") return void 0;