Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@ Here is an overview list of all the tools provided by the Apify MCP Server.

> The `get-actor-output` tool is automatically included with any Actor-related tool, such as `call-actor`, `add-actor`, or any specific Actor tool like `apify-slash-rag-web-browser`. When you call an Actor - either through the `call-actor` tool or directly via an Actor tool (e.g., `apify-slash-rag-web-browser`) - you receive a preview of the output. The preview depends on the Actor's output format and length; for some Actors and runs, it may include the entire output, while for others, only a limited version is returned to avoid overwhelming the LLM. To retrieve the full output of an Actor run, use the `get-actor-output` tool (supports limit, offset, and field filtering) with the `datasetId` provided by the Actor call.

### Tool annotations

All tools include metadata annotations to help MCP clients and LLMs understand tool behavior:

- **`title`**: Short display name for the tool (e.g., "Search Actors", "Call Actor", "apify/rag-web-browser")
- **`readOnlyHint`**: `true` for tools that only read data without modifying state (e.g., `get-dataset`, `fetch-actor-details`)
- **`openWorldHint`**: `true` for tools that access external resources outside the Apify platform (e.g., `call-actor` executes external Actors, `get-html-skeleton` scrapes external websites). Tools that interact only with the Apify platform (like `search-actors` or `fetch-apify-docs`) do not have this hint.

### Tools configuration

The `tools` configuration parameter is used to specify loaded tools - either categories or specific tools directly, and Apify Actors. For example, `tools=storage,runs` loads two categories; `tools=add-actor` loads just one tool.
Expand Down
4 changes: 2 additions & 2 deletions src/mcp/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,8 @@ export class ActorsMcpServer {
}
} else {
// No skyfire mode - store tools as-is
for (const wrap of tools) {
this.tools.set(wrap.name, wrap);
for (const tool of tools) {
this.tools.set(tool.name, tool);
}
}
if (shouldNotifyToolsChangedHandler) this.notifyToolsChangedHandler();
Expand Down
8 changes: 8 additions & 0 deletions src/tools/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ Actor description: ${actorDefinitionPruned.description}`;
inputSchema: inputSchema as ToolInputSchema,
ajvValidate,
memoryMbytes,
annotations: {
title: actorDefinitionPruned.actorFullName,
openWorldHint: true,
},
});
}
return tools;
Expand Down Expand Up @@ -361,6 +365,10 @@ EXAMPLES:
// Additional props true to allow skyfire-pay-id
additionalProperties: true,
}),
annotations: {
title: 'Call Actor',
openWorldHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken, progressTracker, extra, apifyMcpServer } = toolArgs;
const { actor: actorName, step, input, callOptions } = callActorArgs.parse(args);
Expand Down
4 changes: 4 additions & 0 deletions src/tools/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ export const actorDefinitionTool: ToolEntry = {
+ `Limit the length of the README if needed.`,
inputSchema: zodToJsonSchema(getActorDefinitionArgsSchema) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getActorDefinitionArgsSchema)),
annotations: {
title: 'Get Actor definition',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;

Expand Down
12 changes: 12 additions & 0 deletions src/tools/dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ USAGE EXAMPLES:
- user_input: What fields does username~my-dataset have?`,
inputSchema: zodToJsonSchema(getDatasetArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetArgs)),
annotations: {
title: 'Get dataset',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getDatasetArgs.parse(args);
Expand Down Expand Up @@ -89,6 +93,10 @@ USAGE EXAMPLES:
- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`,
inputSchema: zodToJsonSchema(getDatasetItemsArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetItemsArgs)),
annotations: {
title: 'Get dataset items',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getDatasetItemsArgs.parse(args);
Expand Down Expand Up @@ -148,6 +156,10 @@ USAGE EXAMPLES:
- user_input: Show schema of username~my-dataset (clean items only)`,
inputSchema: zodToJsonSchema(getDatasetSchemaArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetSchemaArgs)),
annotations: {
title: 'Get dataset schema',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getDatasetSchemaArgs.parse(args);
Expand Down
4 changes: 4 additions & 0 deletions src/tools/dataset_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ USAGE EXAMPLES:
- user_input: List unnamed datasets`,
inputSchema: zodToJsonSchema(getUserDatasetsListArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getUserDatasetsListArgs)),
annotations: {
title: 'Get user datasets list',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getUserDatasetsListArgs.parse(args);
Expand Down
4 changes: 4 additions & 0 deletions src/tools/fetch-actor-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ USAGE EXAMPLES:
- user_input: What is the pricing for apify/instagram-scraper?`,
inputSchema: zodToJsonSchema(fetchActorDetailsToolArgsSchema) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(fetchActorDetailsToolArgsSchema)),
annotations: {
title: 'Fetch Actor details',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = fetchActorDetailsToolArgsSchema.parse(args);
Expand Down
4 changes: 4 additions & 0 deletions src/tools/fetch-apify-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ USAGE EXAMPLES:
- user_input: Fetch https://docs.apify.com/academy`,
inputSchema: zodToJsonSchema(fetchApifyDocsToolArgsSchema) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(fetchApifyDocsToolArgsSchema)),
annotations: {
title: 'Fetch Apify docs',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args } = toolArgs;

Expand Down
4 changes: 4 additions & 0 deletions src/tools/get-actor-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ Note: This tool is automatically included if the Apify MCP Server is configured
* Allow additional properties for Skyfire mode to pass `skyfire-pay-id`.
*/
ajvValidate: ajv.compile({ ...zodToJsonSchema(getActorOutputArgs), additionalProperties: true }),
annotations: {
title: 'Get Actor output',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken, apifyMcpServer } = toolArgs;

