@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.
@@ -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
- // Record error to stop after in-flight steps complete
205
+ // Stop if configured to do so
212
206
  if (this.options.stopOnFailure) {
213
- stopError = new Error(`Step ${stepNumber} failed: ${errorMessage}`);
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
- // Always wait for all in-flight promises to finish before returning/throwing
223
+ // Wait for all remaining promises to complete
230
224
  if (activePromises.size > 0) {
231
- await Promise.allSettled(activePromises.values());
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
- CRITICAL: You can create a maximum of ${this.options.maxSteps} steps. Plan accordingly and prioritize the most important subtasks.
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
- STRATEGY FOR AVOIDING RATE LIMITS:
282
- - If analyzing multiple files: Create one step per file
283
- - If processing a list: Create one step per item
284
- - If researching: Create steps for: 1) identify what to research, 2) research item 1, 3) research item 2, etc.
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
- // Limit context to prevent token overflow
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
- planGoal: plan?.goal,
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
- input.contextNote = `Showing last ${recentSteps.length} of ${completedSteps.length} completed steps`;
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
- if (!agent.lastTokenUsage)
324
+ const agentWithUsage = agent;
325
+ if (!agentWithUsage.lastTokenUsage)
381
326
  return undefined;
382
327
  return {
383
- inputTokens: agent.lastTokenUsage.input_tokens,
384
- outputTokens: agent.lastTokenUsage.output_tokens,
385
- totalTokens: agent.lastTokenUsage.total_tokens,
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_${maxIndex + 1}`,
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" || s.status === "skipped");
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