@stdiobus/workers-registry 1.3.7
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/LICENSE +201 -0
- package/README.md +932 -0
- package/out/dist/workers/acp-registry/registry-launcher-client.js +52 -0
- package/out/dist/workers/acp-registry/registry-launcher-client.js.map +7 -0
- package/out/dist/workers/acp-registry/registry-launcher-config.json +31 -0
- package/out/dist/workers/acp-worker/index.js +5 -0
- package/out/dist/workers/acp-worker/index.js.map +7 -0
- package/out/dist/workers/echo-worker/echo-worker-config.json +21 -0
- package/out/dist/workers/echo-worker/echo-worker.js +3 -0
- package/out/dist/workers/echo-worker/echo-worker.js.map +7 -0
- package/out/dist/workers/index.d.ts +15 -0
- package/out/dist/workers/index.js +33 -0
- package/out/dist/workers/mcp-echo-server/index.js +3 -0
- package/out/dist/workers/mcp-echo-server/index.js.map +7 -0
- package/out/dist/workers/mcp-echo-server/mcp-echo-server-config.json +21 -0
- package/out/dist/workers/mcp-to-acp-proxy/proxy.js +3 -0
- package/out/dist/workers/mcp-to-acp-proxy/proxy.js.map +7 -0
- package/out/tsc/workers/acp-worker/src/acp/client-capabilities.d.ts +131 -0
- package/out/tsc/workers/acp-worker/src/acp/content-mapper.d.ts +95 -0
- package/out/tsc/workers/acp-worker/src/acp/index.d.ts +13 -0
- package/out/tsc/workers/acp-worker/src/acp/tools.d.ts +119 -0
- package/out/tsc/workers/acp-worker/src/agent.d.ts +113 -0
- package/out/tsc/workers/acp-worker/src/index.d.ts +1 -0
- package/out/tsc/workers/acp-worker/src/mcp/connection.d.ts +54 -0
- package/out/tsc/workers/acp-worker/src/mcp/index.d.ts +10 -0
- package/out/tsc/workers/acp-worker/src/mcp/manager.d.ts +178 -0
- package/out/tsc/workers/acp-worker/src/mcp/types.d.ts +114 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/connection.d.ts +80 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/converter.d.ts +156 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/index.d.ts +2 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/state.d.ts +165 -0
- package/out/tsc/workers/acp-worker/src/mcp-proxy/types.d.ts +163 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/api-keys.d.ts +41 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/config.d.ts +17 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/index.d.ts +10 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/config/types.d.ts +15 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/index.d.ts +2 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/log.d.ts +77 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/registry/index.d.ts +109 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/registry/resolver.d.ts +67 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/registry/types.d.ts +105 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/router/index.d.ts +8 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/router/message-router.d.ts +150 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/agent-runtime.d.ts +58 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/index.d.ts +11 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/manager.d.ts +82 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/runtime/types.d.ts +20 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/stream/index.d.ts +8 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/stream/ndjson-handler.d.ts +119 -0
- package/out/tsc/workers/acp-worker/src/registry-launcher/test-utils/index.d.ts +234 -0
- package/out/tsc/workers/acp-worker/src/session/index.d.ts +12 -0
- package/out/tsc/workers/acp-worker/src/session/manager.d.ts +63 -0
- package/out/tsc/workers/acp-worker/src/session/session.d.ts +86 -0
- package/out/tsc/workers/acp-worker/src/session/types.d.ts +33 -0
- package/out/tsc/workers/acp-worker/src/test-utils/test-harness.d.ts +80 -0
- package/out/tsc/workers/mcp-echo-server/mcp-echo-server.d.ts +2 -0
- package/package.json +77 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages multiple MCP server connections for a session.
|
|
5
|
+
* Handles connection lifecycle, tool discovery, and tool invocation.
|
|
6
|
+
*
|
|
7
|
+
* @module mcp/manager
|
|
8
|
+
*/
|
|
9
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
10
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
11
|
+
import type { ServerCapabilities } from '@modelcontextprotocol/sdk/types.js';
|
|
12
|
+
import type { MCPResource, MCPResourceReadResult, MCPServerConfig, MCPTool, MCPToolCallResult } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Represents an active MCP connection with its client and transport.
|
|
15
|
+
*/
|
|
16
|
+
export interface MCPConnection {
|
|
17
|
+
/** The MCP SDK client instance */
|
|
18
|
+
client: Client;
|
|
19
|
+
/** The stdio transport for the connection */
|
|
20
|
+
transport: StdioClientTransport;
|
|
21
|
+
/** Server configuration */
|
|
22
|
+
config: MCPServerConfig;
|
|
23
|
+
/** Whether the connection is active */
|
|
24
|
+
connected: boolean;
|
|
25
|
+
/** Server capabilities from initialization handshake */
|
|
26
|
+
capabilities?: ServerCapabilities;
|
|
27
|
+
/** Error message if the server crashed */
|
|
28
|
+
crashError?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Factory functions for creating MCP SDK instances.
|
|
32
|
+
* Used for dependency injection in tests.
|
|
33
|
+
*/
|
|
34
|
+
export interface MCPFactories {
|
|
35
|
+
/** Factory for creating Client instances */
|
|
36
|
+
createClient: (options: {
|
|
37
|
+
name: string;
|
|
38
|
+
version: string;
|
|
39
|
+
}) => Client;
|
|
40
|
+
/** Factory for creating StdioClientTransport instances */
|
|
41
|
+
createTransport: (options: {
|
|
42
|
+
command: string;
|
|
43
|
+
args?: string[];
|
|
44
|
+
env?: Record<string, string>;
|
|
45
|
+
}) => StdioClientTransport;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Manages MCP server connections for a session.
|
|
49
|
+
*/
|
|
50
|
+
export declare class MCPManager {
|
|
51
|
+
/** Active connections keyed by server ID */
|
|
52
|
+
private connections;
|
|
53
|
+
/** Map from tool name to server ID for routing tool calls */
|
|
54
|
+
private toolToServer;
|
|
55
|
+
/** Callback for server crash notifications */
|
|
56
|
+
private onServerCrash?;
|
|
57
|
+
/** Factory functions for creating SDK instances (injectable for testing) */
|
|
58
|
+
private factories;
|
|
59
|
+
/**
|
|
60
|
+
* Create a new MCPManager instance.
|
|
61
|
+
*
|
|
62
|
+
* @param factories - Optional factory functions for dependency injection (used in tests)
|
|
63
|
+
*/
|
|
64
|
+
constructor(factories?: Partial<MCPFactories>);
|
|
65
|
+
/**
|
|
66
|
+
* Set a callback to be notified when a server crashes.
|
|
67
|
+
*
|
|
68
|
+
* @param callback - Function to call when a server crashes
|
|
69
|
+
*/
|
|
70
|
+
setOnServerCrash(callback: (serverId: string, error: string) => void): void;
|
|
71
|
+
/**
|
|
72
|
+
* Connect to MCP servers specified in the configuration.
|
|
73
|
+
*
|
|
74
|
+
* @param servers - Array of MCP server configurations
|
|
75
|
+
*/
|
|
76
|
+
connect(servers: MCPServerConfig[]): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Set up crash detection for an MCP server connection.
|
|
79
|
+
*
|
|
80
|
+
* @param serverId - The server ID
|
|
81
|
+
* @param client - The MCP client
|
|
82
|
+
*/
|
|
83
|
+
private setupCrashDetection;
|
|
84
|
+
/**
|
|
85
|
+
* Get all available tools from connected MCP servers.
|
|
86
|
+
*
|
|
87
|
+
* @returns Combined list of tools from all connected servers
|
|
88
|
+
*/
|
|
89
|
+
listTools(): Promise<MCPTool[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Invoke a tool on the appropriate MCP server.
|
|
92
|
+
* - Finds the server that provides the tool
|
|
93
|
+
* - Calls client.callTool({ name, arguments }) on the appropriate connection
|
|
94
|
+
* - Handles CallToolResult response
|
|
95
|
+
* - Checks isError flag for failures
|
|
96
|
+
* - Returns errors for calls to crashed server
|
|
97
|
+
*
|
|
98
|
+
* @param name - The name of the tool to invoke
|
|
99
|
+
* @param args - The arguments to pass to the tool
|
|
100
|
+
* @param serverId - Optional server ID to call the tool on (if known)
|
|
101
|
+
* @returns The tool call result with content and error status
|
|
102
|
+
* @throws Error if tool is not found or server is not connected
|
|
103
|
+
*/
|
|
104
|
+
callTool(name: string, args: Record<string, unknown>, serverId?: string): Promise<MCPToolCallResult>;
|
|
105
|
+
/**
|
|
106
|
+
* Get all available resources from connected MCP servers.
|
|
107
|
+
* - Calls client.listResources() to discover available resources
|
|
108
|
+
* - Stores resource definitions (uri, name, description, mimeType)
|
|
109
|
+
* - Handles pagination via nextCursor if present
|
|
110
|
+
*
|
|
111
|
+
* @returns Combined list of resources from all connected servers
|
|
112
|
+
*/
|
|
113
|
+
listResources(): Promise<MCPResource[]>;
|
|
114
|
+
/**
|
|
115
|
+
* Read a resource from the appropriate MCP server.
|
|
116
|
+
* - Calls client.readResource({ uri }) on the appropriate connection
|
|
117
|
+
* - Handles TextResourceContents and BlobResourceContents
|
|
118
|
+
* - Determines which server handles the URI based on resource list
|
|
119
|
+
*
|
|
120
|
+
* @param uri - The URI of the resource to read
|
|
121
|
+
* @param serverId - Optional server ID to read from (if known)
|
|
122
|
+
* @returns The resource contents
|
|
123
|
+
* @throws Error if resource server is not found or not connected
|
|
124
|
+
*/
|
|
125
|
+
readResource(uri: string, serverId?: string): Promise<MCPResourceReadResult>;
|
|
126
|
+
/**
|
|
127
|
+
* Get a connection by server ID.
|
|
128
|
+
*
|
|
129
|
+
* @param serverId - The server ID to look up
|
|
130
|
+
* @returns The connection or undefined if not found
|
|
131
|
+
*/
|
|
132
|
+
getConnection(serverId: string): MCPConnection | undefined;
|
|
133
|
+
/**
|
|
134
|
+
* Get all active connections.
|
|
135
|
+
*
|
|
136
|
+
* @returns Array of all active connections
|
|
137
|
+
*/
|
|
138
|
+
getAllConnections(): MCPConnection[];
|
|
139
|
+
/**
|
|
140
|
+
* Get server capabilities for a specific server.
|
|
141
|
+
*
|
|
142
|
+
* @param serverId - The server ID to look up
|
|
143
|
+
* @returns The server capabilities or undefined if not found/connected
|
|
144
|
+
*/
|
|
145
|
+
getServerCapabilities(serverId: string): ServerCapabilities | undefined;
|
|
146
|
+
/**
|
|
147
|
+
* Close all MCP server connections.
|
|
148
|
+
*/
|
|
149
|
+
close(): Promise<void>;
|
|
150
|
+
/**
|
|
151
|
+
* Abort all pending MCP operations.
|
|
152
|
+
* Called when a session is cancelled to stop in-flight requests.
|
|
153
|
+
*/
|
|
154
|
+
abortPendingOperations(): void;
|
|
155
|
+
/**
|
|
156
|
+
* Check if a server has crashed.
|
|
157
|
+
*
|
|
158
|
+
* @param serverId - The server ID to check
|
|
159
|
+
* @returns True if the server has crashed
|
|
160
|
+
*/
|
|
161
|
+
isServerCrashed(serverId: string): boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Get the crash error for a server.
|
|
164
|
+
*
|
|
165
|
+
* @param serverId - The server ID to check
|
|
166
|
+
* @returns The crash error message or undefined if not crashed
|
|
167
|
+
*/
|
|
168
|
+
getServerCrashError(serverId: string): string | undefined;
|
|
169
|
+
/**
|
|
170
|
+
* Get all crashed servers.
|
|
171
|
+
*
|
|
172
|
+
* @returns Array of crashed server IDs with their error messages
|
|
173
|
+
*/
|
|
174
|
+
getCrashedServers(): Array<{
|
|
175
|
+
serverId: string;
|
|
176
|
+
error: string;
|
|
177
|
+
}>;
|
|
178
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for MCP client management.
|
|
5
|
+
*
|
|
6
|
+
* @module mcp/types
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for an MCP server connection.
|
|
10
|
+
* Matches the McpServerStdio type from ACP SDK.
|
|
11
|
+
*/
|
|
12
|
+
export interface MCPServerConfig {
|
|
13
|
+
/** Server identifier */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Command to spawn the server */
|
|
16
|
+
command: string;
|
|
17
|
+
/** Arguments for the command */
|
|
18
|
+
args?: string[];
|
|
19
|
+
/** Environment variables for the server process */
|
|
20
|
+
env?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Represents an MCP tool definition.
|
|
24
|
+
*/
|
|
25
|
+
export interface MCPTool {
|
|
26
|
+
/** Tool name */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Tool description */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** JSON Schema for tool input */
|
|
31
|
+
inputSchema: Record<string, unknown>;
|
|
32
|
+
/** Server ID that provides this tool */
|
|
33
|
+
serverId: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Represents an MCP resource definition.
|
|
37
|
+
*/
|
|
38
|
+
export interface MCPResource {
|
|
39
|
+
/** Resource URI */
|
|
40
|
+
uri: string;
|
|
41
|
+
/** Resource name */
|
|
42
|
+
name: string;
|
|
43
|
+
/** Resource description */
|
|
44
|
+
description?: string;
|
|
45
|
+
/** MIME type */
|
|
46
|
+
mimeType?: string;
|
|
47
|
+
/** Server ID that provides this resource */
|
|
48
|
+
serverId: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Content types that can be returned from a tool call.
|
|
52
|
+
* Matches MCP SDK content types.
|
|
53
|
+
*/
|
|
54
|
+
export interface MCPTextContent {
|
|
55
|
+
type: 'text';
|
|
56
|
+
text: string;
|
|
57
|
+
}
|
|
58
|
+
export interface MCPImageContent {
|
|
59
|
+
type: 'image';
|
|
60
|
+
data: string;
|
|
61
|
+
mimeType: string;
|
|
62
|
+
}
|
|
63
|
+
export interface MCPEmbeddedResource {
|
|
64
|
+
type: 'resource';
|
|
65
|
+
resource: {
|
|
66
|
+
uri: string;
|
|
67
|
+
mimeType?: string;
|
|
68
|
+
text?: string;
|
|
69
|
+
blob?: string;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export type MCPContent = MCPTextContent | MCPImageContent | MCPEmbeddedResource;
|
|
73
|
+
/**
|
|
74
|
+
* Result of a tool call.
|
|
75
|
+
*/
|
|
76
|
+
export interface MCPToolCallResult {
|
|
77
|
+
/** Content blocks returned by the tool */
|
|
78
|
+
content: MCPContent[];
|
|
79
|
+
/** Whether the tool execution resulted in an error */
|
|
80
|
+
isError?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Text resource contents from MCP server.
|
|
84
|
+
*/
|
|
85
|
+
export interface MCPTextResourceContents {
|
|
86
|
+
/** Resource URI */
|
|
87
|
+
uri: string;
|
|
88
|
+
/** MIME type */
|
|
89
|
+
mimeType?: string;
|
|
90
|
+
/** Text content */
|
|
91
|
+
text: string;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Blob resource contents from MCP server.
|
|
95
|
+
*/
|
|
96
|
+
export interface MCPBlobResourceContents {
|
|
97
|
+
/** Resource URI */
|
|
98
|
+
uri: string;
|
|
99
|
+
/** MIME type */
|
|
100
|
+
mimeType?: string;
|
|
101
|
+
/** Base64-encoded blob data */
|
|
102
|
+
blob: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Resource contents returned from readResource.
|
|
106
|
+
*/
|
|
107
|
+
export type MCPResourceContents = MCPTextResourceContents | MCPBlobResourceContents;
|
|
108
|
+
/**
|
|
109
|
+
* Result of reading a resource.
|
|
110
|
+
*/
|
|
111
|
+
export interface MCPResourceReadResult {
|
|
112
|
+
/** Array of resource contents (usually one, but can be multiple) */
|
|
113
|
+
contents: MCPResourceContents[];
|
|
114
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ACPNotification, ACPRequest, ACPResponse, ProxyConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* TCP connection handler with NDJSON streaming.
|
|
4
|
+
*
|
|
5
|
+
* Manages the TCP connection to stdio Bus, handling:
|
|
6
|
+
* - Connection establishment and lifecycle
|
|
7
|
+
* - NDJSON buffering and line parsing
|
|
8
|
+
* - Sending ACP requests
|
|
9
|
+
* - Receiving ACP responses and notifications
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* const connection = new ACPConnection(
|
|
14
|
+
* config,
|
|
15
|
+
* (msg) => console.log('Received:', msg),
|
|
16
|
+
* (err) => console.error('Error:', err)
|
|
17
|
+
* );
|
|
18
|
+
*
|
|
19
|
+
* connection.send({
|
|
20
|
+
* jsonrpc: '2.0',
|
|
21
|
+
* id: 1,
|
|
22
|
+
* method: 'initialize',
|
|
23
|
+
* agentId: 'my-agent',
|
|
24
|
+
* sessionId: 'session-123',
|
|
25
|
+
* params: {}
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class ACPConnection {
|
|
30
|
+
private config;
|
|
31
|
+
private onMessage;
|
|
32
|
+
private onError;
|
|
33
|
+
private socket;
|
|
34
|
+
private buffer;
|
|
35
|
+
private connected;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new ACP connection.
|
|
38
|
+
*
|
|
39
|
+
* @param config - Proxy configuration with host and port
|
|
40
|
+
* @param onMessage - Callback for received ACP messages (responses or notifications)
|
|
41
|
+
* @param onError - Callback for connection errors
|
|
42
|
+
*/
|
|
43
|
+
constructor(config: ProxyConfig, onMessage: (msg: ACPResponse | ACPNotification) => void, onError: (err: Error) => void);
|
|
44
|
+
/**
|
|
45
|
+
* Setup event handlers for the TCP socket.
|
|
46
|
+
*
|
|
47
|
+
* Handles connect, error, data, and close events.
|
|
48
|
+
*/
|
|
49
|
+
private setupHandlers;
|
|
50
|
+
/**
|
|
51
|
+
* Buffer and parse NDJSON lines from incoming data.
|
|
52
|
+
*
|
|
53
|
+
* Accumulates data in a buffer and processes complete lines (ending with \n).
|
|
54
|
+
* Incomplete lines remain in the buffer until more data arrives.
|
|
55
|
+
*
|
|
56
|
+
* @param data - Raw data received from the socket
|
|
57
|
+
*/
|
|
58
|
+
private handleData;
|
|
59
|
+
/**
|
|
60
|
+
* Send an ACP request as NDJSON.
|
|
61
|
+
*
|
|
62
|
+
* Serializes the request to JSON and appends a newline character.
|
|
63
|
+
* Logs the request to stderr for debugging.
|
|
64
|
+
*
|
|
65
|
+
* @param request - ACP request to send
|
|
66
|
+
*/
|
|
67
|
+
send(request: ACPRequest): void;
|
|
68
|
+
/**
|
|
69
|
+
* Close the connection gracefully.
|
|
70
|
+
*
|
|
71
|
+
* Ends the socket connection, allowing any pending writes to complete.
|
|
72
|
+
*/
|
|
73
|
+
close(): void;
|
|
74
|
+
/**
|
|
75
|
+
* Check if the connection is currently established.
|
|
76
|
+
*
|
|
77
|
+
* @returns true if connected, false otherwise
|
|
78
|
+
*/
|
|
79
|
+
isConnected(): boolean;
|
|
80
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol conversion logic for the MCP-ACP protocol proxy.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the ProtocolConverter class which handles bidirectional
|
|
5
|
+
* conversion between Model Context Protocol (MCP) and Agent Client Protocol (ACP).
|
|
6
|
+
*
|
|
7
|
+
* The converter:
|
|
8
|
+
* - Converts MCP requests to ACP requests
|
|
9
|
+
* - Converts ACP responses back to MCP responses
|
|
10
|
+
* - Handles ACP notifications (e.g., streaming text chunks)
|
|
11
|
+
* - Manages session creation and request queuing
|
|
12
|
+
*/
|
|
13
|
+
import { ACPNotification, ACPRequest, ACPResponse, MCPRequest, MCPResponse, ProxyConfig } from './types.js';
|
|
14
|
+
import { StateManager } from './state.js';
|
|
15
|
+
/**
|
|
16
|
+
* Protocol converter for MCP ↔ ACP translation.
|
|
17
|
+
*
|
|
18
|
+
* Handles all protocol conversion logic, including:
|
|
19
|
+
* - MCP method routing (initialize, tools/list, tools/call, etc.)
|
|
20
|
+
* - ACP response conversion based on pending request method
|
|
21
|
+
* - Session creation and queuing for tools/call without session
|
|
22
|
+
* - Text accumulation for streaming responses
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const config = { acpHost: '127.0.0.1', acpPort: 9011, agentId: 'my-agent' };
|
|
27
|
+
* const state = new StateManager();
|
|
28
|
+
* const converter = new ProtocolConverter(config, state);
|
|
29
|
+
*
|
|
30
|
+
* const mcpReq = { jsonrpc: '2.0', id: 1, method: 'tools/list' };
|
|
31
|
+
* const acpReq = converter.convertMCPtoACP(mcpReq);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class ProtocolConverter {
|
|
35
|
+
private config;
|
|
36
|
+
private state;
|
|
37
|
+
private sendACPCallback?;
|
|
38
|
+
constructor(config: ProxyConfig, state: StateManager, sendACPCallback?: ((request: ACPRequest) => void) | undefined);
|
|
39
|
+
/**
|
|
40
|
+
* Convert MCP request to ACP request.
|
|
41
|
+
*
|
|
42
|
+
* Routes MCP methods to appropriate conversion handlers. Some methods
|
|
43
|
+
* (like tools/list) return null because they're handled directly without
|
|
44
|
+
* forwarding to ACP.
|
|
45
|
+
*
|
|
46
|
+
* @param mcpReq - The MCP request to convert
|
|
47
|
+
* @returns ACP request to send, or null if response should be sent directly to MCP client
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const mcpReq = { jsonrpc: '2.0', id: 1, method: 'initialize', params: {} };
|
|
52
|
+
* const acpReq = converter.convertMCPtoACP(mcpReq);
|
|
53
|
+
* // Returns ACP initialize request
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
convertMCPtoACP(mcpReq: MCPRequest): ACPRequest | null;
|
|
57
|
+
/**
|
|
58
|
+
* Convert ACP response to MCP response.
|
|
59
|
+
*
|
|
60
|
+
* Looks up the pending request to determine how to convert the response.
|
|
61
|
+
* Different ACP methods require different conversion logic.
|
|
62
|
+
*
|
|
63
|
+
* @param acpResp - The ACP response to convert
|
|
64
|
+
* @returns MCP response to send, or null if no response should be sent
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const acpResp = { jsonrpc: '2.0', id: 1, result: { agentInfo: {...} } };
|
|
69
|
+
* const mcpResp = converter.convertACPtoMCP(acpResp);
|
|
70
|
+
* // Returns MCP initialize response
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
convertACPtoMCP(acpResp: ACPResponse): MCPResponse | null;
|
|
74
|
+
/**
|
|
75
|
+
* Handle ACP notifications (messages without id field).
|
|
76
|
+
*
|
|
77
|
+
* Processes notifications like session/update which contain streaming
|
|
78
|
+
* text chunks from the agent.
|
|
79
|
+
*
|
|
80
|
+
* @param notification - The ACP notification to handle
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const notification = {
|
|
85
|
+
* jsonrpc: '2.0',
|
|
86
|
+
* method: 'session/update',
|
|
87
|
+
* params: { update: { sessionUpdate: 'agent_message_chunk', content: { text: 'Hello' } } }
|
|
88
|
+
* };
|
|
89
|
+
* converter.handleACPNotification(notification);
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
handleACPNotification(notification: ACPNotification): void;
|
|
93
|
+
/**
|
|
94
|
+
* Convert MCP initialize request to ACP initialize request.
|
|
95
|
+
*/
|
|
96
|
+
private convertInitialize;
|
|
97
|
+
/**
|
|
98
|
+
* Handle MCP tools/list request.
|
|
99
|
+
* Returns static tool list directly to MCP client without forwarding to ACP.
|
|
100
|
+
*/
|
|
101
|
+
private handleToolsList;
|
|
102
|
+
/**
|
|
103
|
+
* Convert MCP tools/call request to ACP session/prompt request.
|
|
104
|
+
* If no ACP session exists, creates session/new request first and queues the prompt.
|
|
105
|
+
*/
|
|
106
|
+
private convertToolsCall;
|
|
107
|
+
/**
|
|
108
|
+
* Handle MCP resources/list request.
|
|
109
|
+
* Returns empty resources array directly to MCP client.
|
|
110
|
+
*/
|
|
111
|
+
private handleResourcesList;
|
|
112
|
+
/**
|
|
113
|
+
* Handle MCP resources/templates/list request.
|
|
114
|
+
* Returns empty resource templates array directly to MCP client.
|
|
115
|
+
*/
|
|
116
|
+
private handleResourceTemplatesList;
|
|
117
|
+
/**
|
|
118
|
+
* Handle MCP prompts/list request.
|
|
119
|
+
* Returns empty prompts array directly to MCP client.
|
|
120
|
+
*/
|
|
121
|
+
private handlePromptsList;
|
|
122
|
+
/**
|
|
123
|
+
* Handle unknown MCP method.
|
|
124
|
+
* Returns JSON-RPC error -32601 (method not found).
|
|
125
|
+
*/
|
|
126
|
+
private handleUnknownMethod;
|
|
127
|
+
/**
|
|
128
|
+
* Convert ACP initialize response to MCP initialize response.
|
|
129
|
+
*/
|
|
130
|
+
private convertInitializeResponse;
|
|
131
|
+
/**
|
|
132
|
+
* Handle ACP session/new response.
|
|
133
|
+
* Stores the ACP session ID and sends queued prompt if exists.
|
|
134
|
+
*/
|
|
135
|
+
private handleSessionNewResponse;
|
|
136
|
+
/**
|
|
137
|
+
* Convert ACP session/prompt response to MCP tool call result.
|
|
138
|
+
* Returns accumulated text from streaming notifications.
|
|
139
|
+
*/
|
|
140
|
+
private convertSessionPromptResponse;
|
|
141
|
+
/**
|
|
142
|
+
* Handle session/update notification.
|
|
143
|
+
* Accumulates text chunks for agent_message_chunk updates.
|
|
144
|
+
*/
|
|
145
|
+
private handleSessionUpdate;
|
|
146
|
+
/**
|
|
147
|
+
* Send MCP response directly to stdout.
|
|
148
|
+
* Used for methods that don't require ACP forwarding.
|
|
149
|
+
*/
|
|
150
|
+
private sendMCPDirect;
|
|
151
|
+
/**
|
|
152
|
+
* Send ACP request directly to TCP socket.
|
|
153
|
+
* Used for queued requests (session/new -> session/prompt).
|
|
154
|
+
*/
|
|
155
|
+
private sendACPDirect;
|
|
156
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session state management for the MCP-ACP protocol proxy.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the StateManager class which manages session identifiers,
|
|
5
|
+
* pending request tracking, and text accumulation for streaming responses.
|
|
6
|
+
*/
|
|
7
|
+
import { PendingRequest } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Manages session state for the MCP-ACP proxy.
|
|
10
|
+
*
|
|
11
|
+
* Tracks proxy session ID, ACP session ID, pending requests,
|
|
12
|
+
* and accumulated text for streaming responses.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const state = new StateManager();
|
|
17
|
+
* const sessionId = state.ensureProxySessionId();
|
|
18
|
+
* state.addPendingRequest(1, { method: 'initialize', params: {} });
|
|
19
|
+
* const pending = state.takePendingRequest(1);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare class StateManager {
|
|
23
|
+
private state;
|
|
24
|
+
constructor();
|
|
25
|
+
/**
|
|
26
|
+
* Generate unique proxy session ID on first request.
|
|
27
|
+
*
|
|
28
|
+
* The proxy session ID is used for stdio Bus routing to ensure all
|
|
29
|
+
* requests from this proxy instance are routed to the same worker.
|
|
30
|
+
*
|
|
31
|
+
* @returns The proxy session ID (generates new one if not exists)
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const sessionId = state.ensureProxySessionId();
|
|
36
|
+
* // First call: 'proxy-1234567890'
|
|
37
|
+
* const sameId = state.ensureProxySessionId();
|
|
38
|
+
* // Subsequent calls: 'proxy-1234567890' (same value)
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
ensureProxySessionId(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Store ACP session ID from session/new response.
|
|
44
|
+
*
|
|
45
|
+
* The ACP session ID is received from the agent and used for subsequent
|
|
46
|
+
* session-specific requests like session/prompt.
|
|
47
|
+
*
|
|
48
|
+
* @param sessionId - The session ID from the ACP agent
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* state.setAcpSessionId('session-abc123');
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
setAcpSessionId(sessionId: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Get current ACP session ID.
|
|
58
|
+
*
|
|
59
|
+
* @returns The ACP session ID, or null if no session has been created yet
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const sessionId = state.getAcpSessionId();
|
|
64
|
+
* if (sessionId) {
|
|
65
|
+
* // Can send session/prompt requests
|
|
66
|
+
* } else {
|
|
67
|
+
* // Need to create session first
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
getAcpSessionId(): string | null;
|
|
72
|
+
/**
|
|
73
|
+
* Track a pending request.
|
|
74
|
+
*
|
|
75
|
+
* Stores request information keyed by request ID for later correlation
|
|
76
|
+
* with responses. Used to track method, parameters, and queued requests.
|
|
77
|
+
*
|
|
78
|
+
* @param id - The request ID (string or number)
|
|
79
|
+
* @param request - The pending request information
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* state.addPendingRequest(1, {
|
|
84
|
+
* method: 'session/prompt',
|
|
85
|
+
* params: { prompt: 'Hello' }
|
|
86
|
+
* });
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
addPendingRequest(id: string | number, request: PendingRequest): void;
|
|
90
|
+
/**
|
|
91
|
+
* Retrieve and remove a pending request.
|
|
92
|
+
*
|
|
93
|
+
* Looks up a pending request by ID and removes it from the map.
|
|
94
|
+
* Returns undefined if no request with that ID exists.
|
|
95
|
+
*
|
|
96
|
+
* @param id - The request ID to look up
|
|
97
|
+
* @returns The pending request information, or undefined if not found
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const pending = state.takePendingRequest(1);
|
|
102
|
+
* if (pending) {
|
|
103
|
+
* console.log(`Received response for ${pending.method}`);
|
|
104
|
+
* }
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
takePendingRequest(id: string | number): PendingRequest | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Accumulate text for streaming responses.
|
|
110
|
+
*
|
|
111
|
+
* Appends text chunks to the accumulated string for a given request ID.
|
|
112
|
+
* Used to collect agent_message_chunk notifications during session/prompt.
|
|
113
|
+
*
|
|
114
|
+
* @param id - The request ID
|
|
115
|
+
* @param text - The text chunk to append
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* state.accumulateText(1, 'Hello ');
|
|
120
|
+
* state.accumulateText(1, 'world!');
|
|
121
|
+
* const result = state.takeAccumulatedText(1);
|
|
122
|
+
* // result: 'Hello world!'
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
accumulateText(id: string | number, text: string): void;
|
|
126
|
+
/**
|
|
127
|
+
* Retrieve and clear accumulated text.
|
|
128
|
+
*
|
|
129
|
+
* Returns the accumulated text for a request ID and removes it from the map.
|
|
130
|
+
* Returns empty string if no text has been accumulated.
|
|
131
|
+
*
|
|
132
|
+
* @param id - The request ID
|
|
133
|
+
* @returns The accumulated text (empty string if none)
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* state.accumulateText(1, 'Hello ');
|
|
138
|
+
* state.accumulateText(1, 'world!');
|
|
139
|
+
* const text = state.takeAccumulatedText(1);
|
|
140
|
+
* // text: 'Hello world!'
|
|
141
|
+
* const again = state.takeAccumulatedText(1);
|
|
142
|
+
* // again: '' (cleared after first take)
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
takeAccumulatedText(id: string | number): string;
|
|
146
|
+
/**
|
|
147
|
+
* Find pending session/prompt request for notification handling.
|
|
148
|
+
*
|
|
149
|
+
* Searches through pending requests to find a session/prompt request.
|
|
150
|
+
* Used when processing session/update notifications to determine which
|
|
151
|
+
* request the notification belongs to.
|
|
152
|
+
*
|
|
153
|
+
* @returns Tuple of [requestId, pendingRequest] or null if not found
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* const result = state.findPendingPromptRequest();
|
|
158
|
+
* if (result) {
|
|
159
|
+
* const [id, pending] = result;
|
|
160
|
+
* state.accumulateText(id, 'chunk text');
|
|
161
|
+
* }
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
findPendingPromptRequest(): [string | number, PendingRequest] | null;
|
|
165
|
+
}
|