@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.js CHANGED
@@ -1103,18 +1103,15 @@ var MCPClient = class _MCPClient {
1103
1103
  __publicField(this, "serverUrl");
1104
1104
  __publicField(this, "callbackUrl");
1105
1105
  __publicField(this, "onRedirect");
1106
- __publicField(this, "tokens");
1107
- __publicField(this, "tokenExpiresAt");
1108
- __publicField(this, "clientInformation");
1109
1106
  __publicField(this, "clientId");
1110
1107
  __publicField(this, "clientSecret");
1111
- __publicField(this, "onSaveTokens");
1112
1108
  __publicField(this, "headers");
1113
1109
  /** OAuth Client Metadata */
1114
1110
  __publicField(this, "clientName");
1115
1111
  __publicField(this, "clientUri");
1116
1112
  __publicField(this, "logoUri");
1117
1113
  __publicField(this, "policyUri");
1114
+ __publicField(this, "createdAt");
1118
1115
  /** Event emitters for connection lifecycle */
1119
1116
  __publicField(this, "_onConnectionEvent", new Emitter());
1120
1117
  __publicField(this, "onConnectionEvent", this._onConnectionEvent.event);
@@ -1129,12 +1126,8 @@ var MCPClient = class _MCPClient {
1129
1126
  this.serverId = options.serverId;
1130
1127
  this.sessionId = options.sessionId;
1131
1128
  this.transportType = options.transportType;
1132
- this.tokens = options.tokens;
1133
- this.tokenExpiresAt = options.tokenExpiresAt;
1134
- this.clientInformation = options.clientInformation;
1135
1129
  this.clientId = options.clientId;
1136
1130
  this.clientSecret = options.clientSecret;
1137
- this.onSaveTokens = options.onSaveTokens;
1138
1131
  this.headers = options.headers;
1139
1132
  this.clientName = options.clientName;
1140
1133
  this.clientUri = options.clientUri;
@@ -1154,6 +1147,8 @@ var MCPClient = class _MCPClient {
1154
1147
  sessionId: this.sessionId,
1155
1148
  serverId: this.serverId,
1156
1149
  serverName: this.serverName || this.serverId,
1150
+ serverUrl: this.serverUrl || "",
1151
+ createdAt: this.createdAt,
1157
1152
  state: newState,
1158
1153
  previousState,
1159
1154
  timestamp: Date.now()
@@ -1274,6 +1269,7 @@ var MCPClient = class _MCPClient {
1274
1269
  this.serverName = this.serverName || sessionData.serverName;
1275
1270
  this.serverId = this.serverId || sessionData.serverId || "unknown";
1276
1271
  this.headers = this.headers || sessionData.headers;
1272
+ this.createdAt = sessionData.createdAt;
1277
1273
  }
1278
1274
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1279
1275
  throw new Error("Missing required connection metadata");
@@ -1327,6 +1323,7 @@ var MCPClient = class _MCPClient {
1327
1323
  }
1328
1324
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1329
1325
  if (!existingSession && this.serverId && this.serverUrl && this.callbackUrl) {
1326
+ this.createdAt = Date.now();
1330
1327
  console.log(`[MCPClient] Creating initial session ${this.sessionId} for OAuth flow`);
1331
1328
  await storage.createSession({
1332
1329
  sessionId: this.sessionId,
@@ -1336,7 +1333,8 @@ var MCPClient = class _MCPClient {
1336
1333
  serverUrl: this.serverUrl,
1337
1334
  callbackUrl: this.callbackUrl,
1338
1335
  transportType: this.transportType || "streamable_http",
1339
- createdAt: Date.now()
1336
+ createdAt: this.createdAt,
1337
+ active: false
1340
1338
  }, Math.floor(STATE_EXPIRATION_MS / 1e3));
1341
1339
  }
1342
1340
  }
@@ -1344,9 +1342,10 @@ var MCPClient = class _MCPClient {
1344
1342
  * Saves current session state to storage
1345
1343
  * Creates new session if it doesn't exist, updates if it does
1346
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
1347
1346
  * @private
1348
1347
  */
1349
- async saveSession(ttl = SESSION_TTL_SECONDS) {
1348
+ async saveSession(ttl = SESSION_TTL_SECONDS, active = true) {
1350
1349
  if (!this.sessionId || !this.serverId || !this.serverUrl || !this.callbackUrl) {
1351
1350
  return;
1352
1351
  }
@@ -1358,7 +1357,8 @@ var MCPClient = class _MCPClient {
1358
1357
  serverUrl: this.serverUrl,
1359
1358
  callbackUrl: this.callbackUrl,
1360
1359
  transportType: this.transportType || "streamable_http",
1361
- createdAt: Date.now()
1360
+ createdAt: this.createdAt || Date.now(),
1361
+ active
1362
1362
  };
1363
1363
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1364
1364
  if (existingSession) {
@@ -1432,15 +1432,17 @@ var MCPClient = class _MCPClient {
1432
1432
  this.emitStateChange("CONNECTED");
1433
1433
  this.emitProgress("Connected successfully");
1434
1434
  const existingSession = await storage.getSession(this.identity, this.sessionId);
1435
- if (!existingSession || existingSession.transportType !== this.transportType) {
1436
- console.log(`[MCPClient] Saving session ${this.sessionId} (new or transport changed)`);
1437
- 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);
1438
1440
  }
1439
1441
  } catch (error) {
1440
1442
  if (error instanceof auth_js.UnauthorizedError || error instanceof Error && error.message.toLowerCase().includes("unauthorized")) {
1441
1443
  this.emitStateChange("AUTHENTICATING");
1442
1444
  console.log(`[MCPClient] Saving session ${this.sessionId} with 10min TTL (OAuth pending)`);
1443
- await this.saveSession(Math.floor(STATE_EXPIRATION_MS / 1e3));
1445
+ await this.saveSession(Math.floor(STATE_EXPIRATION_MS / 1e3), false);
1444
1446
  let authUrl = "";
1445
1447
  if (this.oauthProvider) {
1446
1448
  authUrl = this.oauthProvider.authUrl || "";
@@ -1518,7 +1520,7 @@ var MCPClient = class _MCPClient {
1518
1520
  await this.client.connect(this.transport);
1519
1521
  this.emitStateChange("CONNECTED");
1520
1522
  console.log(`[MCPClient] Updating session ${this.sessionId} to 12hr TTL (OAuth complete)`);
1521
- await this.saveSession(SESSION_TTL_SECONDS);
1523
+ await this.saveSession(SESSION_TTL_SECONDS, true);
1522
1524
  return;
1523
1525
  } catch (error) {
1524
1526
  lastError = error;
@@ -2182,7 +2184,9 @@ var SSEConnectionManager = class {
2182
2184
  serverId: s.serverId,
2183
2185
  serverName: s.serverName,
2184
2186
  serverUrl: s.serverUrl,
2185
- transport: s.transportType
2187
+ transport: s.transportType,
2188
+ createdAt: s.createdAt,
2189
+ active: s.active !== false
2186
2190
  }))
2187
2191
  };
2188
2192
  }
@@ -2197,6 +2201,13 @@ var SSEConnectionManager = class {
2197
2201
  (s) => s.serverId === serverId || s.serverUrl === serverUrl
2198
2202
  );
2199
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
+ }
2200
2211
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2201
2212
  }
2202
2213
  const sessionId = await storage.generateSessionId();
@@ -2205,6 +2216,7 @@ var SSEConnectionManager = class {
2205
2216
  sessionId,
2206
2217
  serverId,
2207
2218
  serverName,
2219
+ serverUrl,
2208
2220
  state: "CONNECTING",
2209
2221
  previousState: "DISCONNECTED",
2210
2222
  timestamp: Date.now()
@@ -2337,6 +2349,7 @@ var SSEConnectionManager = class {
2337
2349
  sessionId,
2338
2350
  serverId: session.serverId ?? "unknown",
2339
2351
  serverName: session.serverName ?? "Unknown",
2352
+ serverUrl: session.serverUrl,
2340
2353
  state: "VALIDATING",
2341
2354
  previousState: "DISCONNECTED",
2342
2355
  timestamp: Date.now()
@@ -2388,6 +2401,7 @@ var SSEConnectionManager = class {
2388
2401
  sessionId,
2389
2402
  serverId: session.serverId ?? "unknown",
2390
2403
  serverName: session.serverName ?? "Unknown",
2404
+ serverUrl: session.serverUrl,
2391
2405
  state: "AUTHENTICATING",
2392
2406
  previousState: "DISCONNECTED",
2393
2407
  timestamp: Date.now()
@@ -2519,7 +2533,9 @@ function writeSSEEvent(res, event, data) {
2519
2533
  }
2520
2534
 
2521
2535
  // src/server/handlers/nextjs-handler.ts
2522
- var managers = /* @__PURE__ */ new Map();
2536
+ function isRpcResponseEvent(event) {
2537
+ return "id" in event && ("result" in event || "error" in event);
2538
+ }
2523
2539
  function createNextMcpHandler(options = {}) {
2524
2540
  const {
2525
2541
  getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
@@ -2532,72 +2548,29 @@ function createNextMcpHandler(options = {}) {
2532
2548
  clientDefaults,
2533
2549
  getClientMetadata
2534
2550
  } = options;
2535
- async function GET(request) {
2536
- const identity = getIdentity(request);
2537
- const authToken = getAuthToken(request);
2538
- if (!identity) {
2539
- return new Response("Missing identity", { status: 400 });
2540
- }
2541
- const isAuthorized = await authenticate(identity, authToken);
2542
- if (!isAuthorized) {
2543
- return new Response("Unauthorized", { status: 401 });
2544
- }
2545
- const stream = new TransformStream();
2546
- const writer = stream.writable.getWriter();
2547
- const encoder = new TextEncoder();
2548
- const sendSSE = (event, data) => {
2549
- const message = `event: ${event}
2550
- data: ${JSON.stringify(data)}
2551
-
2552
- `;
2553
- writer.write(encoder.encode(message)).catch(() => {
2554
- });
2555
- };
2556
- const previousManager = managers.get(identity);
2557
- if (previousManager) {
2558
- previousManager.dispose();
2559
- }
2560
- const resolvedClientMetadata = getClientMetadata ? await getClientMetadata(request) : clientDefaults;
2561
- 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(
2562
2561
  {
2563
- identity,
2564
- heartbeatInterval,
2565
- clientDefaults: resolvedClientMetadata
2566
- // Pass resolved metadata
2567
- },
2568
- (event) => {
2569
- if ("id" in event) {
2570
- sendSSE("rpc-response", event);
2571
- } else if ("type" in event && "sessionId" in event) {
2572
- sendSSE("connection", event);
2573
- } else {
2574
- sendSSE("observability", event);
2562
+ error: {
2563
+ code: "METHOD_NOT_ALLOWED",
2564
+ message: "Use POST /api/mcp. For streaming use Accept: text/event-stream."
2575
2565
  }
2576
- }
2566
+ },
2567
+ { status: 405 }
2577
2568
  );
2578
- managers.set(identity, manager);
2579
- sendSSE("connected", { timestamp: Date.now() });
2580
- const abortController = new AbortController();
2581
- request.signal?.addEventListener("abort", () => {
2582
- manager.dispose();
2583
- managers.delete(identity);
2584
- writer.close().catch(() => {
2585
- });
2586
- abortController.abort();
2587
- });
2588
- return new Response(stream.readable, {
2589
- status: 200,
2590
- headers: {
2591
- "Content-Type": "text/event-stream",
2592
- "Cache-Control": "no-cache, no-transform",
2593
- "Connection": "keep-alive",
2594
- "X-Accel-Buffering": "no"
2595
- }
2596
- });
2597
2569
  }
2598
2570
  async function POST(request) {
2599
2571
  const identity = getIdentity(request);
2600
2572
  const authToken = getAuthToken(request);
2573
+ const acceptsEventStream = (request.headers.get("accept") || "").toLowerCase().includes("text/event-stream");
2601
2574
  if (!identity) {
2602
2575
  return Response.json({ error: { code: "MISSING_IDENTITY", message: "Missing identity" } }, { status: 400 });
2603
2576
  }
@@ -2605,28 +2578,103 @@ data: ${JSON.stringify(data)}
2605
2578
  if (!isAuthorized) {
2606
2579
  return Response.json({ error: { code: "UNAUTHORIZED", message: "Unauthorized" } }, { status: 401 });
2607
2580
  }
2581
+ let rawBody = "";
2608
2582
  try {
2609
- const body = await request.json();
2610
- const manager = managers.get(identity);
2611
- if (!manager) {
2583
+ rawBody = await request.text();
2584
+ const body = rawBody ? JSON.parse(rawBody) : null;
2585
+ if (!body || typeof body !== "object") {
2612
2586
  return Response.json(
2613
2587
  {
2614
2588
  error: {
2615
- code: "NO_CONNECTION",
2616
- message: "No SSE connection found. Please establish SSE connection first."
2589
+ code: "INVALID_REQUEST",
2590
+ message: "Invalid JSON-RPC request body"
2617
2591
  }
2618
2592
  },
2619
2593
  { status: 400 }
2620
2594
  );
2621
2595
  }
2622
- const response = await manager.handleRequest(body);
2623
- 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
+ });
2624
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
+ });
2625
2673
  return Response.json(
2626
2674
  {
2627
2675
  error: {
2628
2676
  code: "EXECUTION_ERROR",
2629
- message: error instanceof Error ? error.message : "Unknown error"
2677
+ message: err.message
2630
2678
  }
2631
2679
  },
2632
2680
  { status: 500 }
@@ -2635,62 +2683,27 @@ data: ${JSON.stringify(data)}
2635
2683
  }
2636
2684
  return { GET, POST };
2637
2685
  }
2638
- var DEFAULT_REQUEST_TIMEOUT = 6e4;
2639
- var MAX_RECONNECT_ATTEMPTS = 5;
2640
- var BASE_RECONNECT_DELAY = 1e3;
2641
2686
  var SSEClient = class {
2642
2687
  constructor(options) {
2643
2688
  this.options = options;
2644
- __publicField(this, "eventSource", null);
2645
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
2646
2689
  __publicField(this, "resourceCache", /* @__PURE__ */ new Map());
2647
- __publicField(this, "reconnectAttempts", 0);
2648
- __publicField(this, "isManuallyDisconnected", false);
2649
- __publicField(this, "connectionPromise", null);
2650
- __publicField(this, "connectionResolver", null);
2690
+ __publicField(this, "connected", false);
2651
2691
  }
2652
- // ============================================
2653
- // Connection Management
2654
- // ============================================
2655
- /**
2656
- * Connect to the SSE endpoint
2657
- */
2658
2692
  connect() {
2659
- if (this.eventSource) {
2693
+ if (this.connected) {
2660
2694
  return;
2661
2695
  }
2662
- this.isManuallyDisconnected = false;
2663
- this.options.onStatusChange?.("connecting");
2664
- this.connectionPromise = new Promise((resolve) => {
2665
- this.connectionResolver = resolve;
2666
- });
2667
- const url = this.buildUrl();
2668
- this.eventSource = new EventSource(url);
2669
- this.setupEventListeners();
2696
+ this.connected = true;
2697
+ this.options.onStatusChange?.("connected");
2698
+ this.log("RPC mode: post_stream");
2670
2699
  }
2671
- /**
2672
- * Disconnect from the SSE endpoint
2673
- */
2674
2700
  disconnect() {
2675
- this.isManuallyDisconnected = true;
2676
- if (this.eventSource) {
2677
- this.eventSource.close();
2678
- this.eventSource = null;
2679
- }
2680
- this.connectionPromise = null;
2681
- this.connectionResolver = null;
2682
- this.rejectAllPendingRequests(new Error("Connection closed"));
2701
+ this.connected = false;
2683
2702
  this.options.onStatusChange?.("disconnected");
2684
2703
  }
2685
- /**
2686
- * Check if connected to the SSE endpoint
2687
- */
2688
2704
  isConnected() {
2689
- return this.eventSource?.readyState === EventSource.OPEN;
2705
+ return this.connected;
2690
2706
  }
2691
- // ============================================
2692
- // RPC Methods
2693
- // ============================================
2694
2707
  async getSessions() {
2695
2708
  return this.sendRequest("getSessions");
2696
2709
  }
@@ -2726,22 +2739,10 @@ var SSEClient = class {
2726
2739
  async readResource(sessionId, uri) {
2727
2740
  return this.sendRequest("readResource", { sessionId, uri });
2728
2741
  }
2729
- // ============================================
2730
- // Resource Preloading (for instant UI loading)
2731
- // ============================================
2732
- /**
2733
- * Preload UI resources for tools that have UI metadata.
2734
- * Call this when tools are discovered to enable instant MCP App UI loading.
2735
- */
2736
2742
  preloadToolUiResources(sessionId, tools) {
2737
2743
  for (const tool of tools) {
2738
2744
  const uri = this.extractUiResourceUri(tool);
2739
- if (!uri) continue;
2740
- if (this.resourceCache.has(uri)) {
2741
- this.log(`Resource already cached: ${uri}`);
2742
- continue;
2743
- }
2744
- this.log(`Preloading UI resource for tool "${tool.name}": ${uri}`);
2745
+ if (!uri || this.resourceCache.has(uri)) continue;
2745
2746
  const promise = this.sendRequest("readResource", { sessionId, uri }).catch((err) => {
2746
2747
  this.log(`Failed to preload resource ${uri}: ${err.message}`, "warn");
2747
2748
  this.resourceCache.delete(uri);
@@ -2750,43 +2751,24 @@ var SSEClient = class {
2750
2751
  this.resourceCache.set(uri, promise);
2751
2752
  }
2752
2753
  }
2753
- /**
2754
- * Get a preloaded resource from cache, or fetch if not cached.
2755
- */
2756
2754
  getOrFetchResource(sessionId, uri) {
2757
2755
  const cached = this.resourceCache.get(uri);
2758
- if (cached) {
2759
- this.log(`Cache hit for resource: ${uri}`);
2760
- return cached;
2761
- }
2762
- this.log(`Cache miss, fetching resource: ${uri}`);
2756
+ if (cached) return cached;
2763
2757
  const promise = this.sendRequest("readResource", { sessionId, uri });
2764
2758
  this.resourceCache.set(uri, promise);
2765
2759
  return promise;
2766
2760
  }
2767
- /**
2768
- * Check if a resource is already cached
2769
- */
2770
2761
  hasPreloadedResource(uri) {
2771
2762
  return this.resourceCache.has(uri);
2772
2763
  }
2773
- /**
2774
- * Clear the resource cache
2775
- */
2776
2764
  clearResourceCache() {
2777
2765
  this.resourceCache.clear();
2778
2766
  }
2779
- // ============================================
2780
- // Private: Request Handling
2781
- // ============================================
2782
- /**
2783
- * Send an RPC request and return the response directly from HTTP.
2784
- * This bypasses SSE latency by returning results in the HTTP response body.
2785
- */
2786
2767
  async sendRequest(method, params) {
2787
- if (this.connectionPromise) {
2788
- await this.connectionPromise;
2768
+ if (!this.connected) {
2769
+ this.connect();
2789
2770
  }
2771
+ this.log(`RPC request via post_stream: ${method}`);
2790
2772
  const request = {
2791
2773
  id: `rpc_${nanoid.nanoid(10)}`,
2792
2774
  method,
@@ -2800,103 +2782,93 @@ var SSEClient = class {
2800
2782
  if (!response.ok) {
2801
2783
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
2802
2784
  }
2803
- const data = await response.json();
2804
- 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;
2805
2859
  }
2806
- /**
2807
- * Parse RPC response and handle different response formats
2808
- */
2809
- parseRpcResponse(data, requestId) {
2860
+ parseRpcResponse(data) {
2810
2861
  if ("result" in data) {
2811
2862
  return data.result;
2812
2863
  }
2813
2864
  if ("error" in data && data.error) {
2814
2865
  throw new Error(data.error.message || "Unknown RPC error");
2815
2866
  }
2816
- if ("acknowledged" in data) {
2817
- return this.waitForSseResponse(requestId);
2867
+ if (data && typeof data === "object" && "id" in data) {
2868
+ return void 0;
2818
2869
  }
2819
2870
  throw new Error("Invalid RPC response format");
2820
2871
  }
2821
- /**
2822
- * Wait for RPC response via SSE (legacy fallback)
2823
- */
2824
- waitForSseResponse(requestId) {
2825
- const timeoutMs = this.options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
2826
- return new Promise((resolve, reject) => {
2827
- const timeoutId = setTimeout(() => {
2828
- this.pendingRequests.delete(requestId);
2829
- reject(new Error(`Request timeout after ${timeoutMs}ms`));
2830
- }, timeoutMs);
2831
- this.pendingRequests.set(requestId, {
2832
- resolve,
2833
- reject,
2834
- timeoutId
2835
- });
2836
- });
2837
- }
2838
- /**
2839
- * Handle RPC response received via SSE (legacy)
2840
- */
2841
- handleRpcResponse(response) {
2842
- const pending = this.pendingRequests.get(response.id);
2843
- if (!pending) return;
2844
- clearTimeout(pending.timeoutId);
2845
- this.pendingRequests.delete(response.id);
2846
- if (response.error) {
2847
- pending.reject(new Error(response.error.message));
2848
- } else {
2849
- pending.resolve(response.result);
2850
- }
2851
- }
2852
- // ============================================
2853
- // Private: Event Handling
2854
- // ============================================
2855
- setupEventListeners() {
2856
- if (!this.eventSource) return;
2857
- this.eventSource.addEventListener("open", () => {
2858
- this.log("Connected");
2859
- this.reconnectAttempts = 0;
2860
- this.options.onStatusChange?.("connected");
2861
- });
2862
- this.eventSource.addEventListener("connected", () => {
2863
- this.log("Server ready");
2864
- this.connectionResolver?.();
2865
- this.connectionResolver = null;
2866
- });
2867
- this.eventSource.addEventListener("connection", (e) => {
2868
- const event = JSON.parse(e.data);
2869
- this.options.onConnectionEvent?.(event);
2870
- });
2871
- this.eventSource.addEventListener("observability", (e) => {
2872
- const event = JSON.parse(e.data);
2873
- this.options.onObservabilityEvent?.(event);
2874
- });
2875
- this.eventSource.addEventListener("rpc-response", (e) => {
2876
- const response = JSON.parse(e.data);
2877
- this.handleRpcResponse(response);
2878
- });
2879
- this.eventSource.addEventListener("error", () => {
2880
- this.log("Connection error", "error");
2881
- this.options.onStatusChange?.("error");
2882
- this.attemptReconnect();
2883
- });
2884
- }
2885
- attemptReconnect() {
2886
- if (this.isManuallyDisconnected || this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
2887
- return;
2888
- }
2889
- this.reconnectAttempts++;
2890
- const delay = BASE_RECONNECT_DELAY * this.reconnectAttempts;
2891
- this.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
2892
- setTimeout(() => {
2893
- this.disconnect();
2894
- this.connect();
2895
- }, delay);
2896
- }
2897
- // ============================================
2898
- // Private: Utilities
2899
- // ============================================
2900
2872
  buildUrl() {
2901
2873
  const url = new URL(this.options.url, globalThis.location?.origin);
2902
2874
  url.searchParams.set("identity", this.options.identity);
@@ -2907,20 +2879,14 @@ var SSEClient = class {
2907
2879
  }
2908
2880
  buildHeaders() {
2909
2881
  const headers = {
2910
- "Content-Type": "application/json"
2882
+ "Content-Type": "application/json",
2883
+ "Accept": "text/event-stream"
2911
2884
  };
2912
2885
  if (this.options.authToken) {
2913
2886
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
2914
2887
  }
2915
2888
  return headers;
2916
2889
  }
2917
- rejectAllPendingRequests(error) {
2918
- for (const [, pending] of this.pendingRequests) {
2919
- clearTimeout(pending.timeoutId);
2920
- pending.reject(error);
2921
- }
2922
- this.pendingRequests.clear();
2923
- }
2924
2890
  extractUiResourceUri(tool) {
2925
2891
  const meta = tool._meta?.ui;
2926
2892
  if (!meta || typeof meta !== "object") return void 0;