@compilr-dev/agents 0.0.1
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 +1277 -0
- package/dist/agent.d.ts +1272 -0
- package/dist/agent.js +1912 -0
- package/dist/anchors/builtin.d.ts +24 -0
- package/dist/anchors/builtin.js +61 -0
- package/dist/anchors/index.d.ts +6 -0
- package/dist/anchors/index.js +5 -0
- package/dist/anchors/manager.d.ts +115 -0
- package/dist/anchors/manager.js +412 -0
- package/dist/anchors/types.d.ts +168 -0
- package/dist/anchors/types.js +10 -0
- package/dist/context/index.d.ts +12 -0
- package/dist/context/index.js +10 -0
- package/dist/context/manager.d.ts +224 -0
- package/dist/context/manager.js +770 -0
- package/dist/context/types.d.ts +377 -0
- package/dist/context/types.js +7 -0
- package/dist/costs/index.d.ts +8 -0
- package/dist/costs/index.js +7 -0
- package/dist/costs/tracker.d.ts +121 -0
- package/dist/costs/tracker.js +295 -0
- package/dist/costs/types.d.ts +157 -0
- package/dist/costs/types.js +8 -0
- package/dist/errors.d.ts +178 -0
- package/dist/errors.js +249 -0
- package/dist/guardrails/builtin.d.ts +27 -0
- package/dist/guardrails/builtin.js +223 -0
- package/dist/guardrails/index.d.ts +6 -0
- package/dist/guardrails/index.js +5 -0
- package/dist/guardrails/manager.d.ts +117 -0
- package/dist/guardrails/manager.js +288 -0
- package/dist/guardrails/types.d.ts +159 -0
- package/dist/guardrails/types.js +7 -0
- package/dist/hooks/index.d.ts +31 -0
- package/dist/hooks/index.js +29 -0
- package/dist/hooks/manager.d.ts +147 -0
- package/dist/hooks/manager.js +600 -0
- package/dist/hooks/types.d.ts +368 -0
- package/dist/hooks/types.js +12 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +73 -0
- package/dist/mcp/client.d.ts +93 -0
- package/dist/mcp/client.js +287 -0
- package/dist/mcp/errors.d.ts +60 -0
- package/dist/mcp/errors.js +78 -0
- package/dist/mcp/index.d.ts +43 -0
- package/dist/mcp/index.js +45 -0
- package/dist/mcp/manager.d.ts +120 -0
- package/dist/mcp/manager.js +276 -0
- package/dist/mcp/tools.d.ts +54 -0
- package/dist/mcp/tools.js +99 -0
- package/dist/mcp/types.d.ts +150 -0
- package/dist/mcp/types.js +40 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/loader.d.ts +114 -0
- package/dist/memory/loader.js +463 -0
- package/dist/memory/types.d.ts +182 -0
- package/dist/memory/types.js +8 -0
- package/dist/messages/index.d.ts +82 -0
- package/dist/messages/index.js +155 -0
- package/dist/permissions/index.d.ts +5 -0
- package/dist/permissions/index.js +4 -0
- package/dist/permissions/manager.d.ts +125 -0
- package/dist/permissions/manager.js +379 -0
- package/dist/permissions/types.d.ts +162 -0
- package/dist/permissions/types.js +7 -0
- package/dist/providers/claude.d.ts +90 -0
- package/dist/providers/claude.js +348 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/mock.d.ts +133 -0
- package/dist/providers/mock.js +204 -0
- package/dist/providers/types.d.ts +168 -0
- package/dist/providers/types.js +4 -0
- package/dist/rate-limit/index.d.ts +45 -0
- package/dist/rate-limit/index.js +47 -0
- package/dist/rate-limit/limiter.d.ts +104 -0
- package/dist/rate-limit/limiter.js +326 -0
- package/dist/rate-limit/provider-wrapper.d.ts +112 -0
- package/dist/rate-limit/provider-wrapper.js +201 -0
- package/dist/rate-limit/retry.d.ts +108 -0
- package/dist/rate-limit/retry.js +287 -0
- package/dist/rate-limit/types.d.ts +181 -0
- package/dist/rate-limit/types.js +22 -0
- package/dist/rehearsal/file-analyzer.d.ts +22 -0
- package/dist/rehearsal/file-analyzer.js +351 -0
- package/dist/rehearsal/git-analyzer.d.ts +22 -0
- package/dist/rehearsal/git-analyzer.js +472 -0
- package/dist/rehearsal/index.d.ts +35 -0
- package/dist/rehearsal/index.js +36 -0
- package/dist/rehearsal/manager.d.ts +100 -0
- package/dist/rehearsal/manager.js +290 -0
- package/dist/rehearsal/types.d.ts +235 -0
- package/dist/rehearsal/types.js +8 -0
- package/dist/skills/index.d.ts +160 -0
- package/dist/skills/index.js +282 -0
- package/dist/state/agent-state.d.ts +41 -0
- package/dist/state/agent-state.js +88 -0
- package/dist/state/checkpointer.d.ts +110 -0
- package/dist/state/checkpointer.js +362 -0
- package/dist/state/errors.d.ts +66 -0
- package/dist/state/errors.js +88 -0
- package/dist/state/index.d.ts +35 -0
- package/dist/state/index.js +37 -0
- package/dist/state/serializer.d.ts +55 -0
- package/dist/state/serializer.js +172 -0
- package/dist/state/types.d.ts +312 -0
- package/dist/state/types.js +14 -0
- package/dist/tools/builtin/bash-output.d.ts +61 -0
- package/dist/tools/builtin/bash-output.js +90 -0
- package/dist/tools/builtin/bash.d.ts +150 -0
- package/dist/tools/builtin/bash.js +354 -0
- package/dist/tools/builtin/edit.d.ts +50 -0
- package/dist/tools/builtin/edit.js +215 -0
- package/dist/tools/builtin/glob.d.ts +62 -0
- package/dist/tools/builtin/glob.js +244 -0
- package/dist/tools/builtin/grep.d.ts +74 -0
- package/dist/tools/builtin/grep.js +363 -0
- package/dist/tools/builtin/index.d.ts +44 -0
- package/dist/tools/builtin/index.js +69 -0
- package/dist/tools/builtin/kill-shell.d.ts +44 -0
- package/dist/tools/builtin/kill-shell.js +80 -0
- package/dist/tools/builtin/read-file.d.ts +57 -0
- package/dist/tools/builtin/read-file.js +184 -0
- package/dist/tools/builtin/shell-manager.d.ts +176 -0
- package/dist/tools/builtin/shell-manager.js +337 -0
- package/dist/tools/builtin/task.d.ts +202 -0
- package/dist/tools/builtin/task.js +350 -0
- package/dist/tools/builtin/todo.d.ts +207 -0
- package/dist/tools/builtin/todo.js +453 -0
- package/dist/tools/builtin/utils.d.ts +27 -0
- package/dist/tools/builtin/utils.js +70 -0
- package/dist/tools/builtin/web-fetch.d.ts +96 -0
- package/dist/tools/builtin/web-fetch.js +290 -0
- package/dist/tools/builtin/write-file.d.ts +54 -0
- package/dist/tools/builtin/write-file.js +147 -0
- package/dist/tools/define.d.ts +60 -0
- package/dist/tools/define.js +65 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/registry.d.ts +79 -0
- package/dist/tools/registry.js +151 -0
- package/dist/tools/types.d.ts +59 -0
- package/dist/tools/types.js +4 -0
- package/dist/tracing/hooks.d.ts +58 -0
- package/dist/tracing/hooks.js +377 -0
- package/dist/tracing/index.d.ts +51 -0
- package/dist/tracing/index.js +55 -0
- package/dist/tracing/logging.d.ts +78 -0
- package/dist/tracing/logging.js +310 -0
- package/dist/tracing/manager.d.ts +160 -0
- package/dist/tracing/manager.js +468 -0
- package/dist/tracing/otel.d.ts +102 -0
- package/dist/tracing/otel.js +246 -0
- package/dist/tracing/types.d.ts +346 -0
- package/dist/tracing/types.js +38 -0
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.js +44 -0
- package/package.json +79 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Client - Connects to MCP servers and discovers tools
|
|
3
|
+
*
|
|
4
|
+
* Uses the official @modelcontextprotocol/sdk as an optional peer dependency.
|
|
5
|
+
* If the SDK is not installed, attempting to use MCP features will throw
|
|
6
|
+
* a helpful error with installation instructions.
|
|
7
|
+
*/
|
|
8
|
+
import { MCPError, MCPErrorCode, createSDKNotInstalledError } from './errors.js';
|
|
9
|
+
/**
|
|
10
|
+
* Cached SDK imports
|
|
11
|
+
* Using loose constructor types to accommodate SDK version changes
|
|
12
|
+
*/
|
|
13
|
+
let sdkCache = null;
|
|
14
|
+
/**
|
|
15
|
+
* Dynamically load the MCP SDK
|
|
16
|
+
* @throws MCPError if SDK is not installed
|
|
17
|
+
*/
|
|
18
|
+
async function getMCPSDK() {
|
|
19
|
+
if (sdkCache)
|
|
20
|
+
return sdkCache;
|
|
21
|
+
try {
|
|
22
|
+
// Dynamic imports to keep SDK optional
|
|
23
|
+
const [clientModule, stdioModule, httpModule] = await Promise.all([
|
|
24
|
+
import('@modelcontextprotocol/sdk/client/index.js'),
|
|
25
|
+
import('@modelcontextprotocol/sdk/client/stdio.js'),
|
|
26
|
+
import('@modelcontextprotocol/sdk/client/streamableHttp.js'),
|
|
27
|
+
]);
|
|
28
|
+
sdkCache = {
|
|
29
|
+
Client: clientModule.Client,
|
|
30
|
+
StdioClientTransport: stdioModule.StdioClientTransport,
|
|
31
|
+
StreamableHTTPClientTransport: httpModule.StreamableHTTPClientTransport,
|
|
32
|
+
};
|
|
33
|
+
// Non-null assertion safe: we just assigned sdkCache above
|
|
34
|
+
return sdkCache;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// Check if it's a module not found error
|
|
38
|
+
if (error instanceof Error &&
|
|
39
|
+
(error.message.includes('Cannot find module') ||
|
|
40
|
+
error.message.includes('ERR_MODULE_NOT_FOUND'))) {
|
|
41
|
+
throw createSDKNotInstalledError();
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* MCP Client for connecting to a single MCP server
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const client = new MCPClient({
|
|
52
|
+
* name: 'filesystem',
|
|
53
|
+
* transport: 'stdio',
|
|
54
|
+
* stdio: {
|
|
55
|
+
* command: 'npx',
|
|
56
|
+
* args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
|
|
57
|
+
* },
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* await client.connect();
|
|
61
|
+
* const tools = await client.listTools();
|
|
62
|
+
* const result = await client.callTool('read_file', { path: '/tmp/test.txt' });
|
|
63
|
+
* await client.disconnect();
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export class MCPClient {
|
|
67
|
+
name;
|
|
68
|
+
config;
|
|
69
|
+
client = null;
|
|
70
|
+
transport = null;
|
|
71
|
+
_status = 'disconnected';
|
|
72
|
+
eventHandlers = new Set();
|
|
73
|
+
cachedTools = null;
|
|
74
|
+
constructor(config) {
|
|
75
|
+
this.name = config.name;
|
|
76
|
+
this.config = config;
|
|
77
|
+
// Validate config
|
|
78
|
+
if (config.transport === 'stdio' && !config.stdio) {
|
|
79
|
+
throw new MCPError(`MCP server '${config.name}': stdio transport requires 'stdio' options`, config.name, MCPErrorCode.INVALID_CONFIG);
|
|
80
|
+
}
|
|
81
|
+
if (config.transport === 'http' && !config.http) {
|
|
82
|
+
throw new MCPError(`MCP server '${config.name}': http transport requires 'http' options`, config.name, MCPErrorCode.INVALID_CONFIG);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Current connection status
|
|
87
|
+
*/
|
|
88
|
+
get status() {
|
|
89
|
+
return this._status;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Whether the client is connected
|
|
93
|
+
*/
|
|
94
|
+
get isConnected() {
|
|
95
|
+
return this._status === 'connected';
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Connect to the MCP server
|
|
99
|
+
* @throws MCPError if connection fails
|
|
100
|
+
*/
|
|
101
|
+
async connect() {
|
|
102
|
+
if (this._status === 'connected') {
|
|
103
|
+
return; // Already connected
|
|
104
|
+
}
|
|
105
|
+
this._status = 'connecting';
|
|
106
|
+
try {
|
|
107
|
+
const sdk = await getMCPSDK();
|
|
108
|
+
// Create transport based on config
|
|
109
|
+
if (this.config.transport === 'stdio' && this.config.stdio) {
|
|
110
|
+
this.transport = new sdk.StdioClientTransport({
|
|
111
|
+
command: this.config.stdio.command,
|
|
112
|
+
args: this.config.stdio.args,
|
|
113
|
+
env: this.config.stdio.env,
|
|
114
|
+
cwd: this.config.stdio.cwd,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else if (this.config.transport === 'http' && this.config.http) {
|
|
118
|
+
this.transport = new sdk.StreamableHTTPClientTransport(new URL(this.config.http.url));
|
|
119
|
+
}
|
|
120
|
+
// Create client
|
|
121
|
+
this.client = new sdk.Client({
|
|
122
|
+
name: this.config.clientName ?? '@compilr-dev/agents',
|
|
123
|
+
version: this.config.clientVersion ?? '1.0.0',
|
|
124
|
+
});
|
|
125
|
+
// Set up notification handler for tools changed
|
|
126
|
+
this.client.setNotificationHandler('notifications/tools/list_changed', () => {
|
|
127
|
+
this.cachedTools = null; // Invalidate cache
|
|
128
|
+
this.emit({ type: 'tools_changed', serverName: this.name });
|
|
129
|
+
});
|
|
130
|
+
// Connect with timeout
|
|
131
|
+
const timeoutMs = this.config.timeout ?? 30000;
|
|
132
|
+
const connectPromise = this.client.connect(this.transport);
|
|
133
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
reject(new MCPError(`Connection to '${this.name}' timed out after ${String(timeoutMs)}ms`, this.name, MCPErrorCode.TIMEOUT));
|
|
136
|
+
}, timeoutMs);
|
|
137
|
+
});
|
|
138
|
+
await Promise.race([connectPromise, timeoutPromise]);
|
|
139
|
+
this._status = 'connected';
|
|
140
|
+
this.emit({ type: 'connected', serverName: this.name });
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
this._status = 'error';
|
|
144
|
+
if (error instanceof MCPError) {
|
|
145
|
+
this.emit({ type: 'error', serverName: this.name, error });
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
const mcpError = new MCPError(`Failed to connect to MCP server '${this.name}': ${error instanceof Error ? error.message : String(error)}`, this.name, MCPErrorCode.CONNECTION_FAILED, error instanceof Error ? error : undefined);
|
|
149
|
+
this.emit({ type: 'error', serverName: this.name, error: mcpError });
|
|
150
|
+
throw mcpError;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Disconnect from the MCP server
|
|
155
|
+
*/
|
|
156
|
+
async disconnect() {
|
|
157
|
+
if (this._status === 'disconnected') {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
if (this.client) {
|
|
162
|
+
await this.client.close();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Ignore disconnect errors
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
this.client = null;
|
|
170
|
+
this.transport = null;
|
|
171
|
+
this.cachedTools = null;
|
|
172
|
+
this._status = 'disconnected';
|
|
173
|
+
this.emit({ type: 'disconnected', serverName: this.name });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* List available tools from the server
|
|
178
|
+
* @throws MCPError if not connected or listing fails
|
|
179
|
+
*/
|
|
180
|
+
async listTools() {
|
|
181
|
+
const client = this.getConnectedClient();
|
|
182
|
+
// Return cached tools if available
|
|
183
|
+
if (this.cachedTools) {
|
|
184
|
+
return this.cachedTools;
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
const result = await client.listTools();
|
|
188
|
+
this.cachedTools = result.tools;
|
|
189
|
+
return result.tools;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
throw new MCPError(`Failed to list tools from '${this.name}': ${error instanceof Error ? error.message : String(error)}`, this.name, MCPErrorCode.TRANSPORT_ERROR, error instanceof Error ? error : undefined);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Call a tool on the server
|
|
197
|
+
* @param toolName Name of the tool to call
|
|
198
|
+
* @param args Arguments to pass to the tool
|
|
199
|
+
* @throws MCPError if not connected, tool not found, or execution fails
|
|
200
|
+
*/
|
|
201
|
+
async callTool(toolName, args) {
|
|
202
|
+
const client = this.getConnectedClient();
|
|
203
|
+
try {
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
205
|
+
const result = await client.callTool({
|
|
206
|
+
name: toolName,
|
|
207
|
+
arguments: args,
|
|
208
|
+
});
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
// Check if it's a tool not found error
|
|
214
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
215
|
+
if (message.includes('not found') || message.includes('unknown tool')) {
|
|
216
|
+
throw new MCPError(`Tool '${toolName}' not found on server '${this.name}'`, this.name, MCPErrorCode.TOOL_NOT_FOUND, error instanceof Error ? error : undefined);
|
|
217
|
+
}
|
|
218
|
+
throw new MCPError(`Failed to call tool '${toolName}' on '${this.name}': ${message}`, this.name, MCPErrorCode.TOOL_EXECUTION_FAILED, error instanceof Error ? error : undefined);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Register an event handler
|
|
223
|
+
*/
|
|
224
|
+
onEvent(handler) {
|
|
225
|
+
this.eventHandlers.add(handler);
|
|
226
|
+
return () => this.eventHandlers.delete(handler);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Convenience method to listen for tools changed events
|
|
230
|
+
*/
|
|
231
|
+
onToolsChanged(callback) {
|
|
232
|
+
return this.onEvent((event) => {
|
|
233
|
+
if (event.type === 'tools_changed') {
|
|
234
|
+
// Fetch new tools and call callback
|
|
235
|
+
this.listTools()
|
|
236
|
+
.then(callback)
|
|
237
|
+
.catch(() => {
|
|
238
|
+
/* ignore errors in callback */
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Convenience method to listen for errors
|
|
245
|
+
*/
|
|
246
|
+
onError(callback) {
|
|
247
|
+
return this.onEvent((event) => {
|
|
248
|
+
if (event.type === 'error' && event.error) {
|
|
249
|
+
callback(event.error);
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Convenience method to listen for disconnect
|
|
255
|
+
*/
|
|
256
|
+
onDisconnect(callback) {
|
|
257
|
+
return this.onEvent((event) => {
|
|
258
|
+
if (event.type === 'disconnected') {
|
|
259
|
+
callback();
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Emit an event to all handlers
|
|
265
|
+
*/
|
|
266
|
+
emit(event) {
|
|
267
|
+
for (const handler of this.eventHandlers) {
|
|
268
|
+
try {
|
|
269
|
+
handler(event);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Ignore handler errors
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get the connected client, throwing if not connected
|
|
278
|
+
* @throws MCPError if not connected
|
|
279
|
+
* @returns The connected SDK client
|
|
280
|
+
*/
|
|
281
|
+
getConnectedClient() {
|
|
282
|
+
if (!this.client || this._status !== 'connected') {
|
|
283
|
+
throw new MCPError(`MCP client '${this.name}' is not connected`, this.name, MCPErrorCode.CONNECTION_FAILED);
|
|
284
|
+
}
|
|
285
|
+
return this.client;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP-specific error classes
|
|
3
|
+
*/
|
|
4
|
+
import { AgentError } from '../errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Error codes for MCP operations
|
|
7
|
+
*/
|
|
8
|
+
export declare enum MCPErrorCode {
|
|
9
|
+
/** MCP SDK is not installed */
|
|
10
|
+
SDK_NOT_INSTALLED = "SDK_NOT_INSTALLED",
|
|
11
|
+
/** Failed to connect to MCP server */
|
|
12
|
+
CONNECTION_FAILED = "CONNECTION_FAILED",
|
|
13
|
+
/** Server not found in manager */
|
|
14
|
+
SERVER_NOT_FOUND = "SERVER_NOT_FOUND",
|
|
15
|
+
/** Tool not found on server */
|
|
16
|
+
TOOL_NOT_FOUND = "TOOL_NOT_FOUND",
|
|
17
|
+
/** Tool execution failed */
|
|
18
|
+
TOOL_EXECUTION_FAILED = "TOOL_EXECUTION_FAILED",
|
|
19
|
+
/** Transport error (stdio/http) */
|
|
20
|
+
TRANSPORT_ERROR = "TRANSPORT_ERROR",
|
|
21
|
+
/** Connection or operation timeout */
|
|
22
|
+
TIMEOUT = "TIMEOUT",
|
|
23
|
+
/** Invalid server configuration */
|
|
24
|
+
INVALID_CONFIG = "INVALID_CONFIG",
|
|
25
|
+
/** Server already exists */
|
|
26
|
+
SERVER_EXISTS = "SERVER_EXISTS"
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown for MCP-related failures
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* throw new MCPError(
|
|
34
|
+
* 'Failed to connect to server',
|
|
35
|
+
* 'filesystem',
|
|
36
|
+
* MCPErrorCode.CONNECTION_FAILED
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class MCPError extends AgentError {
|
|
41
|
+
readonly serverName: string;
|
|
42
|
+
readonly code: MCPErrorCode;
|
|
43
|
+
constructor(message: string, serverName: string, code: MCPErrorCode, cause?: Error);
|
|
44
|
+
/**
|
|
45
|
+
* Check if the error is due to missing SDK
|
|
46
|
+
*/
|
|
47
|
+
isSDKNotInstalled(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Check if the error is retryable (connection/timeout issues)
|
|
50
|
+
*/
|
|
51
|
+
isRetryable(): boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Type guard to check if an error is an MCPError
|
|
55
|
+
*/
|
|
56
|
+
export declare function isMCPError(error: unknown): error is MCPError;
|
|
57
|
+
/**
|
|
58
|
+
* Create an SDK not installed error with helpful message
|
|
59
|
+
*/
|
|
60
|
+
export declare function createSDKNotInstalledError(): MCPError;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP-specific error classes
|
|
3
|
+
*/
|
|
4
|
+
import { AgentError } from '../errors.js';
|
|
5
|
+
/**
|
|
6
|
+
* Error codes for MCP operations
|
|
7
|
+
*/
|
|
8
|
+
export var MCPErrorCode;
|
|
9
|
+
(function (MCPErrorCode) {
|
|
10
|
+
/** MCP SDK is not installed */
|
|
11
|
+
MCPErrorCode["SDK_NOT_INSTALLED"] = "SDK_NOT_INSTALLED";
|
|
12
|
+
/** Failed to connect to MCP server */
|
|
13
|
+
MCPErrorCode["CONNECTION_FAILED"] = "CONNECTION_FAILED";
|
|
14
|
+
/** Server not found in manager */
|
|
15
|
+
MCPErrorCode["SERVER_NOT_FOUND"] = "SERVER_NOT_FOUND";
|
|
16
|
+
/** Tool not found on server */
|
|
17
|
+
MCPErrorCode["TOOL_NOT_FOUND"] = "TOOL_NOT_FOUND";
|
|
18
|
+
/** Tool execution failed */
|
|
19
|
+
MCPErrorCode["TOOL_EXECUTION_FAILED"] = "TOOL_EXECUTION_FAILED";
|
|
20
|
+
/** Transport error (stdio/http) */
|
|
21
|
+
MCPErrorCode["TRANSPORT_ERROR"] = "TRANSPORT_ERROR";
|
|
22
|
+
/** Connection or operation timeout */
|
|
23
|
+
MCPErrorCode["TIMEOUT"] = "TIMEOUT";
|
|
24
|
+
/** Invalid server configuration */
|
|
25
|
+
MCPErrorCode["INVALID_CONFIG"] = "INVALID_CONFIG";
|
|
26
|
+
/** Server already exists */
|
|
27
|
+
MCPErrorCode["SERVER_EXISTS"] = "SERVER_EXISTS";
|
|
28
|
+
})(MCPErrorCode || (MCPErrorCode = {}));
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown for MCP-related failures
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* throw new MCPError(
|
|
35
|
+
* 'Failed to connect to server',
|
|
36
|
+
* 'filesystem',
|
|
37
|
+
* MCPErrorCode.CONNECTION_FAILED
|
|
38
|
+
* );
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export class MCPError extends AgentError {
|
|
42
|
+
serverName;
|
|
43
|
+
code;
|
|
44
|
+
constructor(message, serverName, code, cause) {
|
|
45
|
+
super(message, cause);
|
|
46
|
+
this.serverName = serverName;
|
|
47
|
+
this.code = code;
|
|
48
|
+
this.name = 'MCPError';
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if the error is due to missing SDK
|
|
52
|
+
*/
|
|
53
|
+
isSDKNotInstalled() {
|
|
54
|
+
return this.code === MCPErrorCode.SDK_NOT_INSTALLED;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if the error is retryable (connection/timeout issues)
|
|
58
|
+
*/
|
|
59
|
+
isRetryable() {
|
|
60
|
+
return (this.code === MCPErrorCode.CONNECTION_FAILED ||
|
|
61
|
+
this.code === MCPErrorCode.TIMEOUT ||
|
|
62
|
+
this.code === MCPErrorCode.TRANSPORT_ERROR);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Type guard to check if an error is an MCPError
|
|
67
|
+
*/
|
|
68
|
+
export function isMCPError(error) {
|
|
69
|
+
return error instanceof MCPError;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create an SDK not installed error with helpful message
|
|
73
|
+
*/
|
|
74
|
+
export function createSDKNotInstalledError() {
|
|
75
|
+
return new MCPError('MCP SDK is not installed. To use MCP features, install the SDK:\n\n' +
|
|
76
|
+
' npm install @modelcontextprotocol/sdk\n\n' +
|
|
77
|
+
'The SDK is an optional peer dependency - only install if you need MCP support.', '', MCPErrorCode.SDK_NOT_INSTALLED);
|
|
78
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Support
|
|
3
|
+
*
|
|
4
|
+
* This module provides integration with MCP servers, allowing agents to
|
|
5
|
+
* use tools provided by MCP-compliant servers.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: The MCP SDK (@modelcontextprotocol/sdk) is an optional peer dependency.
|
|
8
|
+
* If you want to use MCP features, install it:
|
|
9
|
+
*
|
|
10
|
+
* npm install @modelcontextprotocol/sdk
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { MCPManager, MCPClient } from '@compilr-dev/agents';
|
|
15
|
+
*
|
|
16
|
+
* // Using MCPManager (recommended for multiple servers)
|
|
17
|
+
* const manager = new MCPManager();
|
|
18
|
+
* await manager.addServer({
|
|
19
|
+
* name: 'filesystem',
|
|
20
|
+
* transport: 'stdio',
|
|
21
|
+
* command: 'npx',
|
|
22
|
+
* args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const tools = await manager.discoverTools();
|
|
26
|
+
*
|
|
27
|
+
* // Using MCPClient directly (for single server)
|
|
28
|
+
* const client = new MCPClient({
|
|
29
|
+
* name: 'filesystem',
|
|
30
|
+
* transport: 'stdio',
|
|
31
|
+
* stdio: { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'] },
|
|
32
|
+
* });
|
|
33
|
+
* await client.connect();
|
|
34
|
+
* const mcpTools = await client.listTools();
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export { MCPClient } from './client.js';
|
|
38
|
+
export { MCPManager } from './manager.js';
|
|
39
|
+
export { mcpToolToTool, mcpToolsToTools, convertMCPResult, contentBlocksToString, generateToolName, } from './tools.js';
|
|
40
|
+
export type { MCPToolConversionOptions } from './tools.js';
|
|
41
|
+
export type { MCPTransport, MCPConnectionStatus, MCPStdioOptions, MCPHttpOptions, MCPClientConfig, MCPServerConfig, MCPToolDefinition, MCPContentBlock, MCPToolResult, MCPClientEventType, MCPClientEvent, MCPClientEventHandler, MCPManagerOptions, } from './types.js';
|
|
42
|
+
export { normalizeServerConfig } from './types.js';
|
|
43
|
+
export { MCPError, MCPErrorCode, isMCPError, createSDKNotInstalledError } from './errors.js';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) Support
|
|
3
|
+
*
|
|
4
|
+
* This module provides integration with MCP servers, allowing agents to
|
|
5
|
+
* use tools provided by MCP-compliant servers.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: The MCP SDK (@modelcontextprotocol/sdk) is an optional peer dependency.
|
|
8
|
+
* If you want to use MCP features, install it:
|
|
9
|
+
*
|
|
10
|
+
* npm install @modelcontextprotocol/sdk
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { MCPManager, MCPClient } from '@compilr-dev/agents';
|
|
15
|
+
*
|
|
16
|
+
* // Using MCPManager (recommended for multiple servers)
|
|
17
|
+
* const manager = new MCPManager();
|
|
18
|
+
* await manager.addServer({
|
|
19
|
+
* name: 'filesystem',
|
|
20
|
+
* transport: 'stdio',
|
|
21
|
+
* command: 'npx',
|
|
22
|
+
* args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const tools = await manager.discoverTools();
|
|
26
|
+
*
|
|
27
|
+
* // Using MCPClient directly (for single server)
|
|
28
|
+
* const client = new MCPClient({
|
|
29
|
+
* name: 'filesystem',
|
|
30
|
+
* transport: 'stdio',
|
|
31
|
+
* stdio: { command: 'npx', args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'] },
|
|
32
|
+
* });
|
|
33
|
+
* await client.connect();
|
|
34
|
+
* const mcpTools = await client.listTools();
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
// Client
|
|
38
|
+
export { MCPClient } from './client.js';
|
|
39
|
+
// Manager
|
|
40
|
+
export { MCPManager } from './manager.js';
|
|
41
|
+
// Tool conversion utilities
|
|
42
|
+
export { mcpToolToTool, mcpToolsToTools, convertMCPResult, contentBlocksToString, generateToolName, } from './tools.js';
|
|
43
|
+
export { normalizeServerConfig } from './types.js';
|
|
44
|
+
// Errors
|
|
45
|
+
export { MCPError, MCPErrorCode, isMCPError, createSDKNotInstalledError } from './errors.js';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Manager - Manages multiple MCP server connections
|
|
3
|
+
*
|
|
4
|
+
* Provides a high-level interface for:
|
|
5
|
+
* - Managing multiple MCP servers
|
|
6
|
+
* - Discovering and registering tools from servers
|
|
7
|
+
* - Handling server lifecycle (connect, disconnect, reconnect)
|
|
8
|
+
*/
|
|
9
|
+
import type { Tool } from '../tools/index.js';
|
|
10
|
+
import { DefaultToolRegistry } from '../tools/index.js';
|
|
11
|
+
import { MCPClient } from './client.js';
|
|
12
|
+
import type { MCPServerConfig, MCPManagerOptions, MCPClientEventHandler } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* MCP Manager for managing multiple MCP server connections
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const manager = new MCPManager();
|
|
19
|
+
*
|
|
20
|
+
* // Add servers
|
|
21
|
+
* await manager.addServer({
|
|
22
|
+
* name: 'filesystem',
|
|
23
|
+
* transport: 'stdio',
|
|
24
|
+
* command: 'npx',
|
|
25
|
+
* args: ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'],
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* // Discover and get tools
|
|
29
|
+
* const tools = await manager.discoverTools();
|
|
30
|
+
*
|
|
31
|
+
* // Use with agent
|
|
32
|
+
* const agent = new Agent({
|
|
33
|
+
* provider: claude,
|
|
34
|
+
* tools: [...builtinTools, ...tools],
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* // Cleanup
|
|
38
|
+
* await manager.disconnectAll();
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare class MCPManager {
|
|
42
|
+
private readonly clients;
|
|
43
|
+
private toolRegistry;
|
|
44
|
+
private readonly toolPrefix;
|
|
45
|
+
private readonly autoConnect;
|
|
46
|
+
private readonly eventHandlers;
|
|
47
|
+
constructor(options?: MCPManagerOptions);
|
|
48
|
+
/**
|
|
49
|
+
* Set a tool registry for automatic tool registration
|
|
50
|
+
* When set, tools from MCP servers will be automatically registered
|
|
51
|
+
*/
|
|
52
|
+
setToolRegistry(registry: DefaultToolRegistry): void;
|
|
53
|
+
/**
|
|
54
|
+
* Add an MCP server
|
|
55
|
+
*
|
|
56
|
+
* @param config Server configuration
|
|
57
|
+
* @returns The created MCPClient
|
|
58
|
+
* @throws MCPError if server with same name already exists
|
|
59
|
+
*/
|
|
60
|
+
addServer(config: MCPServerConfig): Promise<MCPClient>;
|
|
61
|
+
/**
|
|
62
|
+
* Remove an MCP server
|
|
63
|
+
*
|
|
64
|
+
* @param name Server name
|
|
65
|
+
* @throws MCPError if server not found
|
|
66
|
+
*/
|
|
67
|
+
removeServer(name: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Get an MCP client by name
|
|
70
|
+
*/
|
|
71
|
+
getServer(name: string): MCPClient | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Get all MCP clients
|
|
74
|
+
*/
|
|
75
|
+
getServers(): MCPClient[];
|
|
76
|
+
/**
|
|
77
|
+
* Get all server names
|
|
78
|
+
*/
|
|
79
|
+
getServerNames(): string[];
|
|
80
|
+
/**
|
|
81
|
+
* Check if a server exists
|
|
82
|
+
*/
|
|
83
|
+
hasServer(name: string): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Discover tools from all connected servers
|
|
86
|
+
*
|
|
87
|
+
* @returns Array of converted tools ready for registration
|
|
88
|
+
*/
|
|
89
|
+
discoverTools(): Promise<Tool[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Discover tools from a specific server
|
|
92
|
+
*/
|
|
93
|
+
discoverToolsFrom(serverName: string): Promise<Tool[]>;
|
|
94
|
+
/**
|
|
95
|
+
* Refresh tools from servers and update the tool registry
|
|
96
|
+
*
|
|
97
|
+
* @param serverName Optional server name to refresh. If not provided, refreshes all.
|
|
98
|
+
*/
|
|
99
|
+
refreshTools(serverName?: string): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Get raw MCP tool definitions from a server
|
|
102
|
+
*/
|
|
103
|
+
private getMCPTools;
|
|
104
|
+
/**
|
|
105
|
+
* Connect all servers
|
|
106
|
+
*/
|
|
107
|
+
connectAll(): Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Disconnect all servers
|
|
110
|
+
*/
|
|
111
|
+
disconnectAll(): Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* Register an event handler
|
|
114
|
+
*/
|
|
115
|
+
onEvent(handler: MCPClientEventHandler): () => void;
|
|
116
|
+
/**
|
|
117
|
+
* Emit an event to all handlers
|
|
118
|
+
*/
|
|
119
|
+
private emit;
|
|
120
|
+
}
|