Expand Down
5 changes: 5 additions & 0 deletions src/tools/get-html-skeleton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ USAGE EXAMPLES:
- user_input: Get next chunk of HTML skeleton for https://example.com (chunk=2)`,
inputSchema: zodToJsonSchema(getHtmlSkeletonArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getHtmlSkeletonArgs)),
annotations: {
title: 'Get HTML skeleton',
readOnlyHint: true,
openWorldHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getHtmlSkeletonArgs.parse(args);
Expand Down
3 changes: 3 additions & 0 deletions src/tools/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ USAGE EXAMPLES:
- user_input: Add apify/instagram-scraper as a tool`,
inputSchema: zodToJsonSchema(addToolArgsSchema) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(addToolArgsSchema)),
annotations: {
title: 'Add tool',
},
// TODO: I don't like that we are passing apifyMcpServer and mcpServer to the tool
call: async (toolArgs: InternalToolArgs) => {
const { apifyMcpServer, apifyToken, args, extra: { sendNotification } } = toolArgs;
Expand Down
12 changes: 12 additions & 0 deletions src/tools/key_value_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ USAGE EXAMPLES:
- user_input: Get details for store adb123`,
inputSchema: zodToJsonSchema(getKeyValueStoreArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreArgs)),
annotations: {
title: 'Get key-value store',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getKeyValueStoreArgs.parse(args);
Expand Down Expand Up @@ -69,6 +73,10 @@ USAGE EXAMPLES:
- user_input: Continue listing keys in store a123 from key data.json`,
inputSchema: zodToJsonSchema(getKeyValueStoreKeysArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreKeysArgs)),
annotations: {
title: 'Get key-value store keys',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getKeyValueStoreKeysArgs.parse(args);
Expand Down Expand Up @@ -107,6 +115,10 @@ USAGE EXAMPLES:
- user_input: Get record data.json from store username~my-store`,
inputSchema: zodToJsonSchema(getKeyValueStoreRecordArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreRecordArgs)),
annotations: {
title: 'Get key-value store record',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getKeyValueStoreRecordArgs.parse(args);
Expand Down
4 changes: 4 additions & 0 deletions src/tools/key_value_store_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ USAGE EXAMPLES:
- user_input: List unnamed key-value stores`,
inputSchema: zodToJsonSchema(getUserKeyValueStoresListArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getUserKeyValueStoresListArgs)),
annotations: {
title: 'Get user key-value stores list',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getUserKeyValueStoresListArgs.parse(args);
Expand Down
11 changes: 11 additions & 0 deletions src/tools/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ USAGE EXAMPLES:
- user_input: What is the datasetId for run y2h7sK3Wc?`,
inputSchema: zodToJsonSchema(getActorRunArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getActorRunArgs)),
annotations: {
title: 'Get Actor run',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getActorRunArgs.parse(args);
Expand Down Expand Up @@ -74,6 +78,10 @@ USAGE EXAMPLES:
- user_input: Get logs for run y2h7sK3Wc`,
inputSchema: zodToJsonSchema(GetRunLogArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(GetRunLogArgs)),
annotations: {
title: 'Get Actor run log',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = GetRunLogArgs.parse(args);
Expand Down Expand Up @@ -103,6 +111,9 @@ USAGE EXAMPLES:
- user_input: Gracefully abort run y2h7sK3Wc`,
inputSchema: zodToJsonSchema(abortRunArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(abortRunArgs)),
annotations: {
title: 'Abort Actor run',
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = abortRunArgs.parse(args);
Expand Down
4 changes: 4 additions & 0 deletions src/tools/run_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ USAGE EXAMPLES:
- user_input: Show only SUCCEEDED runs`,
inputSchema: zodToJsonSchema(getUserRunsListArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(getUserRunsListArgs)),
annotations: {
title: 'Get user runs list',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getUserRunsListArgs.parse(args);
Expand Down
6 changes: 5 additions & 1 deletion src/tools/search-apify-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const searchApifyDocsTool: ToolEntry = {
Apify documentation has information about Apify console, Actors (development
(actor.json, input schema, dataset schema, dockerfile), deployment, builds, runs),
schedules, storages (datasets, key-value store), Proxy, Integrations,
Apify Academy (crawling and webscraping with Crawlee),
Apify Academy (crawling and webscraping with Crawlee).

The results will include the URL of the documentation page, a fragment identifier (if available),
and a limited piece of content that matches the search query.
Expand All @@ -50,6 +50,10 @@ export const searchApifyDocsTool: ToolEntry = {
- query: How scrape with Crawlee?`,
inputSchema: zodToJsonSchema(searchApifyDocsToolArgsSchema) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(searchApifyDocsToolArgsSchema)),
annotations: {
title: 'Search Apify docs',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args } = toolArgs;

Expand Down
4 changes: 4 additions & 0 deletions src/tools/store_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ Returns list of Actor cards with the following info:
`,
inputSchema: zodToJsonSchema(searchActorsArgsSchema) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(searchActorsArgsSchema)),
annotations: {
title: 'Search Actors',
readOnlyHint: true,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken, userRentedActorIds, apifyMcpServer } = toolArgs;
const parsed = searchActorsArgsSchema.parse(args);
Expand Down
1 change: 1 addition & 0 deletions src/utils/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export function getToolPublicFieldOnly(tool: ToolBase) {
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema,
annotations: tool.annotations,
};
}

Expand Down