@mcp-ts/sdk 1.3.2 → 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.
- package/README.md +405 -406
- package/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/client/index.d.mts +8 -64
- package/dist/client/index.d.ts +8 -64
- package/dist/client/index.js +91 -173
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +91 -173
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +12 -2
- package/dist/client/react.d.ts +12 -2
- package/dist/client/react.js +119 -182
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +119 -182
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +24 -4
- package/dist/client/vue.d.ts +24 -4
- package/dist/client/vue.js +121 -182
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +121 -182
- package/dist/client/vue.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +215 -250
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +215 -250
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-B1DBx5yR.d.mts → multi-session-client-DzjmT7FX.d.mts} +1 -0
- package/dist/{multi-session-client-DyFzyJUx.d.ts → multi-session-client-FAFpUzZ4.d.ts} +1 -0
- package/dist/server/index.d.mts +16 -21
- package/dist/server/index.d.ts +16 -21
- package/dist/server/index.js +124 -77
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +124 -77
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +2 -2
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{types-PjM1W07s.d.mts → types-CW6lghof.d.mts} +5 -0
- package/dist/{types-PjM1W07s.d.ts → types-CW6lghof.d.ts} +5 -0
- package/package.json +1 -1
- package/src/client/core/sse-client.ts +354 -493
- package/src/client/react/use-mcp.ts +75 -23
- package/src/client/vue/use-mcp.ts +111 -48
- package/src/server/handlers/nextjs-handler.ts +207 -217
- package/src/server/handlers/sse-handler.ts +10 -0
- package/src/server/mcp/oauth-client.ts +41 -32
- package/src/server/storage/types.ts +12 -5
- package/src/shared/types.ts +5 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as MCPClient, a as MultiSessionClient } from '../multi-session-client-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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';
|
package/dist/client/index.d.mts
CHANGED
|
@@ -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-
|
|
4
|
-
export { p as McpRpcRequest, q as McpRpcResponse, T as ToolInfo } from '../types-
|
|
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
|
-
*
|
|
8
|
+
* Stateless RPC-over-stream client for MCP connections.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
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;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -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-
|
|
4
|
-
export { p as McpRpcRequest, q as McpRpcResponse, T as ToolInfo } from '../types-
|
|
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
|
-
*
|
|
8
|
+
* Stateless RPC-over-stream client for MCP connections.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
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;
|
package/dist/client/index.js
CHANGED
|
@@ -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, "
|
|
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.
|
|
16
|
+
if (this.connected) {
|
|
31
17
|
return;
|
|
32
18
|
}
|
|
33
|
-
this.
|
|
34
|
-
this.options.onStatusChange?.("
|
|
35
|
-
this.
|
|
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.
|
|
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.
|
|
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.
|
|
159
|
-
|
|
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
|
|
175
|
-
|
|
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
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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 ("
|
|
188
|
-
return
|
|
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;
|