Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions src/tools/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;

Expand Down
15 changes: 15 additions & 0 deletions src/tools/dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getDatasetArgs.parse(args);
Expand Down Expand Up @@ -89,6 +94,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getDatasetItemsArgs.parse(args);
Expand Down Expand Up @@ -148,6 +158,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getDatasetSchemaArgs.parse(args);
Expand Down
5 changes: 5 additions & 0 deletions src/tools/dataset_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getUserDatasetsListArgs.parse(args);
Expand Down
5 changes: 5 additions & 0 deletions src/tools/fetch-actor-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = fetchActorDetailsToolArgsSchema.parse(args);
Expand Down
5 changes: 5 additions & 0 deletions src/tools/fetch-apify-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args } = toolArgs;

Expand Down
5 changes: 5 additions & 0 deletions src/tools/get-actor-output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ 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,
openWorldHint: false,
},
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
4 changes: 4 additions & 0 deletions src/tools/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ 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',
openWorldHint: true,
},
// 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
15 changes: 15 additions & 0 deletions src/tools/key_value_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getKeyValueStoreArgs.parse(args);
Expand Down Expand Up @@ -69,6 +74,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getKeyValueStoreKeysArgs.parse(args);
Expand Down Expand Up @@ -107,6 +117,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getKeyValueStoreRecordArgs.parse(args);
Expand Down
5 changes: 5 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,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getUserKeyValueStoresListArgs.parse(args);
Expand Down
14 changes: 14 additions & 0 deletions src/tools/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getActorRunArgs.parse(args);
Expand Down Expand Up @@ -74,6 +79,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = GetRunLogArgs.parse(args);
Expand Down Expand Up @@ -103,6 +113,10 @@ USAGE EXAMPLES:
- user_input: Gracefully abort run y2h7sK3Wc`,
inputSchema: zodToJsonSchema(abortRunArgs) as ToolInputSchema,
ajvValidate: ajv.compile(zodToJsonSchema(abortRunArgs)),
annotations: {
title: 'Abort Actor run',
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = abortRunArgs.parse(args);
Expand Down
5 changes: 5 additions & 0 deletions src/tools/run_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args, apifyToken } = toolArgs;
const parsed = getUserRunsListArgs.parse(args);
Expand Down
7 changes: 6 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,11 @@ 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,
openWorldHint: false,
},
call: async (toolArgs: InternalToolArgs) => {
const { args } = toolArgs;

Expand Down
5 changes: 5 additions & 0 deletions src/tools/store_collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ 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,
openWorldHint: false,
},
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
Loading