@agentionai/agents 0.6.1 → 0.8.0
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/agents/BaseAgent.d.ts +0 -39
- package/dist/agents/BaseAgent.js +1 -100
- package/dist/agents/anthropic/ClaudeAgent.d.ts +2 -0
- package/dist/agents/anthropic/ClaudeAgent.js +4 -8
- package/dist/agents/google/GeminiAgent.d.ts +2 -0
- package/dist/agents/google/GeminiAgent.js +4 -4
- package/dist/agents/mistral/MistralAgent.d.ts +2 -0
- package/dist/agents/mistral/MistralAgent.js +4 -4
- package/dist/agents/openai/OpenAiAgent.d.ts +2 -0
- package/dist/agents/openai/OpenAiAgent.js +4 -4
- package/dist/chunkers/Chunker.d.ts +1 -1
- package/dist/chunkers/Chunker.js +19 -20
- package/dist/chunkers/TokenChunker.d.ts +1 -1
- package/dist/chunkers/TokenChunker.js +2 -3
- package/dist/chunkers/types.d.ts +17 -11
- package/dist/core.d.ts +1 -0
- package/dist/core.js +2 -0
- package/dist/graph/planning/PlanExecutor.d.ts +0 -12
- package/dist/graph/planning/PlanExecutor.js +19 -74
- package/dist/graph/planning/PlanStore.js +2 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/mcp/MCPClient.d.ts +106 -0
- package/dist/mcp/MCPClient.js +264 -0
- package/dist/mcp/index.d.ts +64 -0
- package/dist/mcp/index.js +67 -0
- package/dist/mcp/types.d.ts +51 -0
- package/dist/mcp/types.js +3 -0
- package/dist/vectorstore/LanceDBVectorStore.d.ts +102 -54
- package/dist/vectorstore/LanceDBVectorStore.js +231 -135
- package/dist/vectorstore/VectorStore.d.ts +2 -2
- package/dist/vectorstore/VectorStore.js +3 -3
- package/package.json +7 -3
|
@@ -57,7 +57,6 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
57
57
|
maxSteps: options.maxSteps ?? 50,
|
|
58
58
|
concurrency: options.concurrency ?? 1,
|
|
59
59
|
stopOnFailure: options.stopOnFailure ?? true,
|
|
60
|
-
maxContextSteps: options.maxContextSteps ?? 0, // Default: no auto context
|
|
61
60
|
onPlanCreated: options.onPlanCreated,
|
|
62
61
|
onStepStart: options.onStepStart,
|
|
63
62
|
onStepComplete: options.onStepComplete,
|
|
@@ -151,16 +150,11 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
151
150
|
const results = [];
|
|
152
151
|
let stepNumber = 0;
|
|
153
152
|
const activePromises = new Map();
|
|
154
|
-
let stopError;
|
|
155
153
|
while (stepNumber < this.options.maxSteps) {
|
|
156
154
|
// Wait if we've reached concurrency limit
|
|
157
155
|
if (activePromises.size >= this.options.concurrency) {
|
|
158
156
|
await Promise.race(activePromises.values());
|
|
159
157
|
}
|
|
160
|
-
// If a step failed and stopOnFailure is set, drain remaining promises then throw
|
|
161
|
-
if (stopError) {
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
158
|
const nextStep = this.planStore.getNextStep();
|
|
165
159
|
if (!nextStep) {
|
|
166
160
|
// No more pending steps
|
|
@@ -208,9 +202,9 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
208
202
|
});
|
|
209
203
|
// Notify step failure
|
|
210
204
|
this.options.onStepFailed?.(nextStep, error instanceof Error ? error : new Error(errorMessage), stepNumber);
|
|
211
|
-
//
|
|
205
|
+
// Stop if configured to do so
|
|
212
206
|
if (this.options.stopOnFailure) {
|
|
213
|
-
|
|
207
|
+
throw new Error(`Step ${stepNumber} failed: ${errorMessage}`);
|
|
214
208
|
}
|
|
215
209
|
}
|
|
216
210
|
finally {
|
|
@@ -226,12 +220,9 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
226
220
|
await promise;
|
|
227
221
|
}
|
|
228
222
|
}
|
|
229
|
-
//
|
|
223
|
+
// Wait for all remaining promises to complete
|
|
230
224
|
if (activePromises.size > 0) {
|
|
231
|
-
await Promise.
|
|
232
|
-
}
|
|
233
|
-
if (stopError) {
|
|
234
|
-
throw stopError;
|
|
225
|
+
await Promise.all(activePromises.values());
|
|
235
226
|
}
|
|
236
227
|
if (stepNumber >= this.options.maxSteps) {
|
|
237
228
|
const plan = this.planStore.getActivePlan();
|
|
@@ -250,81 +241,34 @@ class PlanExecutor extends BaseExecutor_1.BaseExecutor {
|
|
|
250
241
|
|
|
251
242
|
Task: ${task}
|
|
252
243
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
CONTEXT LIMIT WARNING: Each step will be executed independently with limited context. To avoid rate limits and context overflow:
|
|
256
|
-
- Break work into VERY SMALL, ATOMIC steps
|
|
257
|
-
- Each step should process only 1-3 items at a time
|
|
258
|
-
- Never create steps that say "analyze all", "process everything", "read all files", etc.
|
|
259
|
-
- Instead, break into multiple steps: "Read file1", "Read file2", "Read file3"
|
|
260
|
-
|
|
261
|
-
Use the create_plan tool to create a plan with clear, actionable steps. Each step MUST be:
|
|
262
|
-
|
|
263
|
-
1. MICRO-SIZED - Can be completed in under 10 seconds with minimal tokens
|
|
264
|
-
2. SINGLE ACTION - Exactly ONE thing to do (read ONE file, list ONE directory, etc.)
|
|
265
|
-
3. SPECIFIC - Mention exact file names, directories, or items (not "all files")
|
|
266
|
-
4. NO BATCH OPERATIONS - Process items one-by-one, not in bulk
|
|
267
|
-
5. SEQUENTIAL - Let each step's output inform the next step
|
|
268
|
-
|
|
269
|
-
GOOD EXAMPLES (SMALL STEPS):
|
|
270
|
-
✓ "List files in the lib/graph directory"
|
|
271
|
-
✓ "Read the first 50 lines of PlanExecutor.ts"
|
|
272
|
-
✓ "Search for the definition of 'createPlan' function"
|
|
273
|
-
✓ "Summarize the purpose of SequentialExecutor class in 2 sentences"
|
|
274
|
-
|
|
275
|
-
BAD EXAMPLES (TOO LARGE):
|
|
276
|
-
✗ "Read and analyze all files in lib/graph" (reads too much, use multiple steps)
|
|
277
|
-
✗ "Analyze the entire codebase architecture" (too broad, break into 5+ steps)
|
|
278
|
-
✗ "Review all test files and identify issues" (batch operation, do one at a time)
|
|
279
|
-
✗ "Research best practices and implement them" (vague, multi-step)
|
|
244
|
+
IMPORTANT: You can create a maximum of ${this.options.maxSteps} steps. Plan accordingly and prioritize the most important subtasks.
|
|
280
245
|
|
|
281
|
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
285
|
-
- If the task seems large: Create 2x as many steps as you initially think
|
|
286
|
-
|
|
287
|
-
Break down complex tasks into the SMALLEST possible steps. Having ${this.options.maxSteps} small steps is much better than having ${Math.floor(this.options.maxSteps / 2)} larger ones.
|
|
246
|
+
Use the create_plan tool to create a plan with clear, actionable steps. Each step should be:
|
|
247
|
+
- Specific and focused on a single subtask
|
|
248
|
+
- Ordered logically (dependencies should be addressed)
|
|
249
|
+
- Achievable by a worker agent
|
|
288
250
|
|
|
289
251
|
After creating the plan, respond with a brief confirmation.`;
|
|
290
252
|
}
|
|
291
253
|
/**
|
|
292
254
|
* Create input for a step execution.
|
|
293
|
-
*
|
|
294
|
-
* By default, only includes the current step information.
|
|
295
|
-
* Workers should use context_get to retrieve data from previous steps.
|
|
296
|
-
* This prevents token overflow from accumulating context.
|
|
297
255
|
*/
|
|
298
256
|
createStepInput(step, stepNumber) {
|
|
299
257
|
const plan = this.planStore.getActivePlan();
|
|
300
258
|
const completedSteps = plan?.steps.filter((s) => s.status === "completed") || [];
|
|
301
|
-
|
|
302
|
-
// Only include the most recent N steps based on maxContextSteps option
|
|
303
|
-
const recentSteps = this.options.maxContextSteps > 0
|
|
304
|
-
? completedSteps.slice(-this.options.maxContextSteps)
|
|
305
|
-
: [];
|
|
306
|
-
const input = {
|
|
259
|
+
return JSON.stringify({
|
|
307
260
|
stepNumber,
|
|
308
261
|
totalSteps: plan?.steps.length,
|
|
309
262
|
currentStep: {
|
|
310
263
|
id: step.id,
|
|
311
264
|
description: step.description,
|
|
312
265
|
},
|
|
313
|
-
|
|
314
|
-
};
|
|
315
|
-
// Only add previous steps if maxContextSteps > 0
|
|
316
|
-
if (this.options.maxContextSteps > 0 && recentSteps.length > 0) {
|
|
317
|
-
input.previousSteps = recentSteps.map((s) => ({
|
|
266
|
+
previousSteps: completedSteps.map((s) => ({
|
|
318
267
|
description: s.description,
|
|
319
268
|
output: s.output,
|
|
320
|
-
}))
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
input.contextNote =
|
|
325
|
-
"Use context_get tool to retrieve data from previous steps if needed";
|
|
326
|
-
}
|
|
327
|
-
return JSON.stringify(input, null, 2);
|
|
269
|
+
})),
|
|
270
|
+
planGoal: plan?.goal,
|
|
271
|
+
});
|
|
328
272
|
}
|
|
329
273
|
/**
|
|
330
274
|
* Compile the final result from step results.
|
|
@@ -377,12 +321,13 @@ After creating the plan, respond with a brief confirmation.`;
|
|
|
377
321
|
* Extract token usage from an agent if available.
|
|
378
322
|
*/
|
|
379
323
|
extractTokenUsage(agent) {
|
|
380
|
-
|
|
324
|
+
const agentWithUsage = agent;
|
|
325
|
+
if (!agentWithUsage.lastTokenUsage)
|
|
381
326
|
return undefined;
|
|
382
327
|
return {
|
|
383
|
-
inputTokens:
|
|
384
|
-
outputTokens:
|
|
385
|
-
totalTokens:
|
|
328
|
+
inputTokens: agentWithUsage.lastTokenUsage.input_tokens,
|
|
329
|
+
outputTokens: agentWithUsage.lastTokenUsage.output_tokens,
|
|
330
|
+
totalTokens: agentWithUsage.lastTokenUsage.total_tokens,
|
|
386
331
|
};
|
|
387
332
|
}
|
|
388
333
|
/**
|
|
@@ -119,12 +119,8 @@ class PlanStore {
|
|
|
119
119
|
const plan = this.getActivePlan();
|
|
120
120
|
if (!plan)
|
|
121
121
|
return undefined;
|
|
122
|
-
const maxIndex = plan.steps.reduce((max, s) => {
|
|
123
|
-
const match = s.id.match(/^step_(\d+)$/);
|
|
124
|
-
return match ? Math.max(max, parseInt(match[1], 10)) : max;
|
|
125
|
-
}, 0);
|
|
126
122
|
const newStep = {
|
|
127
|
-
id: `step_${
|
|
123
|
+
id: `step_${plan.steps.length + 1}`,
|
|
128
124
|
description,
|
|
129
125
|
status: "pending",
|
|
130
126
|
};
|
|
@@ -173,7 +169,7 @@ class PlanStore {
|
|
|
173
169
|
* Update the overall plan status based on step statuses.
|
|
174
170
|
*/
|
|
175
171
|
updatePlanStatus(plan) {
|
|
176
|
-
const allCompleted = plan.steps.every((s) => s.status === "completed"
|
|
172
|
+
const allCompleted = plan.steps.every((s) => s.status === "completed");
|
|
177
173
|
const anyFailed = plan.steps.some((s) => s.status === "failed");
|
|
178
174
|
const anyInProgress = plan.steps.some((s) => s.status === "in_progress");
|
|
179
175
|
let newStatus;
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./history/types";
|
|
|
9
9
|
export { anthropicTransformer, openAiTransformer, mistralTransformer, geminiTransformer, } from "./history/transformers";
|
|
10
10
|
export * from "./graph/AgentGraph";
|
|
11
11
|
export * from "./tools/Tool";
|
|
12
|
+
export * from "./mcp";
|
|
12
13
|
export * from "./viz";
|
|
13
14
|
export * from "./vectorstore";
|
|
14
15
|
export * from "./embeddings";
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,8 @@ Object.defineProperty(exports, "geminiTransformer", { enumerable: true, get: fun
|
|
|
45
45
|
__exportStar(require("./graph/AgentGraph"), exports);
|
|
46
46
|
// Tools
|
|
47
47
|
__exportStar(require("./tools/Tool"), exports);
|
|
48
|
+
// MCP (Model Context Protocol)
|
|
49
|
+
__exportStar(require("./mcp"), exports);
|
|
48
50
|
// Visualization
|
|
49
51
|
__exportStar(require("./viz"), exports);
|
|
50
52
|
// Vector Store
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Tool } from "../tools/Tool";
|
|
2
|
+
import { MCPStdioConfig, MCPHttpConfig, MCPClientOptions } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* MCPClient connects to an MCP (Model Context Protocol) server and converts its
|
|
5
|
+
* tools into agention-lib {@link Tool} instances that can be passed to any agent.
|
|
6
|
+
*
|
|
7
|
+
* Supports two transport types:
|
|
8
|
+
* - **stdio** — spawns a local process and communicates over stdin/stdout
|
|
9
|
+
* - **http** — connects to a remote MCP server over Streamable HTTP
|
|
10
|
+
*
|
|
11
|
+
* @requires @modelcontextprotocol/sdk - Install as a peer dependency:
|
|
12
|
+
* ```
|
|
13
|
+
* npm install @modelcontextprotocol/sdk
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example Stdio (local process)
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
19
|
+
* import { ClaudeAgent } from "@agentionai/agents/claude";
|
|
20
|
+
*
|
|
21
|
+
* const mcp = MCPClient.fromStdio({
|
|
22
|
+
* command: "npx",
|
|
23
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* await mcp.connect();
|
|
27
|
+
* const agent = new ClaudeAgent({
|
|
28
|
+
* id: "file-agent",
|
|
29
|
+
* name: "File Agent",
|
|
30
|
+
* description: "An agent that can work with files",
|
|
31
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
32
|
+
* tools: mcp.getTools(),
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
36
|
+
* await mcp.disconnect();
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example HTTP with static API key
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
42
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* await mcp.connect();
|
|
46
|
+
* agent.addTools(mcp.getTools());
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example HTTP with OAuth
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
52
|
+
*
|
|
53
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
54
|
+
* authProvider: myOAuthProvider, // implements OAuthClientProvider
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare class MCPClient {
|
|
59
|
+
private readonly transportConfig;
|
|
60
|
+
private readonly options;
|
|
61
|
+
private sdkClient;
|
|
62
|
+
private sdkTransport;
|
|
63
|
+
private _tools;
|
|
64
|
+
private connected;
|
|
65
|
+
private constructor();
|
|
66
|
+
/**
|
|
67
|
+
* Create an MCPClient that connects to a local MCP server process via stdio.
|
|
68
|
+
*
|
|
69
|
+
* @param config - Command and arguments to spawn the MCP server process
|
|
70
|
+
* @param options - Optional client identification options
|
|
71
|
+
*/
|
|
72
|
+
static fromStdio(config: MCPStdioConfig, options?: MCPClientOptions): MCPClient;
|
|
73
|
+
/**
|
|
74
|
+
* Create an MCPClient that connects to a remote MCP server via HTTP.
|
|
75
|
+
*
|
|
76
|
+
* @param url - Full URL to the MCP endpoint
|
|
77
|
+
* @param options - Optional client options including auth headers or OAuth provider
|
|
78
|
+
*/
|
|
79
|
+
static fromUrl(url: string, options?: MCPClientOptions & Pick<MCPHttpConfig, "headers" | "authProvider">): MCPClient;
|
|
80
|
+
/**
|
|
81
|
+
* Connect to the MCP server and discover all available tools.
|
|
82
|
+
*
|
|
83
|
+
* This method is idempotent — calling it when already connected is a no-op.
|
|
84
|
+
* Must be called before {@link getTools}.
|
|
85
|
+
*
|
|
86
|
+
* @throws If the MCP server cannot be reached or the SDK is not installed
|
|
87
|
+
*/
|
|
88
|
+
connect(): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Return all tools discovered from the MCP server as agention-lib Tool instances.
|
|
91
|
+
*
|
|
92
|
+
* Returns an empty array if {@link connect} has not been called yet.
|
|
93
|
+
* The returned tools can be passed directly to any agent via the `tools` config
|
|
94
|
+
* option or {@link BaseAgent.addTools}.
|
|
95
|
+
*/
|
|
96
|
+
getTools(): Tool<unknown>[];
|
|
97
|
+
/**
|
|
98
|
+
* Disconnect from the MCP server and release all resources.
|
|
99
|
+
*
|
|
100
|
+
* This method is idempotent — calling it when not connected is a no-op.
|
|
101
|
+
* After disconnecting, {@link getTools} returns an empty array.
|
|
102
|
+
*/
|
|
103
|
+
disconnect(): Promise<void>;
|
|
104
|
+
private wrapMcpTool;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=MCPClient.d.ts.map
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.MCPClient = void 0;
|
|
37
|
+
const Tool_1 = require("../tools/Tool");
|
|
38
|
+
/**
|
|
39
|
+
* MCPClient connects to an MCP (Model Context Protocol) server and converts its
|
|
40
|
+
* tools into agention-lib {@link Tool} instances that can be passed to any agent.
|
|
41
|
+
*
|
|
42
|
+
* Supports two transport types:
|
|
43
|
+
* - **stdio** — spawns a local process and communicates over stdin/stdout
|
|
44
|
+
* - **http** — connects to a remote MCP server over Streamable HTTP
|
|
45
|
+
*
|
|
46
|
+
* @requires @modelcontextprotocol/sdk - Install as a peer dependency:
|
|
47
|
+
* ```
|
|
48
|
+
* npm install @modelcontextprotocol/sdk
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example Stdio (local process)
|
|
52
|
+
* ```typescript
|
|
53
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
54
|
+
* import { ClaudeAgent } from "@agentionai/agents/claude";
|
|
55
|
+
*
|
|
56
|
+
* const mcp = MCPClient.fromStdio({
|
|
57
|
+
* command: "npx",
|
|
58
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
59
|
+
* });
|
|
60
|
+
*
|
|
61
|
+
* await mcp.connect();
|
|
62
|
+
* const agent = new ClaudeAgent({
|
|
63
|
+
* id: "file-agent",
|
|
64
|
+
* name: "File Agent",
|
|
65
|
+
* description: "An agent that can work with files",
|
|
66
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
67
|
+
* tools: mcp.getTools(),
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
71
|
+
* await mcp.disconnect();
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @example HTTP with static API key
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
77
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* await mcp.connect();
|
|
81
|
+
* agent.addTools(mcp.getTools());
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @example HTTP with OAuth
|
|
85
|
+
* ```typescript
|
|
86
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
87
|
+
*
|
|
88
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
89
|
+
* authProvider: myOAuthProvider, // implements OAuthClientProvider
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
class MCPClient {
|
|
94
|
+
constructor(transportConfig, options = {}) {
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
96
|
+
this.sdkClient = null;
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
98
|
+
this.sdkTransport = null;
|
|
99
|
+
this._tools = [];
|
|
100
|
+
this.connected = false;
|
|
101
|
+
this.transportConfig = transportConfig;
|
|
102
|
+
this.options = {
|
|
103
|
+
clientName: options.clientName ?? "agention-mcp-client",
|
|
104
|
+
clientVersion: options.clientVersion ?? "1.0.0",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create an MCPClient that connects to a local MCP server process via stdio.
|
|
109
|
+
*
|
|
110
|
+
* @param config - Command and arguments to spawn the MCP server process
|
|
111
|
+
* @param options - Optional client identification options
|
|
112
|
+
*/
|
|
113
|
+
static fromStdio(config, options) {
|
|
114
|
+
return new MCPClient({ type: "stdio", config }, options);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Create an MCPClient that connects to a remote MCP server via HTTP.
|
|
118
|
+
*
|
|
119
|
+
* @param url - Full URL to the MCP endpoint
|
|
120
|
+
* @param options - Optional client options including auth headers or OAuth provider
|
|
121
|
+
*/
|
|
122
|
+
static fromUrl(url, options) {
|
|
123
|
+
const config = {
|
|
124
|
+
url,
|
|
125
|
+
headers: options?.headers,
|
|
126
|
+
authProvider: options?.authProvider,
|
|
127
|
+
};
|
|
128
|
+
return new MCPClient({ type: "http", config }, options);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Connect to the MCP server and discover all available tools.
|
|
132
|
+
*
|
|
133
|
+
* This method is idempotent — calling it when already connected is a no-op.
|
|
134
|
+
* Must be called before {@link getTools}.
|
|
135
|
+
*
|
|
136
|
+
* @throws If the MCP server cannot be reached or the SDK is not installed
|
|
137
|
+
*/
|
|
138
|
+
async connect() {
|
|
139
|
+
if (this.connected)
|
|
140
|
+
return;
|
|
141
|
+
// Build module paths at runtime so tsc does not attempt to resolve them at
|
|
142
|
+
// compile time. @modelcontextprotocol/sdk is an optional peer dependency and
|
|
143
|
+
// may not be installed on the build host.
|
|
144
|
+
const pkg = "@modelcontextprotocol/sdk";
|
|
145
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
146
|
+
const { Client } = await Promise.resolve(`${`${pkg}/client/index.js`}`).then(s => __importStar(require(s)));
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
148
|
+
const sdkClient = new Client({ name: this.options.clientName, version: this.options.clientVersion }, { capabilities: {} });
|
|
149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
|
+
let transport;
|
|
151
|
+
if (this.transportConfig.type === "stdio") {
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
|
+
const { StdioClientTransport } = await Promise.resolve(`${`${pkg}/client/stdio.js`}`).then(s => __importStar(require(s)));
|
|
154
|
+
transport = new StdioClientTransport({
|
|
155
|
+
command: this.transportConfig.config.command,
|
|
156
|
+
args: this.transportConfig.config.args ?? [],
|
|
157
|
+
env: this.transportConfig.config.env,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
162
|
+
const { StreamableHTTPClientTransport } = await Promise.resolve(`${`${pkg}/client/streamableHttp.js`}`).then(s => __importStar(require(s)));
|
|
163
|
+
const { url, headers, authProvider } = this.transportConfig.config;
|
|
164
|
+
transport = new StreamableHTTPClientTransport(new URL(url), {
|
|
165
|
+
...(headers ? { requestInit: { headers } } : {}),
|
|
166
|
+
...(authProvider ? { authProvider } : {}),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
await sdkClient.connect(transport);
|
|
170
|
+
this.sdkClient = sdkClient;
|
|
171
|
+
this.sdkTransport = transport;
|
|
172
|
+
this.connected = true;
|
|
173
|
+
// Paginate through all tools
|
|
174
|
+
const allMcpTools = [];
|
|
175
|
+
let cursor;
|
|
176
|
+
do {
|
|
177
|
+
const response = await sdkClient.listTools(cursor ? { cursor } : {});
|
|
178
|
+
allMcpTools.push(...response.tools);
|
|
179
|
+
cursor = response.nextCursor;
|
|
180
|
+
} while (cursor);
|
|
181
|
+
this._tools = allMcpTools.map((mcpTool) => this.wrapMcpTool(mcpTool));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Return all tools discovered from the MCP server as agention-lib Tool instances.
|
|
185
|
+
*
|
|
186
|
+
* Returns an empty array if {@link connect} has not been called yet.
|
|
187
|
+
* The returned tools can be passed directly to any agent via the `tools` config
|
|
188
|
+
* option or {@link BaseAgent.addTools}.
|
|
189
|
+
*/
|
|
190
|
+
getTools() {
|
|
191
|
+
return this._tools;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Disconnect from the MCP server and release all resources.
|
|
195
|
+
*
|
|
196
|
+
* This method is idempotent — calling it when not connected is a no-op.
|
|
197
|
+
* After disconnecting, {@link getTools} returns an empty array.
|
|
198
|
+
*/
|
|
199
|
+
async disconnect() {
|
|
200
|
+
if (!this.connected)
|
|
201
|
+
return;
|
|
202
|
+
try {
|
|
203
|
+
if (this.transportConfig.type === "http" && this.sdkTransport) {
|
|
204
|
+
await this.sdkTransport.terminateSession?.();
|
|
205
|
+
}
|
|
206
|
+
if (this.sdkClient) {
|
|
207
|
+
await this.sdkClient.close();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
this.sdkClient = null;
|
|
212
|
+
this.sdkTransport = null;
|
|
213
|
+
this._tools = [];
|
|
214
|
+
this.connected = false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
wrapMcpTool(mcpTool) {
|
|
218
|
+
const inputSchema = {
|
|
219
|
+
type: "object",
|
|
220
|
+
properties: mcpTool.inputSchema?.properties ?? {},
|
|
221
|
+
required: mcpTool.inputSchema?.required,
|
|
222
|
+
};
|
|
223
|
+
return new Tool_1.Tool({
|
|
224
|
+
name: mcpTool.name,
|
|
225
|
+
description: mcpTool.description ?? mcpTool.name,
|
|
226
|
+
inputSchema,
|
|
227
|
+
execute: async (input) => {
|
|
228
|
+
if (!this.connected || !this.sdkClient) {
|
|
229
|
+
throw new Error(`MCPClient: Cannot execute tool "${mcpTool.name}" — client is not connected`);
|
|
230
|
+
}
|
|
231
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
232
|
+
let result;
|
|
233
|
+
try {
|
|
234
|
+
result = await this.sdkClient.callTool({
|
|
235
|
+
name: mcpTool.name,
|
|
236
|
+
arguments: input,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
241
|
+
throw new Error(`MCPClient: Tool "${mcpTool.name}" execution failed: ${message}`);
|
|
242
|
+
}
|
|
243
|
+
// Extract text content items from MCP result
|
|
244
|
+
if (result?.content && Array.isArray(result.content)) {
|
|
245
|
+
const textItems = result.content
|
|
246
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
247
|
+
.filter((item) => item.type === "text")
|
|
248
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
249
|
+
.map((item) => item.text);
|
|
250
|
+
if (textItems.length > 0) {
|
|
251
|
+
return textItems.length === 1 ? textItems[0] : textItems.join("\n");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Fall back to structured content or full JSON serialization
|
|
255
|
+
if (result?.structuredContent !== undefined) {
|
|
256
|
+
return result.structuredContent;
|
|
257
|
+
}
|
|
258
|
+
return JSON.stringify(result ?? null);
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
exports.MCPClient = MCPClient;
|
|
264
|
+
//# sourceMappingURL=MCPClient.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP (Model Context Protocol) support for agention-lib.
|
|
3
|
+
*
|
|
4
|
+
* Connects to any MCP server — local stdio processes or remote HTTP endpoints —
|
|
5
|
+
* and exposes their tools as agention-lib {@link Tool} instances compatible with
|
|
6
|
+
* all agent types (ClaudeAgent, OpenAiAgent, MistralAgent, GeminiAgent).
|
|
7
|
+
*
|
|
8
|
+
* @requires @modelcontextprotocol/sdk - Optional peer dependency, install when needed:
|
|
9
|
+
* ```
|
|
10
|
+
* npm install @modelcontextprotocol/sdk
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* @example Stdio (local process)
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { MCPClient, ClaudeAgent } from "@agentionai/agents";
|
|
16
|
+
*
|
|
17
|
+
* const mcp = MCPClient.fromStdio({
|
|
18
|
+
* command: "npx",
|
|
19
|
+
* args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* await mcp.connect();
|
|
23
|
+
*
|
|
24
|
+
* const agent = new ClaudeAgent({
|
|
25
|
+
* id: "file-agent",
|
|
26
|
+
* name: "File Agent",
|
|
27
|
+
* description: "An agent that can work with files",
|
|
28
|
+
* apiKey: process.env.ANTHROPIC_API_KEY!,
|
|
29
|
+
* tools: mcp.getTools(),
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const result = await agent.execute("List the files in /tmp");
|
|
33
|
+
* await mcp.disconnect();
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example HTTP with static API key
|
|
37
|
+
* ```typescript
|
|
38
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
39
|
+
*
|
|
40
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
41
|
+
* headers: { Authorization: "Bearer my-api-key" },
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* await mcp.connect();
|
|
45
|
+
* agent.addTools(mcp.getTools());
|
|
46
|
+
* await mcp.disconnect();
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example HTTP with OAuth
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { MCPClient } from "@agentionai/agents";
|
|
52
|
+
* import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
53
|
+
*
|
|
54
|
+
* // Implement OAuthClientProvider from the MCP SDK
|
|
55
|
+
* const myOAuthProvider: OAuthClientProvider = { ... };
|
|
56
|
+
*
|
|
57
|
+
* const mcp = MCPClient.fromUrl("https://my-mcp-server.com/mcp", {
|
|
58
|
+
* authProvider: myOAuthProvider,
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export { MCPClient } from "./MCPClient";
|
|
63
|
+
export type { MCPStdioConfig, MCPHttpConfig, MCPClientOptions } from "./types";
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|