@thinkwell/acp 0.5.4 → 0.5.6

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.
@@ -1,183 +1,139 @@
1
- /**
2
- * Handler for MCP-over-ACP protocol messages.
3
- *
4
- * This class manages the lifecycle of MCP connections tunneled through ACP:
5
- * - mcp/connect: Establishes a new MCP connection
6
- * - mcp/message: Routes MCP requests to the appropriate server
7
- * - mcp/disconnect: Tears down an MCP connection
8
- *
9
- * Note: The ACP SDK strips the underscore prefix from extension methods,
10
- * so we receive "mcp/connect" even though the wire format is "_mcp/connect".
11
- */
12
1
  export class McpOverAcpHandler {
13
- /** Maps acp:uuid URLs to registered MCP servers */
14
- _serversByUrl = new Map();
15
- /** Maps connection IDs to active connections */
16
- _connections = new Map();
17
- /** Current session ID for context */
18
- _sessionId = "";
19
- /** Maps session IDs to pending tools discovery promises */
20
- _toolsDiscoveryBySession = new Map();
21
- /**
22
- * Register an MCP server to handle requests for its acp: URL
23
- */
24
- register(server) {
25
- this._serversByUrl.set(server.acpUrl, server);
26
- }
27
- /**
28
- * Unregister an MCP server
29
- */
30
- unregister(server) {
31
- this._serversByUrl.delete(server.acpUrl);
32
- }
33
- /**
34
- * Set the current session ID for context
35
- */
36
- setSessionId(sessionId) {
37
- this._sessionId = sessionId;
38
- }
39
- /**
40
- * Handle an incoming mcp/connect request
41
- */
42
- handleConnect(params) {
43
- // The protocol uses "acp_url" as the parameter name
44
- // Generate connectionId if not provided by conductor
45
- const connectionId = params.connectionId ?? `conn-${Date.now()}-${Math.random().toString(36).slice(2)}`;
46
- const url = (params.acp_url ?? params.url);
47
- const server = this._serversByUrl.get(url);
48
- if (!server) {
49
- throw new Error(`No MCP server registered for URL: ${url}`);
50
- }
51
- // Store the connection
52
- this._connections.set(connectionId, {
53
- connectionId,
54
- server,
55
- sessionId: this._sessionId,
56
- });
57
- // Include tool definitions in the connect response
58
- // The conductor bridge may use this to provide tool info to the agent
59
- const tools = server.getToolDefinitions();
60
- // Return response with snake_case field names to match the Rust conductor's expectations
61
- // Note: The conductor only requires connection_id, but we include extra info for potential use
62
- return {
63
- connection_id: connectionId,
64
- connectionId, // Also include camelCase for backwards compatibility
65
- serverInfo: {
66
- name: server.name,
67
- version: "0.1.0",
68
- },
69
- capabilities: {
70
- tools: {},
71
- },
72
- // Include tools directly - the bridge may forward this to the agent
73
- tools,
74
- };
75
- }
76
- /**
77
- * Handle an incoming mcp/message request.
78
- *
79
- * IMPORTANT: The response to _mcp/message is just the raw MCP result,
80
- * NOT wrapped in {connectionId, result}. The conductor expects the raw
81
- * MCP response (e.g., InitializeResult, ToolsListResult) directly.
82
- */
83
- async handleMessage(params) {
84
- const connectionId = params.connectionId;
85
- const method = params.method;
86
- const mcpParams = params.params;
87
- const connection = this._connections.get(connectionId);
88
- if (!connection) {
89
- // Return MCP-style error for unknown connection
90
- throw new Error(`Unknown connection: ${connectionId}`);
91
- }
92
- // If this is a tools/list request, resolve any pending tools discovery promise
93
- if (method === "tools/list") {
94
- this._resolveToolsDiscovery(connection.sessionId);
95
- }
96
- const context = {
97
- connectionId,
98
- sessionId: connection.sessionId,
99
- };
100
- // Return the raw MCP result - the conductor will wrap it appropriately
101
- return await connection.server.handleMethod(method, mcpParams, context);
102
- }
103
- /**
104
- * Wait for the agent to discover tools via tools/list.
105
- *
106
- * This is used to avoid a race condition where the client sends a prompt
107
- * before the agent has finished MCP initialization. The promise resolves
108
- * when tools/list is called or when the timeout expires.
109
- *
110
- * @param sessionId - The session to wait for
111
- * @param timeout - Maximum time to wait in milliseconds (default: 2000ms)
112
- */
113
- waitForToolsDiscovery(sessionId, timeout = 2000) {
114
- // If there's already a pending promise for this session, return it
115
- const existing = this._toolsDiscoveryBySession.get(sessionId);
116
- if (existing) {
117
- return new Promise((resolve) => {
118
- const originalResolve = existing.resolve;
119
- existing.resolve = () => {
120
- originalResolve();
121
- resolve();
122
- };
123
- });
124
- }
125
- return new Promise((resolve) => {
126
- const state = {
127
- resolve: () => {
128
- if (state.timeoutId) {
129
- clearTimeout(state.timeoutId);
130
- }
131
- this._toolsDiscoveryBySession.delete(sessionId);
132
- resolve();
133
- },
134
- timeoutId: setTimeout(() => {
135
- state.timeoutId = null;
136
- state.resolve();
137
- }, timeout),
138
- };
139
- this._toolsDiscoveryBySession.set(sessionId, state);
140
- });
141
- }
142
- /**
143
- * Resolve the tools discovery promise for a session
144
- */
145
- _resolveToolsDiscovery(sessionId) {
146
- const state = this._toolsDiscoveryBySession.get(sessionId);
147
- if (state) {
148
- state.resolve();
149
- }
150
- }
151
- /**
152
- * Handle an incoming mcp/disconnect notification
153
- */
154
- handleDisconnect(params) {
155
- const connectionId = params.connectionId;
156
- this._connections.delete(connectionId);
157
- }
158
- /**
159
- * Check if this is an MCP-over-ACP request.
160
- * Note: The ACP SDK strips the underscore prefix, so we check for "mcp/".
161
- */
162
- isMcpRequest(method) {
163
- return method.startsWith("mcp/");
164
- }
165
- /**
166
- * Route an MCP-over-ACP request to the appropriate handler.
167
- * Note: Methods arrive without the underscore prefix (e.g., "mcp/connect" not "_mcp/connect").
168
- */
169
- async routeRequest(method, params) {
170
- switch (method) {
171
- case "mcp/connect":
172
- return this.handleConnect(params);
173
- case "mcp/message":
174
- return this.handleMessage(params);
175
- case "mcp/disconnect":
176
- this.handleDisconnect(params);
177
- return undefined;
178
- default:
179
- throw new Error(`Unknown MCP-over-ACP method: ${method}`);
180
- }
2
+ /** Maps acp:uuid URLs to registered MCP servers */
3
+ _serversByUrl = /* @__PURE__ */ new Map();
4
+ /** Maps connection IDs to active connections */
5
+ _connections = /* @__PURE__ */ new Map();
6
+ /** Current session ID for context */
7
+ _sessionId = "";
8
+ /** Maps session IDs to pending tools discovery promises */
9
+ _toolsDiscoveryBySession = /* @__PURE__ */ new Map();
10
+ /**
11
+ * Register an MCP server to handle requests for its acp: URL
12
+ */
13
+ register(server) {
14
+ this._serversByUrl.set(server.acpUrl, server);
15
+ }
16
+ /**
17
+ * Unregister an MCP server
18
+ */
19
+ unregister(server) {
20
+ this._serversByUrl.delete(server.acpUrl);
21
+ }
22
+ /**
23
+ * Set the current session ID for context
24
+ */
25
+ setSessionId(sessionId) {
26
+ this._sessionId = sessionId;
27
+ }
28
+ /**
29
+ * Handle an incoming mcp/connect request
30
+ */
31
+ handleConnect(params) {
32
+ const connectionId = params.connectionId ?? `conn-${Date.now()}-${Math.random().toString(36).slice(2)}`, url = params.acp_url ?? params.url, server = this._serversByUrl.get(url);
33
+ if (!server)
34
+ throw new Error(`No MCP server registered for URL: ${url}`);
35
+ this._connections.set(connectionId, {
36
+ connectionId,
37
+ server,
38
+ sessionId: this._sessionId
39
+ });
40
+ const tools = server.getToolDefinitions();
41
+ return {
42
+ connection_id: connectionId,
43
+ connectionId,
44
+ // Also include camelCase for backwards compatibility
45
+ serverInfo: {
46
+ name: server.name,
47
+ version: "0.1.0"
48
+ },
49
+ capabilities: {
50
+ tools: {}
51
+ },
52
+ // Include tools directly - the bridge may forward this to the agent
53
+ tools
54
+ };
55
+ }
56
+ /**
57
+ * Handle an incoming mcp/message request.
58
+ *
59
+ * IMPORTANT: The response to _mcp/message is just the raw MCP result,
60
+ * NOT wrapped in {connectionId, result}. The conductor expects the raw
61
+ * MCP response (e.g., InitializeResult, ToolsListResult) directly.
62
+ */
63
+ async handleMessage(params) {
64
+ const connectionId = params.connectionId, method = params.method, mcpParams = params.params, connection = this._connections.get(connectionId);
65
+ if (!connection)
66
+ throw new Error(`Unknown connection: ${connectionId}`);
67
+ method === "tools/list" && this._resolveToolsDiscovery(connection.sessionId);
68
+ const context = {
69
+ connectionId,
70
+ sessionId: connection.sessionId
71
+ };
72
+ return await connection.server.handleMethod(method, mcpParams, context);
73
+ }
74
+ /**
75
+ * Wait for the agent to discover tools via tools/list.
76
+ *
77
+ * This is used to avoid a race condition where the client sends a prompt
78
+ * before the agent has finished MCP initialization. The promise resolves
79
+ * when tools/list is called or when the timeout expires.
80
+ *
81
+ * @param sessionId - The session to wait for
82
+ * @param timeout - Maximum time to wait in milliseconds (default: 2000ms)
83
+ */
84
+ waitForToolsDiscovery(sessionId, timeout = 2e3) {
85
+ const existing = this._toolsDiscoveryBySession.get(sessionId);
86
+ return existing ? new Promise((resolve) => {
87
+ const originalResolve = existing.resolve;
88
+ existing.resolve = () => {
89
+ originalResolve(), resolve();
90
+ };
91
+ }) : new Promise((resolve) => {
92
+ const state = {
93
+ resolve: () => {
94
+ state.timeoutId && clearTimeout(state.timeoutId), this._toolsDiscoveryBySession.delete(sessionId), resolve();
95
+ },
96
+ timeoutId: setTimeout(() => {
97
+ state.timeoutId = null, state.resolve();
98
+ }, timeout)
99
+ };
100
+ this._toolsDiscoveryBySession.set(sessionId, state);
101
+ });
102
+ }
103
+ /**
104
+ * Resolve the tools discovery promise for a session
105
+ */
106
+ _resolveToolsDiscovery(sessionId) {
107
+ const state = this._toolsDiscoveryBySession.get(sessionId);
108
+ state && state.resolve();
109
+ }
110
+ /**
111
+ * Handle an incoming mcp/disconnect notification
112
+ */
113
+ handleDisconnect(params) {
114
+ const connectionId = params.connectionId;
115
+ this._connections.delete(connectionId);
116
+ }
117
+ /**
118
+ * Check if this is an MCP-over-ACP request.
119
+ */
120
+ isMcpRequest(method) {
121
+ return method.startsWith("_mcp/");
122
+ }
123
+ /**
124
+ * Route an MCP-over-ACP request to the appropriate handler.
125
+ */
126
+ async routeRequest(method, params) {
127
+ switch (method) {
128
+ case "_mcp/connect":
129
+ return this.handleConnect(params);
130
+ case "_mcp/message":
131
+ return this.handleMessage(params);
132
+ case "_mcp/disconnect":
133
+ this.handleDisconnect(params);
134
+ return;
135
+ default:
136
+ throw new Error(`Unknown MCP-over-ACP method: ${method}`);
181
137
  }
138
+ }
182
139
  }
183
- //# sourceMappingURL=mcp-over-acp-handler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-over-acp-handler.js","sourceRoot":"","sources":["../src/mcp-over-acp-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mcp-over-acp-handler.js","sourceRoot":"","sources":["../src/mcp-over-acp-handler.ts"],"names":[],"mappings":"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"}
@@ -1,152 +1,128 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
- /**
3
- * Fluent builder for creating MCP servers with registered tools
4
- */
5
2
  export class McpServerBuilder {
6
- _name;
7
- _instructions;
8
- _tools = new Map();
9
- constructor(name) {
10
- this._name = name;
11
- }
12
- /**
13
- * Set instructions for the MCP server
14
- */
15
- instructions(text) {
16
- this._instructions = text;
17
- return this;
18
- }
19
- /**
20
- * Register a tool with input/output JSON schemas
21
- */
22
- tool(name, description, inputSchema, outputSchema, handler) {
23
- this._tools.set(name, {
24
- name,
25
- description,
26
- inputSchema,
27
- outputSchema,
28
- handler: handler,
29
- });
30
- return this;
31
- }
32
- /**
33
- * Build the MCP server
34
- */
35
- build() {
36
- return new McpServer(this._name, this._instructions, new Map(this._tools));
37
- }
3
+ _name;
4
+ _instructions;
5
+ _tools = /* @__PURE__ */ new Map();
6
+ constructor(name) {
7
+ this._name = name;
8
+ }
9
+ /**
10
+ * Set instructions for the MCP server
11
+ */
12
+ instructions(text) {
13
+ return this._instructions = text, this;
14
+ }
15
+ /**
16
+ * Register a tool with input/output JSON schemas
17
+ */
18
+ tool(name, description, inputSchema, outputSchema, handler) {
19
+ return this._tools.set(name, {
20
+ name,
21
+ description,
22
+ inputSchema,
23
+ outputSchema,
24
+ handler
25
+ }), this;
26
+ }
27
+ /**
28
+ * Build the MCP server
29
+ */
30
+ build() {
31
+ return new McpServer(this._name, this._instructions, new Map(this._tools));
32
+ }
38
33
  }
39
- /**
40
- * MCP server that handles tool calls via MCP-over-ACP
41
- */
42
34
  export class McpServer {
43
- id;
44
- name;
45
- _instructions;
46
- _tools;
47
- constructor(name, instructions, tools) {
48
- this.id = uuidv4();
49
- this.name = name;
50
- this._instructions = instructions;
51
- this._tools = tools;
52
- }
53
- /**
54
- * Get the acp: URL for this server
55
- */
56
- get acpUrl() {
57
- return `acp:${this.id}`;
58
- }
59
- /**
60
- * Get MCP server config for session requests
61
- */
62
- toSessionConfig() {
63
- return {
64
- type: "http",
65
- name: this.name,
66
- url: this.acpUrl,
67
- };
68
- }
69
- /**
70
- * Get the list of tool definitions for tools/list
71
- */
72
- getToolDefinitions() {
73
- return Array.from(this._tools.values()).map((tool) => ({
74
- name: tool.name,
75
- description: tool.description,
76
- inputSchema: tool.inputSchema,
77
- }));
78
- }
79
- /**
80
- * Handle an MCP method call or notification
81
- */
82
- async handleMethod(method, params, context) {
83
- switch (method) {
84
- case "tools/list":
85
- return this.handleToolsList();
86
- case "tools/call":
87
- return this.handleToolsCall(params, context);
88
- case "initialize":
89
- return this.handleInitialize(params);
90
- case "notifications/initialized":
91
- // Client notification after initialize - no response needed
92
- return undefined;
93
- default:
94
- throw new Error(`Unknown MCP method: ${method}`);
95
- }
96
- }
97
- handleInitialize(params) {
98
- const instructions = this._instructions ?? "You have access to tools. Call return_result when done.";
99
- // Include tools directly in initialize response - some clients expect this
100
- // instead of calling tools/list separately
101
- const tools = this.getToolDefinitions();
102
- // Echo back the client's protocol version if provided, otherwise use a known good version
103
- const clientVersion = params?.protocolVersion ?? "2024-11-05";
104
- return {
105
- protocolVersion: clientVersion,
106
- serverInfo: {
107
- name: this.name,
108
- version: "0.1.0",
109
- },
110
- capabilities: {
111
- tools: {},
112
- },
113
- instructions,
114
- tools, // Include tools directly in initialize response
115
- };
116
- }
117
- handleToolsList() {
118
- return {
119
- tools: this.getToolDefinitions(),
120
- };
35
+ id;
36
+ name;
37
+ _instructions;
38
+ _tools;
39
+ constructor(name, instructions, tools) {
40
+ this.id = uuidv4(), this.name = name, this._instructions = instructions, this._tools = tools;
41
+ }
42
+ /**
43
+ * Get the acp: URL for this server
44
+ */
45
+ get acpUrl() {
46
+ return `acp:${this.id}`;
47
+ }
48
+ /**
49
+ * Get MCP server config for session requests
50
+ */
51
+ toSessionConfig() {
52
+ return {
53
+ type: "http",
54
+ name: this.name,
55
+ url: this.acpUrl
56
+ };
57
+ }
58
+ /**
59
+ * Get the list of tool definitions for tools/list
60
+ */
61
+ getToolDefinitions() {
62
+ return Array.from(this._tools.values()).map((tool) => ({
63
+ name: tool.name,
64
+ description: tool.description,
65
+ inputSchema: tool.inputSchema
66
+ }));
67
+ }
68
+ /**
69
+ * Handle an MCP method call or notification
70
+ */
71
+ async handleMethod(method, params, context) {
72
+ switch (method) {
73
+ case "tools/list":
74
+ return this.handleToolsList();
75
+ case "tools/call":
76
+ return this.handleToolsCall(params, context);
77
+ case "initialize":
78
+ return this.handleInitialize(params);
79
+ case "notifications/initialized":
80
+ return;
81
+ default:
82
+ throw new Error(`Unknown MCP method: ${method}`);
121
83
  }
122
- async handleToolsCall(params, context) {
123
- const tool = this._tools.get(params.name);
124
- if (!tool) {
125
- return {
126
- content: [{ type: "text", text: `Unknown tool: ${params.name}` }],
127
- isError: true,
128
- };
129
- }
130
- try {
131
- const result = await tool.handler(params.arguments, context);
132
- const resultText = typeof result === "string" ? result : JSON.stringify(result);
133
- return {
134
- content: [{ type: "text", text: resultText }],
135
- };
136
- }
137
- catch (error) {
138
- const message = error instanceof Error ? error.message : String(error);
139
- return {
140
- content: [{ type: "text", text: `Tool error: ${message}` }],
141
- isError: true,
142
- };
143
- }
84
+ }
85
+ handleInitialize(params) {
86
+ const instructions = this._instructions ?? "You have access to tools. Call return_result when done.", tools = this.getToolDefinitions();
87
+ return {
88
+ protocolVersion: params?.protocolVersion ?? "2024-11-05",
89
+ serverInfo: {
90
+ name: this.name,
91
+ version: "0.1.0"
92
+ },
93
+ capabilities: {
94
+ tools: {}
95
+ },
96
+ instructions,
97
+ tools
98
+ // Include tools directly in initialize response
99
+ };
100
+ }
101
+ handleToolsList() {
102
+ return {
103
+ tools: this.getToolDefinitions()
104
+ };
105
+ }
106
+ async handleToolsCall(params, context) {
107
+ const tool = this._tools.get(params.name);
108
+ if (!tool)
109
+ return {
110
+ content: [{ type: "text", text: `Unknown tool: ${params.name}` }],
111
+ isError: !0
112
+ };
113
+ try {
114
+ const result = await tool.handler(params.arguments, context);
115
+ return {
116
+ content: [{ type: "text", text: typeof result == "string" ? result : JSON.stringify(result) }]
117
+ };
118
+ } catch (error) {
119
+ return {
120
+ content: [{ type: "text", text: `Tool error: ${error instanceof Error ? error.message : String(error)}` }],
121
+ isError: !0
122
+ };
144
123
  }
124
+ }
145
125
  }
146
- /**
147
- * Create a new MCP server builder
148
- */
149
126
  export function mcpServer(name) {
150
- return new McpServerBuilder(name);
127
+ return new McpServerBuilder(name);
151
128
  }
152
- //# sourceMappingURL=mcp-server.js.map