@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
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-B1DBx5yR.mjs';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DzjmT7FX.mjs';
2
2
  import '../events-CK3N--3g.mjs';
3
3
  import '@modelcontextprotocol/sdk/types.js';
4
4
  import '@modelcontextprotocol/sdk/client/auth.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DyFzyJUx.js';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-FAFpUzZ4.js';
2
2
  import '../events-CK3N--3g.js';
3
3
  import '@modelcontextprotocol/sdk/types.js';
4
4
  import '@modelcontextprotocol/sdk/client/auth.js';
@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
2
2
  import { Middleware, RunAgentInput, AbstractAgent, BaseEvent } from '@ag-ui/client';
3
3
  export { AbstractAgent, BaseEvent, EventType, Middleware, RunAgentInput, Tool, ToolCallEndEvent } from '@ag-ui/client';
4
4
  import { AguiTool } from './agui-adapter.mjs';
5
- import '../multi-session-client-B1DBx5yR.mjs';
5
+ import '../multi-session-client-DzjmT7FX.mjs';
6
6
  import '../events-CK3N--3g.mjs';
7
7
  import '@modelcontextprotocol/sdk/types.js';
8
8
  import '@modelcontextprotocol/sdk/client/auth.js';
@@ -2,7 +2,7 @@ import { Observable } from 'rxjs';
2
2
  import { Middleware, RunAgentInput, AbstractAgent, BaseEvent } from '@ag-ui/client';
3
3
  export { AbstractAgent, BaseEvent, EventType, Middleware, RunAgentInput, Tool, ToolCallEndEvent } from '@ag-ui/client';
4
4
  import { AguiTool } from './agui-adapter.js';
5
- import '../multi-session-client-DyFzyJUx.js';
5
+ import '../multi-session-client-FAFpUzZ4.js';
6
6
  import '../events-CK3N--3g.js';
7
7
  import '@modelcontextprotocol/sdk/types.js';
8
8
  import '@modelcontextprotocol/sdk/client/auth.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-B1DBx5yR.mjs';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DzjmT7FX.mjs';
2
2
  import { ToolSet } from 'ai';
3
3
  import '../events-CK3N--3g.mjs';
4
4
  import '@modelcontextprotocol/sdk/types.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DyFzyJUx.js';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-FAFpUzZ4.js';
2
2
  import { ToolSet } from 'ai';
3
3
  import '../events-CK3N--3g.js';
4
4
  import '@modelcontextprotocol/sdk/types.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-B1DBx5yR.mjs';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DzjmT7FX.mjs';
2
2
  import { StructuredTool } from '@langchain/core/tools';
3
3
  import '../events-CK3N--3g.mjs';
4
4
  import '@modelcontextprotocol/sdk/types.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DyFzyJUx.js';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-FAFpUzZ4.js';
2
2
  import { StructuredTool } from '@langchain/core/tools';
3
3
  import '../events-CK3N--3g.js';
4
4
  import '@modelcontextprotocol/sdk/types.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-B1DBx5yR.mjs';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DzjmT7FX.mjs';
2
2
  import { z } from 'zod';
3
3
  import '../events-CK3N--3g.mjs';
4
4
  import '@modelcontextprotocol/sdk/types.js';
@@ -1,4 +1,4 @@
1
- import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-DyFzyJUx.js';
1
+ import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-FAFpUzZ4.js';
2
2
  import { z } from 'zod';
3
3
  import '../events-CK3N--3g.js';
4
4
  import '@modelcontextprotocol/sdk/types.js';
@@ -1,25 +1,18 @@
1
1
  import { M as McpConnectionEvent, d as McpObservabilityEvent, e as McpAppsUIEvent } from '../events-CK3N--3g.mjs';
2
2
  export { D as Disposable, a as DisposableStore, E as Emitter, b as Event, c as McpConnectionState } from '../events-CK3N--3g.mjs';
