@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.
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +184 -263
- package/dist/connection.js.map +1 -1
- package/dist/generated/features.d.ts +5 -0
- package/dist/generated/features.d.ts.map +1 -0
- package/dist/generated/features.js +4 -0
- package/dist/generated/features.js.map +1 -0
- package/dist/index.js +0 -7
- package/dist/json.js +0 -1
- package/dist/mcp-over-acp-handler.d.ts +3 -8
- package/dist/mcp-over-acp-handler.d.ts.map +1 -1
- package/dist/mcp-over-acp-handler.js +136 -180
- package/dist/mcp-over-acp-handler.js.map +1 -1
- package/dist/mcp-server.js +119 -143
- package/dist/session.js +113 -159
- package/dist/skill-server.js +54 -89
- package/dist/skill.js +41 -107
- package/dist/types.js +0 -7
- package/package.json +6 -5
|
@@ -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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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":"AA0BA
|
|
1
|
+
{"version":3,"file":"mcp-over-acp-handler.js","sourceRoot":"","sources":["../src/mcp-over-acp-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-server.js
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
127
|
+
return new McpServerBuilder(name);
|
|
151
128
|
}
|
|
152
|
-
//# sourceMappingURL=mcp-server.js.map
|