Skip to content

Commit fea5336

Browse files
authored
fix: improve generic actor-call tool and hide it behind beta flag (#164)
fix generic actorl-call and move it behind beta flag ?beta=1 or --beta
1 parent 8e5ce12 commit fea5336

File tree

12 files changed

+94
-20
lines changed

12 files changed

+94
-20
lines changed

src/input.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,8 @@ export function processInput(originalInput: Partial<Input>): Input {
2929
} else {
3030
input.enableAddingActors = input.enableAddingActors === true || input.enableAddingActors === 'true';
3131
}
32+
33+
// If beta present, set input.beta to true
34+
input.beta = input.beta !== undefined && (input.beta !== false && input.beta !== 'false');
3235
return input;
3336
}

src/mcp/server.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
SERVER_NAME,
2424
SERVER_VERSION,
2525
} from '../const.js';
26-
import { addRemoveTools, callActorGetDataset, defaultTools, getActorsAsTools } from '../tools/index.js';
26+
import { addRemoveTools, betaTools, callActorGetDataset, defaultTools, getActorsAsTools } from '../tools/index.js';
2727
import { actorNameToToolName } from '../tools/utils.js';
2828
import type { ActorMcpTool, ActorTool, HelperTool, ToolEntry } from '../types.js';
2929
import { connectMCPClient } from './client.js';
@@ -33,6 +33,7 @@ import { processParamsGetTools } from './utils.js';
3333
type ActorsMcpServerOptions = {
3434
enableAddingActors?: boolean;
3535
enableDefaultActors?: boolean;
36+
enableBeta?: boolean; // Enable beta features
3637
};
3738

