Skip to content

Commit 4f28d9b

Browse files
authored
fix: Provide better output. Fix datasetId in examples (#293)
* fix: Provide better output. Fix datasetId in examples
1 parent f9a23e1 commit 4f28d9b

File tree

6 files changed

+28
-27
lines changed

6 files changed

+28
-27
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The Apify Model Context Protocol (MCP) server at [**mcp.apify.com**](https://mcp
2626
>
2727
> It supports OAuth, so you can connect from clients like Claude.ai or Visual Studio Code with just the URL.
2828
29-
![Apify-MCP-server](docs/actors-mcp-server.png)
29+
![Apify-MCP-server](https://raw.githubusercontent.com/apify/apify-mcp-server/refs/heads/master/docs/apify-mcp-server.png)
3030

3131
## Table of Contents
3232
- [🌐 Introducing the Apify MCP server](#-introducing-the-apify-mcp-server)
File renamed without changes.

src/tools/actor.ts

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,10 @@ const callActorArgs = z.object({
306306
actor: z.string()
307307
.describe('The name of the Actor to call. For example, "apify/rag-web-browser".'),
308308
step: z.enum(['info', 'call'])
309-
.default('info')
310309
.describe(`Step to perform: "info" to get Actor details and input schema (required first step), "call" to run the Actor (only after getting info).`),
311310
input: z.object({}).passthrough()
312311
.optional()
313-
.describe(`The input JSON to pass to the Actor. For example, {"query": "apify", "maxResults": 5, "outputFormats": ["markdown"]}. Required only when step is "call".`),
312+
.describe(`The input JSON to pass to the Actor. For example, {"query": "apify", "maxResults": 5}. Must be used only when step="call".`),
314313
callOptions: z.object({
315314
memory: z.number()
316315
.min(128, 'Memory must be at least 128 MB')
@@ -369,6 +368,9 @@ EXAMPLES:
369368
const { args, apifyToken, progressTracker, extra, apifyMcpServer } = toolArgs;
370369
const { actor: actorName, step, input, callOptions } = callActorArgs.parse(args);
371370

371+
// If input is provided but step is not "call", we assume the user wants to call the Actor
372+
const performStep = input && step !== 'call' ? 'call' : step;
373+
372374
// Parse special format: actor:tool
373375
const mcpToolMatch = actorName.match(/^(.+):(.+)$/);
374376
let baseActorName = actorName;
@@ -382,7 +384,7 @@ EXAMPLES:
382384
// For definition resolution we always use token-based client; Skyfire is only for actual Actor runs
383385
const apifyClientForDefinition = new ApifyClient({ token: apifyToken });
384386
// Resolve MCP server URL
385-
const needsMcpUrl = mcpToolName !== undefined || step === 'info';
387+
const needsMcpUrl = mcpToolName !== undefined || performStep === 'info';
386388
const mcpServerUrlOrFalse = needsMcpUrl ? await getActorMcpUrlCached(baseActorName, apifyClientForDefinition) : false;
387389
const isActorMcpServer = mcpServerUrlOrFalse && typeof mcpServerUrlOrFalse === 'string';
388390

@@ -392,7 +394,7 @@ EXAMPLES:
392394
}
393395

394396
try {
395-
if (step === 'info') {
397+
if (performStep === 'info') {
396398
if (isActorMcpServer) {
397399
// MCP server: list tools
398400
const mcpServerUrl = mcpServerUrlOrFalse;
@@ -419,19 +421,16 @@ EXAMPLES:
419421
return buildMCPResponse([`Actor information for '${baseActorName}' was not found. Please check the Actor ID or name and ensure the Actor exists.`]);
420422
}
421423
const content = [
422-
// TODO: update result to say: this is result of info step, you must now call again with step=call and proper input
423-
{ type: 'text', text: `Input schema: \n${JSON.stringify(details.inputSchema, null, 0)}` },
424+
`Actor name: ${actorName}`,
425+
`Input schema: \n${JSON.stringify(details.inputSchema, null, 0)}`,
426+
`To run Actor, use step="call" with Actor name format: "${actorName}"`,
424427
];
425-
/**
426-
* Add Skyfire instructions also in the info step since clients are most likely truncating the long tool description of the call-actor.
427-
*/
428+
// Add Skyfire instructions also in the info performStep since clients are most likely truncating
429+
// the long tool description of the call-actor.
428430
if (apifyMcpServer.options.skyfireMode) {
429-
content.push({
430-
type: 'text',
431-
text: SKYFIRE_TOOL_INSTRUCTIONS,
432-
});
431+
content.push(SKYFIRE_TOOL_INSTRUCTIONS);
433432
}
434-
return { content };
433+
return buildMCPResponse(content);
435434
}
436435
}
437436

@@ -496,12 +495,14 @@ EXAMPLES:
496495

497496
if (!actor.tool.ajvValidate(input)) {
498497
const { errors } = actor.tool.ajvValidate;
498+
const content = [
499+
`Input validation failed for Actor '${actorName}'. Please ensure your input matches the Actor's input schema.`,
500+
`Input schema:\n${JSON.stringify(actor.tool.inputSchema)}`,
501+
];
499502
if (errors && errors.length > 0) {
500-
return buildMCPResponse([
501-
`Input validation failed for Actor '${actorName}': ${errors.map((e) => e.message).join(', ')}`,
502-
`Input schema:\n${JSON.stringify(actor.tool.inputSchema)}`,
503-
]);
503+
content.push(`Validation errors: ${errors.map((e) => e.message).join(', ')}`);
504504
}
505+
return buildMCPResponse(content);
505506
}
506507

507508
const callResult = await callActorGetDataset(
@@ -523,7 +524,7 @@ EXAMPLES:
523524

524525
return { content };
525526
} catch (error) {
526-
log.error('Failed to call Actor', { error, actorName, step });
527+
log.error('Failed to call Actor', { error, actorName, performStep });
527528
return buildMCPResponse([`Failed to call Actor '${actorName}': ${error instanceof Error ? error.message : String(error)}`]);
528529
}
529530
},

src/tools/dataset.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ USAGE:
5555
- Use when you need dataset metadata to understand its structure before fetching items.
5656
5757
USAGE EXAMPLES:
58-
- user_input: Show info for dataset 8TtYhCwKzQeQk7dJx
58+
- user_input: Show info for dataset xyz123
5959
- user_input: What fields does username~my-dataset have?`,
6060
inputSchema: zodToJsonSchema(getDatasetArgs),
6161
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetArgs)),
@@ -90,7 +90,7 @@ USAGE:
9090
- Use when you need to read data from a dataset (all items or only selected fields).
9191
9292
USAGE EXAMPLES:
93-
- user_input: Get first 100 items from dataset 8TtYhCwKzQeQk7dJx
93+
- user_input: Get first 100 items from dataset abd123
9494
- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`,
9595
inputSchema: zodToJsonSchema(getDatasetItemsArgs),
9696
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetItemsArgs)),
@@ -152,7 +152,7 @@ USAGE:
152152
- Use when you need to infer the structure of dataset items for downstream processing or validation.
153153
154154
USAGE EXAMPLES:
155-
- user_input: Generate schema for dataset 8TtYhCwKzQeQk7dJx using 10 items
155+
- user_input: Generate schema for dataset 34das2 using 10 items
156156
- user_input: Show schema of username~my-dataset (clean items only)`,
157157
inputSchema: zodToJsonSchema(getDatasetSchemaArgs),
158158
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetSchemaArgs)),

src/tools/get-actor-output.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ USAGE:
8282
USAGE EXAMPLES:
8383
- user_input: Get data of my last Actor run
8484
- user_input: Get number_of_likes from my dataset
85-
- user_input: Return only crawl.statusCode and url from dataset 8TtYhCwKzQeQk7dJx
85+
- user_input: Return only crawl.statusCode and url from dataset aab123
8686
8787
Note: This tool is automatically included if the Apify MCP Server is configured with any Actor tools (e.g., "apify-slash-rag-web-browser") or tools that can interact with Actors (e.g., "call-actor", "add-actor").`,
8888
inputSchema: zodToJsonSchema(getActorOutputArgs),

src/tools/key_value_store.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ USAGE:
2828
2929
USAGE EXAMPLES:
3030
- user_input: Show info for key-value store username~my-store
31-
- user_input: Get details for store 8TtYhCwKzQeQk7dJx`,
31+
- user_input: Get details for store adb123`,
3232
inputSchema: zodToJsonSchema(getKeyValueStoreArgs),
3333
ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreArgs)),
3434
call: async (toolArgs) => {
@@ -71,7 +71,7 @@ USAGE:
7171
7272
USAGE EXAMPLES:
7373
- user_input: List first 100 keys in store username~my-store
74-
- user_input: Continue listing keys in store 8TtYhCwKzQeQk7dJx from key data.json`,
74+
- user_input: Continue listing keys in store a123 from key data.json`,
7575
inputSchema: zodToJsonSchema(getKeyValueStoreKeysArgs),
7676
ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreKeysArgs)),
7777
call: async (toolArgs) => {
@@ -111,7 +111,7 @@ USAGE:
111111
- Use when you need to retrieve a specific record (JSON, text, or binary) from a store.
112112
113113
USAGE EXAMPLES:
114-
- user_input: Get record INPUT from store 8TtYhCwKzQeQk7dJx
114+
- user_input: Get record INPUT from store abc123
115115
- user_input: Get record data.json from store username~my-store`,
116116
inputSchema: zodToJsonSchema(getKeyValueStoreRecordArgs),
117117
ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreRecordArgs)),

0 commit comments

Comments
 (0)