3
- import { s as SessionListResult, e as ConnectParams, h as ConnectResult, j as DisconnectResult, n as ListToolsRpcResult, r as RestoreSessionResult, k as FinishAuthResult, L as ListPromptsResult, l as ListResourcesResult } from '../types-PjM1W07s.mjs';
4
- export { p as McpRpcRequest, q as McpRpcResponse, T as ToolInfo } from '../types-PjM1W07s.mjs';
3
+ import { s as SessionListResult, e as ConnectParams, h as ConnectResult, j as DisconnectResult, n as ListToolsRpcResult, r as RestoreSessionResult, k as FinishAuthResult, L as ListPromptsResult, l as ListResourcesResult } from '../types-CW6lghof.mjs';
4
+ export { p as McpRpcRequest, q as McpRpcResponse, T as ToolInfo } from '../types-CW6lghof.mjs';
5
5
  import '@modelcontextprotocol/sdk/types.js';
6
6
 
7
7
  /**
8
- * SSE Client for MCP Connections
8
+ * Stateless RPC-over-stream client for MCP connections.
9
9
  *
10
- * Browser-side client that manages real-time communication with the MCP server
11
- * using Server-Sent Events (SSE) for server→client streaming and HTTP POST for
12
- * client→server RPC requests.
13
- *
14
- * Key features:
15
- * - Direct HTTP response for RPC calls (bypasses SSE latency)
16
- * - Resource preloading for instant MCP App UI loading
17
- * - Automatic reconnection with exponential backoff
18
- * - Type-safe RPC methods
10
+ * Uses single POST requests with `Accept: text/event-stream` for every RPC call.
11
+ * Progress events and the final rpc-response are delivered in the same response.
19
12
  */
20
13
 