3839
type ToolsChangedHandler = (toolNames: string[]) => void;
@@ -51,6 +52,7 @@ export class ActorsMcpServer {
5152
this.options = {
5253
enableAddingActors: options.enableAddingActors ?? true,
5354
enableDefaultActors: options.enableDefaultActors ?? true, // Default to true for backward compatibility
55+
enableBeta: options.enableBeta ?? false, // Disabled by default
5456
};
5557
this.server = new Server(
5658
{
@@ -76,6 +78,10 @@ export class ActorsMcpServer {
7678
this.enableDynamicActorTools();
7779
}
7880

81+
if (this.options.enableBeta) {
82+
this.upsertTools(betaTools, false);
83+
}
84+
7985
// Initialize automatically for backward compatibility
8086
this.initialize().catch((error) => {
8187
log.error('Failed to initialize server:', error);

src/mcp/utils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
22
import { parse } from 'node:querystring';
33

44
import { processInput } from '../input.js';
5-
import { addRemoveTools, getActorsAsTools } from '../tools/index.js';
5+
import { addRemoveTools, betaTools, getActorsAsTools } from '../tools/index.js';
66
import type { Input, ToolEntry } from '../types.js';
77
import { MAX_TOOL_NAME_LENGTH, SERVER_ID_LENGTH } from './const.js';
88

@@ -50,6 +50,9 @@ export async function processParamsGetTools(url: string, apifyToken: string) {
5050
if (input.enableAddingActors) {
5151
tools.push(...addRemoveTools);
5252
}
53+
if (input.beta) {
54+
tools.push(...betaTools);
55+
}
5356
return tools;
5457
}
5558

src/stdio.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ interface CliArgs {
3636
enableAddingActors: boolean;
3737
/** @deprecated */
3838
enableActorAutoLoading: boolean;
39+
beta: boolean;
3940
}
4041

4142
// Configure logging, set to ERROR
@@ -60,6 +61,11 @@ const argv = yargs(hideBin(process.argv))
6061
hidden: true,
6162
describe: 'Deprecated: use enable-adding-actors instead',
6263
})
64+
.option('beta', {
65+
type: 'boolean',
66+
default: false,
67+
describe: 'Enable beta features',
68+
})
6369
.help('help')
6470
.alias('h', 'help')
6571
.version(false)
@@ -73,6 +79,7 @@ const argv = yargs(hideBin(process.argv))
7379
const enableAddingActors = argv.enableAddingActors && argv.enableActorAutoLoading;
7480
const actors = argv.actors as string || '';
7581
const actorList = actors ? actors.split(',').map((a: string) => a.trim()) : [];
82+
const enableBeta = argv.beta;
7683

7784
// Validate environment
7885
if (!process.env.APIFY_TOKEN) {
@@ -81,7 +88,7 @@ if (!process.env.APIFY_TOKEN) {
8188
}
8289

8390
async function main() {
84-
const mcpServer = new ActorsMcpServer({ enableAddingActors, enableDefaultActors: false });
91+
const mcpServer = new ActorsMcpServer({ enableAddingActors, enableDefaultActors: false, enableBeta });
8592
const tools = await getActorsAsTools(actorList.length ? actorList : defaults.actors, process.env.APIFY_TOKEN as string);
8693
mcpServer.upsertTools(tools);
8794

src/tools/actor.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,9 @@ export const getActor: ToolEntry = {
292292

293293
const callActorArgs = z.object({
294294
actor: z.string()
295-
.describe('The name of the Actor to call.'),
295+
.describe('The name of the Actor to call. For example, "apify/instagram-scraper".'),
296296
input: z.object({}).passthrough()
297-
.describe('The input JSON to pass to the Actor.'),
297+
.describe('The input JSON to pass to the Actor. For example, {"query": "apify", "maxItems": 10}.'),
298298
callOptions: z.object({
299299
memory: z.number().optional(),
300300
timeout: z.number().optional(),
@@ -307,7 +307,7 @@ export const callActor: ToolEntry = {
307307
tool: {
308308
name: HelperTools.ACTOR_CALL,
309309
actorFullName: HelperTools.ACTOR_CALL,
310-
description: `Call Actor and get dataset results. Call without input and result response with requred input properties. Actor MUST be added before calling, use ${HelperTools.ACTOR_ADD} tool before.`,
310+
description: `Call an Actor and get the Actor run results. If you are not sure about the Actor input, you MUST get the Actor details first, which also returns the input schema using ${HelperTools.ACTOR_GET_DETAILS}. The Actor MUST be added before calling; use the ${HelperTools.ACTOR_ADD} tool first. By default, the Apify MCP server makes newly added Actors available as tools for calling. Use this tool ONLY if you cannot call the newly added tool directly, and NEVER call this tool before first trying to call the tool directly. For example, when you add an Actor "apify/instagram-scraper" using the ${HelperTools.ACTOR_ADD} tool, the Apify MCP server will add a new tool ${actorNameToToolName('apify/instagram-scraper')} that you can call directly. If calling this tool does not work, then and ONLY then MAY you use this tool as a backup.`,
311311
inputSchema: zodToJsonSchema(callActorArgs),
312312
ajvValidate: ajv.compile(zodToJsonSchema(callActorArgs)),
313313
call: async (toolArgs) => {
@@ -316,12 +316,12 @@ export const callActor: ToolEntry = {
316316

317317
const actors = apifyMcpServer.listActorToolNames();
318318
if (!actors.includes(actorName)) {
319-
const toolsText = actors.length > 0 ? `Available Actors are: ${actors.join(', ')}` : 'Not added Actors yet.';
319+
const toolsText = actors.length > 0 ? `Available Actors are: ${actors.join(', ')}` : 'No Actors have been added yet.';
320320
if (apifyMcpServer.tools.has(HelperTools.ACTOR_ADD)) {
321321
return {
322322
content: [{
323323
type: 'text',
324-
text: `Actor '${actorName}' is not added. Add it with tool '${HelperTools.ACTOR_ADD}'. ${toolsText}`,
324+
text: `Actor '${actorName}' is not added. Add it with the '${HelperTools.ACTOR_ADD}' tool. ${toolsText}`,
325325
}],
326326
};
327327
}

src/tools/get-actor-details.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const getActorDetailsTool: ToolEntry = {
4848
name: HelperTools.ACTOR_GET_DETAILS,
4949
description: `Retrieve information about an Actor by its ID or full name.
5050
The Actor name is always composed of "username/name", for example, "apify/rag-web-browser".
51-
This tool returns information about the Actor, including whether it is public or deprecated, when it was created or modified, the categories in which the Actor is listed, a description, a README (the Actor's documentation), the input schema, and usage statisticssuch as how many users are using it and the number of failed runs of the Actor.
51+
This tool returns information about the Actor, including whether it is public or deprecated, when it was created or modified, the categories in which the Actor is listed, a description, a README (the Actor's documentation), the input schema, and usage statistics - such as how many users are using it and the number of failed runs of the Actor.
5252
For example, use this tool when a user wants to know more about a specific Actor or wants to use optional or advanced parameters of the Actor that are not listed in the default Actor tool input schema - so you know the details and how to pass them.`,
5353
inputSchema: zodToJsonSchema(getActorDetailsToolArgsSchema),
5454
ajvValidate: ajv.compile(zodToJsonSchema(getActorDetailsToolArgsSchema)),

src/tools/helpers.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ A tool is an Actor or MCP server that can be called by the user.
4545
Do not execute the tool, only add it and list it in the available tools.
4646
For example, when a user wants to scrape a website, first search for relevant Actors
4747
using ${HelperTools.STORE_SEARCH} tool, and once the user selects one they want to use,
48-
add it as a tool to the Apify MCP server.
49-
If added tools is not available, use generic tool ${HelperTools.ACTOR_CALL} to call added Actor directly.`,
48+
add it as a tool to the Apify MCP server.`,
5049
inputSchema: zodToJsonSchema(addToolArgsSchema),
5150
ajvValidate: ajv.compile(zodToJsonSchema(addToolArgsSchema)),
5251
// TODO: I don't like that we are passing apifyMcpServer and mcpServer to the tool

src/tools/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@ export const defaultTools = [
2020
// getUserRunsList,
2121
// getUserDatasetsList,
2222
// getUserKeyValueStoresList,
23-
callActor,
2423
getActorDetailsTool,
2524
helpTool,
2625
searchActors,
2726
searchApifyDocsTool,
2827
fetchApifyDocsTool,
2928
];
3029

30+
export const betaTools = [
31+
callActor,
32+
];
33+
3134
export const addRemoveTools = [
3235
addTool,
3336
// removeTool,

src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ export type Input = {
223223
maxActorMemoryBytes?: number;
224224
debugActor?: string;
225225
debugActorInput?: unknown;
226+
/** Enable beta features flag */
227+
beta?: boolean | string;
226228
};
227229

228230
// Utility type to get a union of values from an object type

tests/helpers.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { HelperTools } from '../src/const.js';
99
export interface McpClientOptions {
1010
actors?: string[];
1111
enableAddingActors?: boolean;
12+
enableBeta?: boolean; // Optional, used for beta features
1213
}
1314

1415
export async function createMcpSseClient(
@@ -19,13 +20,16 @@ export async function createMcpSseClient(
1920
throw new Error('APIFY_TOKEN environment variable is not set.');
2021
}
2122
const url = new URL(serverUrl);
22-
const { actors, enableAddingActors } = options || {};
23+
const { actors, enableAddingActors, enableBeta } = options || {};
2324
if (actors) {
2425
url.searchParams.append('actors', actors.join(','));
2526
}
2627
if (enableAddingActors !== undefined) {
2728
url.searchParams.append('enableAddingActors', enableAddingActors.toString());
2829
}
30+
if (enableBeta !== undefined) {
31+
url.searchParams.append('beta', enableBeta.toString());
32+
}
2933

3034
const transport = new SSEClientTransport(
3135
url,
@@ -55,13 +59,16 @@ export async function createMcpStreamableClient(
5559
throw new Error('APIFY_TOKEN environment variable is not set.');
5660
}
5761
const url = new URL(serverUrl);
58-
const { actors, enableAddingActors } = options || {};
62+
const { actors, enableAddingActors, enableBeta } = options || {};
5963
if (actors) {
6064
url.searchParams.append('actors', actors.join(','));
6165
}
6266
if (enableAddingActors !== undefined) {
6367
url.searchParams.append('enableAddingActors', enableAddingActors.toString());
6468
}
69+
if (enableBeta !== undefined) {
70+
url.searchParams.append('beta', enableBeta.toString());
71+
}
6572

6673
const transport = new StreamableHTTPClientTransport(
6774
url,
@@ -89,14 +96,17 @@ export async function createMcpStdioClient(
8996
if (!process.env.APIFY_TOKEN) {
9097
throw new Error('APIFY_TOKEN environment variable is not set.');
9198
}
92-
const { actors, enableAddingActors } = options || {};
99+
const { actors, enableAddingActors, enableBeta } = options || {};
93100
const args = ['dist/stdio.js'];
94101
if (actors) {
95102
args.push('--actors', actors.join(','));
96103
}
97104
if (enableAddingActors !== undefined) {
98105
args.push('--enable-adding-actors', enableAddingActors.toString());
99106
}
107+
if (enableBeta !== undefined) {
108+
args.push('--beta', enableBeta.toString());
109+
}
100110
const transport = new StdioClientTransport({
101111
command: 'node',
102112
args,

0 commit comments

Comments
 (0)