Skip to content

Commit 703db22

Browse files
committed
feat: add call-actor tool
1 parent b2c31b6 commit 703db22

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

src/const.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const USER_AGENT_ORIGIN = 'Origin/mcp-server';
1717

1818
export enum HelperTools {
1919
ACTOR_ADD = 'add-actor',
20+
ACTOR_CALL = 'call-actor',
2021
ACTOR_GET = 'get-actor',
2122
ACTOR_GET_DETAILS = 'get-actor-details',
2223
ACTOR_REMOVE = 'remove-actor',

src/tools/actor.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,79 @@ export const getActor: ToolEntry = {
261261
},
262262
} as InternalTool,
263263
};
264+
265+
const callActorArgs = z.object({
266+
actorName: z.string()
267+
.describe('The name of the Actor to call.'),
268+
input: z.any()
269+
.describe('The input to pass to the Actor.'),
270+
callOptions: z.object({
271+
memory: z.number().optional(),
272+
timeout: z.number().optional(),
273+
}).optional()
274+
.describe('Optional call options for the Actor.'),
275+
});
276+
277+
export const callActor: ToolEntry = {
278+
type: 'internal',
279+
tool: {
280+
name: HelperTools.ACTOR_CALL,
281+
actorFullName: HelperTools.ACTOR_CALL,
282+
description: 'Call Actor and get dataset id. Call without input and result response with requred input properties.',
283+
inputSchema: zodToJsonSchema(callActorArgs),
284+
ajvValidate: ajv.compile(zodToJsonSchema(callActorArgs)),
285+
call: async (toolArgs) => {
286+
const { args, apifyToken } = toolArgs;
287+
const { actorName, input, callOptions } = callActorArgs.parse(args);
288+
if (!apifyToken) {
289+
throw new Error('APIFY_TOKEN environment variable is not set.');
290+
}
291+
try {
292+
// FIXME: Bug, every call add "**REQUIRED**" to the description of the input properties
293+
const [actor] = await getActorsAsTools([actorName], apifyToken);
294+
295+
if (!actor) {
296+
return {
297+
content: [
298+
{ type: 'text', text: `Actor '${actorName}' not found.` },
299+
],
300+
};
301+
}
302+
303+
if (!actor.tool.ajvValidate(input)) {
304+
const { errors } = actor.tool.ajvValidate;
305+
if (errors && errors.length > 0) {
306+
return {
307+
content: [
308+
{ type: 'text', text: `Input validation failed for Actor '${actorName}': ${errors.map((e) => e.message).join(', ')}` },
309+
{ type: 'json', json: actor.tool.inputSchema },
310+
],
311+
};
312+
}
313+
}
314+
315+
const { actorRun, datasetInfo, items } = await callActorGetDataset(
316+
actorName,
317+
input,
318+
apifyToken,
319+
callOptions,
320+
);
321+
322+
return {
323+
content: [
324+
{ type: 'text', text: `Actor run ID: ${actorRun.id}` },
325+
{ type: 'text', text: `Dataset ID: ${datasetInfo?.id}` },
326+
{ type: 'text', text: `Items count: ${items.total}` },
327+
],
328+
};
329+
} catch (error) {
330+
console.error(`Error calling Actor: ${error}`);
331+
return {
332+
content: [
333+
{ type: 'text', text: `Error calling Actor: ${error instanceof Error ? error.message : String(error)}` },
334+
],
335+
};
336+
}
337+
},
338+
},
339+
};

src/tools/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Import specific tools that are being used
2-
import { callActorGetDataset, getActor, getActorsAsTools } from './actor.js';
2+
import { callActor, callActorGetDataset, getActor, getActorsAsTools } from './actor.js';
33
import { actorDefinitionTool } from './build.js';
44
import { getDataset, getDatasetItems } from './dataset.js';
55
import { getUserDatasetsList } from './dataset_collection.js';
@@ -13,6 +13,7 @@ import { searchActors } from './store_collection.js';
1313
export const defaultTools = [
1414
abortActorRun,
1515
actorDefinitionTool,
16+
callActor,
1617
getActor,
1718
getActorLog,
1819
getActorRun,

0 commit comments

Comments
 (0)