21
14
  interface SSEClientOptions {
22
- /** SSE endpoint URL */
15
+ /** MCP endpoint URL */
23
16
  url: string;
24
17
  /** User/Client identifier */
25
18
  identity: string;
@@ -33,36 +26,17 @@ interface SSEClientOptions {
33
26
  onStatusChange?: (status: ConnectionStatus) => void;
34
27
  /** Callback for MCP App UI events */
35
28
  onEvent?: (event: McpAppsUIEvent) => void;
36
- /** Request timeout in milliseconds @default 60000 */
37
- requestTimeout?: number;
38
29
  /** Enable debug logging @default false */
39
30
  debug?: boolean;
40
31
  }
41
32
  type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'error';
42
- /**
43
- * SSE Client for real-time MCP connection management
44
- */
45
33
  declare class SSEClient {
46
34
  private readonly options;
47
- private eventSource;
48
- private pendingRequests;
49
35
  private resourceCache;
50
- private reconnectAttempts;
51
- private isManuallyDisconnected;
52
- private connectionPromise;
53
- private connectionResolver;
36
+ private connected;
54
37
  constructor(options: SSEClientOptions);
55
- /**
56
- * Connect to the SSE endpoint
57
- */
58
38
  connect(): void;
59
- /**
60
- * Disconnect from the SSE endpoint
61
- */
62
39
  disconnect(): void;
63
- /**
64
- * Check if connected to the SSE endpoint
65
- */
66
40
  isConnected(): boolean;
67
41
  getSessions(): Promise<SessionListResult>;
68
42
  connectToServer(params: ConnectParams): Promise<ConnectResult>;
@@ -75,48 +49,18 @@ declare class SSEClient {
75
49
  getPrompt(sessionId: string, name: string, args?: Record<string, string>): Promise<unknown>;
76
50
  listResources(sessionId: string): Promise<ListResourcesResult>;
77
51
  readResource(sessionId: string, uri: string): Promise<unknown>;
78
- /**
79
- * Preload UI resources for tools that have UI metadata.
80
- * Call this when tools are discovered to enable instant MCP App UI loading.
81
- */
82
52
  preloadToolUiResources(sessionId: string, tools: Array<{
83
53
  name: string;
84
54
  _meta?: unknown;
85
55
  }>): void;
86
- /**
87
- * Get a preloaded resource from cache, or fetch if not cached.
88
- */
89
56
  getOrFetchResource(sessionId: string, uri: string): Promise<unknown>;
90
- /**
91
- * Check if a resource is already cached
92
- */
93
57
  hasPreloadedResource(uri: string): boolean;
94
- /**
95
- * Clear the resource cache
96
- */
97
58
  clearResourceCache(): void;
98
- /**
99
- * Send an RPC request and return the response directly from HTTP.
100
- * This bypasses SSE latency by returning results in the HTTP response body.
101
- */
102
59
  private sendRequest;
103
- /**
104
- * Parse RPC response and handle different response formats
105
- */
60
+ private readRpcResponseFromStream;
106
61
  private parseRpcResponse;
107
- /**
108
- * Wait for RPC response via SSE (legacy fallback)
109
- */
110
- private waitForSseResponse;
111
- /**
112
- * Handle RPC response received via SSE (legacy)
113
- */
114
- private handleRpcResponse;
115
- private setupEventListeners;
116
- private attemptReconnect;
117
62
  private buildUrl;
118
63
  private buildHeaders;
119
- private rejectAllPendingRequests;
120
64
  private extractUiResourceUri;
121
65
  private emitUiEventIfPresent;
122
66
  private log;
@@ -1,25 +1,18 @@
1
1
  import { M as McpConnectionEvent, d as McpObservabilityEvent, e as McpAppsUIEvent } from '../events-CK3N--3g.js';
2
2
  export { D as Disposable, a as DisposableStore, E as Emitter, b as Event, c as McpConnectionState } from '../events-CK3N--3g.js';
3
- import { s as SessionListResult, e as ConnectParams, h as ConnectResult, j as DisconnectResult, n as ListToolsRpcResult, r as RestoreSessionResult, k as FinishAuthResult, L as ListPromptsResult, l as ListResourcesResult } from '../types-PjM1W07s.js';
4
- export { p as McpRpcRequest, q as McpRpcResponse, T as ToolInfo } from '../types-PjM1W07s.js';
3
+ import { s as SessionListResult, e as ConnectParams, h as ConnectResult, j as DisconnectResult, n as ListToolsRpcResult, r as RestoreSessionResult, k as FinishAuthResult, L as ListPromptsResult, l as ListResourcesResult } from '../types-CW6lghof.js';
4
+ export { p as McpRpcRequest, q as McpRpcResponse, T as ToolInfo } from '../types-CW6lghof.js';
5
5
  import '@modelcontextprotocol/sdk/types.js';
6
6
 
7
7
  /**
8
- * SSE Client for MCP Connections
8
+ * Stateless RPC-over-stream client for MCP connections.
9
9
  *
10
- * Browser-side client that manages real-time communication with the MCP server
11
- * using Server-Sent Events (SSE) for server→client streaming and HTTP POST for
12
- * client→server RPC requests.
13
- *
14
- * Key features:
15
- * - Direct HTTP response for RPC calls (bypasses SSE latency)
16
- * - Resource preloading for instant MCP App UI loading
17
- * - Automatic reconnection with exponential backoff
18
- * - Type-safe RPC methods
10
+ * Uses single POST requests with `Accept: text/event-stream` for every RPC call.
11
+ * Progress events and the final rpc-response are delivered in the same response.
19
12
  */
20
13
 
21
14
  interface SSEClientOptions {
22
- /** SSE endpoint URL */
15
+ /** MCP endpoint URL */
23
16
  url: string;
24
17
  /** User/Client identifier */
25
18
  identity: string;
@@ -33,36 +26,17 @@ interface SSEClientOptions {
33
26
  onStatusChange?: (status: ConnectionStatus) => void;
34
27
  /** Callback for MCP App UI events */
35
28
  onEvent?: (event: McpAppsUIEvent) => void;
36
- /** Request timeout in milliseconds @default 60000 */
37
- requestTimeout?: number;
38
29
  /** Enable debug logging @default false */
39
30
  debug?: boolean;
40
31
  }
41
32
  type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'error';
42
- /**
43
- * SSE Client for real-time MCP connection management
44
- */
45
33
  declare class SSEClient {
46
34
  private readonly options;
47
- private eventSource;
48
- private pendingRequests;
49
35
  private resourceCache;
50
- private reconnectAttempts;
51
- private isManuallyDisconnected;
52
- private connectionPromise;
53
- private connectionResolver;
36
+ private connected;
54
37
  constructor(options: SSEClientOptions);
55
- /**
56
- * Connect to the SSE endpoint
57
- */
58
38
  connect(): void;
59
- /**
60
- * Disconnect from the SSE endpoint
61
- */
62
39
  disconnect(): void;
63
- /**
64
- * Check if connected to the SSE endpoint
65
- */
66
40
  isConnected(): boolean;
67
41
  getSessions(): Promise<SessionListResult>;
68
42
  connectToServer(params: ConnectParams): Promise<ConnectResult>;
@@ -75,48 +49,18 @@ declare class SSEClient {
75
49
  getPrompt(sessionId: string, name: string, args?: Record<string, string>): Promise<unknown>;
76
50
  listResources(sessionId: string): Promise<ListResourcesResult>;
77
51
  readResource(sessionId: string, uri: string): Promise<unknown>;
78
- /**
79
- * Preload UI resources for tools that have UI metadata.
80
- * Call this when tools are discovered to enable instant MCP App UI loading.
81
- */
82
52
  preloadToolUiResources(sessionId: string, tools: Array<{
83
53
  name: string;
84
54
  _meta?: unknown;
85
55
  }>): void;
86
- /**
87
- * Get a preloaded resource from cache, or fetch if not cached.
88
- */
89
56
  getOrFetchResource(sessionId: string, uri: string): Promise<unknown>;
90
- /**
91
- * Check if a resource is already cached
92
- */
93
57
  hasPreloadedResource(uri: string): boolean;
94
- /**
95
- * Clear the resource cache
96
- */
97
58
  clearResourceCache(): void;
98
- /**
99
- * Send an RPC request and return the response directly from HTTP.
100
- * This bypasses SSE latency by returning results in the HTTP response body.
101
- */
102
59
  private sendRequest;
103
- /**
104
- * Parse RPC response and handle different response formats
105
- */
60
+ private readRpcResponseFromStream;
106
61
  private parseRpcResponse;
107
- /**
108
- * Wait for RPC response via SSE (legacy fallback)
109
- */
110
- private waitForSseResponse;
111
- /**
112
- * Handle RPC response received via SSE (legacy)
113
- */
114
- private handleRpcResponse;
115
- private setupEventListeners;
116
- private attemptReconnect;
117
62
  private buildUrl;
118
63
  private buildHeaders;
119
- private rejectAllPendingRequests;
120
64
  private extractUiResourceUri;
121
65
  private emitUiEventIfPresent;
122
66
  private log;
@@ -6,62 +6,27 @@ var appBridge = require('@modelcontextprotocol/ext-apps/app-bridge');
6
6
  var __defProp = Object.defineProperty;
7
7
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
8
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
9
- var DEFAULT_REQUEST_TIMEOUT = 6e4;
10
- var MAX_RECONNECT_ATTEMPTS = 5;
11
- var BASE_RECONNECT_DELAY = 1e3;
12
9
  var SSEClient = class {
13
10
  constructor(options) {
14
11
  this.options = options;
15
- __publicField(this, "eventSource", null);
16
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
17
12
  __publicField(this, "resourceCache", /* @__PURE__ */ new Map());
18
- __publicField(this, "reconnectAttempts", 0);
19
- __publicField(this, "isManuallyDisconnected", false);
20
- __publicField(this, "connectionPromise", null);
21
- __publicField(this, "connectionResolver", null);
13
+ __publicField(this, "connected", false);
22
14
  }
23
- // ============================================
24
- // Connection Management
25
- // ============================================
26
- /**
27
- * Connect to the SSE endpoint
28
- */
29
15
  connect() {
30
- if (this.eventSource) {
16
+ if (this.connected) {
31
17
  return;
32
18
  }
33
- this.isManuallyDisconnected = false;
34
- this.options.onStatusChange?.("connecting");
35
- this.connectionPromise = new Promise((resolve) => {
36
- this.connectionResolver = resolve;
37
- });
38
- const url = this.buildUrl();
39
- this.eventSource = new EventSource(url);
40
- this.setupEventListeners();
19
+ this.connected = true;
20
+ this.options.onStatusChange?.("connected");
21
+ this.log("RPC mode: post_stream");
41
22
  }
42
- /**
43
- * Disconnect from the SSE endpoint
44
- */
45
23
  disconnect() {
46
- this.isManuallyDisconnected = true;
47
- if (this.eventSource) {
48
- this.eventSource.close();
49
- this.eventSource = null;
50
- }
51
- this.connectionPromise = null;
52
- this.connectionResolver = null;
53
- this.rejectAllPendingRequests(new Error("Connection closed"));
24
+ this.connected = false;
54
25
  this.options.onStatusChange?.("disconnected");
55
26
  }
56
- /**
57
- * Check if connected to the SSE endpoint
58
- */
59
27
  isConnected() {
60
- return this.eventSource?.readyState === EventSource.OPEN;
28
+ return this.connected;
61
29
  }
62
- // ============================================
63
- // RPC Methods
64
- // ============================================
65
30
  async getSessions() {
66
31
  return this.sendRequest("getSessions");
67
32
  }
@@ -97,22 +62,10 @@ var SSEClient = class {
97
62
  async readResource(sessionId, uri) {
98
63
  return this.sendRequest("readResource", { sessionId, uri });
99
64
  }
100
- // ============================================
101
- // Resource Preloading (for instant UI loading)
102
- // ============================================
103
- /**
104
- * Preload UI resources for tools that have UI metadata.
105
- * Call this when tools are discovered to enable instant MCP App UI loading.
106
- */
107
65
  preloadToolUiResources(sessionId, tools) {
108
66
  for (const tool of tools) {
109
67
  const uri = this.extractUiResourceUri(tool);
110
- if (!uri) continue;
111
- if (this.resourceCache.has(uri)) {
112
- this.log(`Resource already cached: ${uri}`);
113
- continue;
114
- }
115
- this.log(`Preloading UI resource for tool "${tool.name}": ${uri}`);
68
+ if (!uri || this.resourceCache.has(uri)) continue;
116
69
  const promise = this.sendRequest("readResource", { sessionId, uri }).catch((err) => {
117
70
  this.log(`Failed to preload resource ${uri}: ${err.message}`, "warn");
118
71
  this.resourceCache.delete(uri);
@@ -121,43 +74,24 @@ var SSEClient = class {
121
74
  this.resourceCache.set(uri, promise);
122
75
  }
123
76
  }
124
- /**
125
- * Get a preloaded resource from cache, or fetch if not cached.
126
- */
127
77
  getOrFetchResource(sessionId, uri) {
128
78
  const cached = this.resourceCache.get(uri);
129
- if (cached) {
130
- this.log(`Cache hit for resource: ${uri}`);
131
- return cached;
132
- }
133
- this.log(`Cache miss, fetching resource: ${uri}`);
79
+ if (cached) return cached;
134
80
  const promise = this.sendRequest("readResource", { sessionId, uri });
135
81
  this.resourceCache.set(uri, promise);
136
82
  return promise;
137
83
  }
138
- /**
139
- * Check if a resource is already cached
140
- */
141
84
  hasPreloadedResource(uri) {
142
85
  return this.resourceCache.has(uri);
143
86
  }
144
- /**
145
- * Clear the resource cache
146
- */
147
87
  clearResourceCache() {
148
88
  this.resourceCache.clear();
149
89
  }
150
- // ============================================
151
- // Private: Request Handling
152
- // ============================================
153
- /**
154
- * Send an RPC request and return the response directly from HTTP.
155
- * This bypasses SSE latency by returning results in the HTTP response body.
156
- */
157
90
  async sendRequest(method, params) {
158
- if (this.connectionPromise) {
159
- await this.connectionPromise;
91
+ if (!this.connected) {
92
+ this.connect();
160
93
  }
94
+ this.log(`RPC request via post_stream: ${method}`);
161
95
  const request = {
162
96
  id: `rpc_${nanoid.nanoid(10)}`,
163
97
  method,
@@ -171,103 +105,93 @@ var SSEClient = class {
171
105
  if (!response.ok) {
172
106
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
173
107
  }
174
- const data = await response.json();
175
- return this.parseRpcResponse(data, request.id);
108
+ const contentType = (response.headers.get("content-type") || "").toLowerCase();
109
+ if (!contentType.includes("text/event-stream")) {
110
+ const data2 = await response.json();
111
+ return this.parseRpcResponse(data2);
112
+ }
113
+ const data = await this.readRpcResponseFromStream(response);
114
+ return this.parseRpcResponse(data);
176
115
  }
177
- /**
178
- * Parse RPC response and handle different response formats
179
- */
180
- parseRpcResponse(data, requestId) {
116
+ async readRpcResponseFromStream(response) {
117
+ if (!response.body) {
118
+ throw new Error("Streaming response body is missing");
119
+ }
120
+ const reader = response.body.getReader();
121
+ const decoder = new TextDecoder();
122
+ let buffer = "";
123
+ let rpcResponse = null;
124
+ const dispatchBlock = (block) => {
125
+ const lines = block.split("\n");
126
+ let eventName = "message";
127
+ const dataLines = [];
128
+ for (const rawLine of lines) {
129
+ const line = rawLine.replace(/\r$/, "");
130
+ if (!line || line.startsWith(":")) continue;
131
+ if (line.startsWith("event:")) {
132
+ eventName = line.slice("event:".length).trim();
133
+ continue;
134
+ }
135
+ if (line.startsWith("data:")) {
136
+ dataLines.push(line.slice("data:".length).trimStart());
137
+ }
138
+ }
139
+ if (!dataLines.length) return;
140
+ const payloadText = dataLines.join("\n");
141
+ let payload = payloadText;
142
+ try {
143
+ payload = JSON.parse(payloadText);
144
+ } catch {
145
+ }
146
+ switch (eventName) {
147
+ case "connected":
148
+ this.options.onStatusChange?.("connected");
149
+ break;
150
+ case "connection":
151
+ this.options.onConnectionEvent?.(payload);
152
+ break;
153
+ case "observability":
154
+ this.options.onObservabilityEvent?.(payload);
155
+ break;
156
+ case "rpc-response":
157
+ rpcResponse = payload;
158
+ break;
159
+ }
160
+ };
161
+ while (true) {
162
+ const { value, done } = await reader.read();
163
+ if (done) break;
164
+ buffer += decoder.decode(value, { stream: true });
165
+ let separatorMatch = buffer.match(/\r?\n\r?\n/);
166
+ while (separatorMatch && separatorMatch.index !== void 0) {
167
+ const separatorIndex = separatorMatch.index;
168
+ const separatorLength = separatorMatch[0].length;
169
+ const block = buffer.slice(0, separatorIndex);
170
+ buffer = buffer.slice(separatorIndex + separatorLength);
171
+ dispatchBlock(block);
172
+ separatorMatch = buffer.match(/\r?\n\r?\n/);
173
+ }
174
+ }
175
+ if (buffer.trim()) {
176
+ dispatchBlock(buffer);
177
+ }
178
+ if (!rpcResponse) {
179
+ throw new Error("Missing rpc-response event in streamed RPC result");
180
+ }
181
+ return rpcResponse;
182
+ }
183
+ parseRpcResponse(data) {
181
184
  if ("result" in data) {
182
185
  return data.result;
183
186
  }
184
187
  if ("error" in data && data.error) {
185
188
  throw new Error(data.error.message || "Unknown RPC error");
186
189
  }
187
- if ("acknowledged" in data) {
188
- return this.waitForSseResponse(requestId);
190
+ if (data && typeof data === "object" && "id" in data) {
191
+ return void 0;
189
192
  }
190
193
  throw new Error("Invalid RPC response format");
191
194
  }
192
- /**
193
- * Wait for RPC response via SSE (legacy fallback)
194
- */
195
- waitForSseResponse(requestId) {
196
- const timeoutMs = this.options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
197
- return new Promise((resolve, reject) => {
198
- const timeoutId = setTimeout(() => {
199
- this.pendingRequests.delete(requestId);
200
- reject(new Error(`Request timeout after ${timeoutMs}ms`));
201
- }, timeoutMs);
202
- this.pendingRequests.set(requestId, {
203
- resolve,
204
- reject,
205
- timeoutId
206
- });
207
- });
208
- }
209
- /**
210
- * Handle RPC response received via SSE (legacy)
211
- */
212
- handleRpcResponse(response) {
213
- const pending = this.pendingRequests.get(response.id);
214
- if (!pending) return;
215
- clearTimeout(pending.timeoutId);
216
- this.pendingRequests.delete(response.id);
217
- if (response.error) {
218
- pending.reject(new Error(response.error.message));
219
- } else {
220
- pending.resolve(response.result);
221
- }
222
- }
223
- // ============================================
224
- // Private: Event Handling
225
- // ============================================
226
- setupEventListeners() {
227
- if (!this.eventSource) return;
228
- this.eventSource.addEventListener("open", () => {
229
- this.log("Connected");
230
- this.reconnectAttempts = 0;
231
- this.options.onStatusChange?.("connected");
232
- });
233
- this.eventSource.addEventListener("connected", () => {
234
- this.log("Server ready");
235
- this.connectionResolver?.();
236
- this.connectionResolver = null;
237
- });
238
- this.eventSource.addEventListener("connection", (e) => {
239
- const event = JSON.parse(e.data);
240
- this.options.onConnectionEvent?.(event);
241
- });
242
- this.eventSource.addEventListener("observability", (e) => {
243
- const event = JSON.parse(e.data);
244
- this.options.onObservabilityEvent?.(event);
245
- });
246
- this.eventSource.addEventListener("rpc-response", (e) => {
247
- const response = JSON.parse(e.data);
248
- this.handleRpcResponse(response);
249
- });
250
- this.eventSource.addEventListener("error", () => {
251
- this.log("Connection error", "error");
252
- this.options.onStatusChange?.("error");
253
- this.attemptReconnect();
254
- });
255
- }
256
- attemptReconnect() {
257
- if (this.isManuallyDisconnected || this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
258
- return;
259
- }
260
- this.reconnectAttempts++;
261
- const delay = BASE_RECONNECT_DELAY * this.reconnectAttempts;
262
- this.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
263
- setTimeout(() => {
264
- this.disconnect();
265
- this.connect();
266
- }, delay);
267
- }
268
- // ============================================
269
- // Private: Utilities
270
- // ============================================
271
195
  buildUrl() {
272
196
  const url = new URL(this.options.url, globalThis.location?.origin);
273
197
  url.searchParams.set("identity", this.options.identity);
@@ -278,20 +202,14 @@ var SSEClient = class {
278
202
  }
279
203
  buildHeaders() {
280
204
  const headers = {
281
- "Content-Type": "application/json"
205
+ "Content-Type": "application/json",
206
+ "Accept": "text/event-stream"
282
207
  };
283
208
  if (this.options.authToken) {
284
209
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
285
210
  }
286
211
  return headers;
287
212
  }
288
- rejectAllPendingRequests(error) {
289
- for (const [, pending] of this.pendingRequests) {
290
- clearTimeout(pending.timeoutId);
291
- pending.reject(error);
292
- }
293
- this.pendingRequests.clear();
294
- }
295
213
  extractUiResourceUri(tool) {
296
214
  const meta = tool._meta?.ui;
297
215
  if (!meta || typeof meta !== "object") return void 0;