Skip to content

Commit 149cbbc

Browse files
authored
feat: Add tool annotations (#333)
* feat: Add tool annotations (title, readOnlyHint, openWorldHint) Add annotations to all internal and Actor tools: - title: Short display name (sentence case, Actor/Apify capitalized) - readOnlyHint: true for read-only tools - openWorldHint: true only for tools accessing open world (external web/Actors), not Apify platform Examples: call-actor and get-html-skeleton are openWorld; search-actors and fetch-apify-docs are not * fix: Update README.md * fix: add openWorldHint=false explicitly to relevant tools
1 parent 6a9e25c commit 149cbbc

18 files changed

+118
-3
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,14 @@ Here is an overview list of all the tools provided by the Apify MCP Server.
178178
179179
> 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.
180180
181+
### Tool annotations
182+
183+
All tools include metadata annotations to help MCP clients and LLMs understand tool behavior:
184+
185+
- **`title`**: Short display name for the tool (e.g., "Search Actors", "Call Actor", "apify/rag-web-browser")
186+
- **`readOnlyHint`**: `true` for tools that only read data without modifying state (e.g., `get-dataset`, `fetch-actor-details`)
187+
- **`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.
188+
181189
### Tools configuration
182190

183191
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.

src/mcp/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ export class ActorsMcpServer {
298298
}
299299
} else {
300300
// No skyfire mode - store tools as-is
301-
for (const wrap of tools) {
302-
this.tools.set(wrap.name, wrap);
301+
for (const tool of tools) {
302+
this.tools.set(tool.name, tool);
303303
}
304304
}
305305
if (shouldNotifyToolsChangedHandler) this.notifyToolsChangedHandler();

src/tools/actor.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ Actor description: ${actorDefinitionPruned.description}`;
199199
inputSchema: inputSchema as ToolInputSchema,
200200
ajvValidate,
201201
memoryMbytes,
202+
annotations: {
203+
title: actorDefinitionPruned.actorFullName,
204+
openWorldHint: true,
205+
},
202206
});
203207
}
204208
return tools;
@@ -375,6 +379,10 @@ EXAMPLES:
375379
// Additional props true to allow skyfire-pay-id
376380
additionalProperties: true,
377381
}),
382+
annotations: {
383+
title: 'Call Actor',
384+
openWorldHint: true,
385+
},
378386
call: async (toolArgs: InternalToolArgs) => {
379387
const { args, apifyToken, progressTracker, extra, apifyMcpServer } = toolArgs;
380388
const { actor: actorName, step, input, callOptions } = callActorArgs.parse(args);

src/tools/build.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ export const actorDefinitionTool: ToolEntry = {
125125
+ `Limit the length of the README if needed.`,
126126
inputSchema: zodToJsonSchema(getActorDefinitionArgsSchema) as ToolInputSchema,
127127
ajvValidate: ajv.compile(zodToJsonSchema(getActorDefinitionArgsSchema)),
128+
annotations: {
129+
title: 'Get Actor definition',
130+
readOnlyHint: true,
131+
openWorldHint: false,
132+
},
128133
call: async (toolArgs: InternalToolArgs) => {
129134
const { args, apifyToken } = toolArgs;
130135

src/tools/dataset.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ USAGE EXAMPLES:
5757
- user_input: What fields does username~my-dataset have?`,
5858
inputSchema: zodToJsonSchema(getDatasetArgs) as ToolInputSchema,
5959
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetArgs)),
60+
annotations: {
61+
title: 'Get dataset',
62+
readOnlyHint: true,
63+
openWorldHint: false,
64+
},
6065
call: async (toolArgs: InternalToolArgs) => {
6166
const { args, apifyToken } = toolArgs;
6267
const parsed = getDatasetArgs.parse(args);
@@ -89,6 +94,11 @@ USAGE EXAMPLES:
8994
- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`,
9095
inputSchema: zodToJsonSchema(getDatasetItemsArgs) as ToolInputSchema,
9196
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetItemsArgs)),
97+
annotations: {
98+
title: 'Get dataset items',
99+
readOnlyHint: true,
100+
openWorldHint: false,
101+
},
92102
call: async (toolArgs: InternalToolArgs) => {
93103
const { args, apifyToken } = toolArgs;
94104
const parsed = getDatasetItemsArgs.parse(args);
@@ -148,6 +158,11 @@ USAGE EXAMPLES:
148158
- user_input: Show schema of username~my-dataset (clean items only)`,
149159
inputSchema: zodToJsonSchema(getDatasetSchemaArgs) as ToolInputSchema,
150160
ajvValidate: ajv.compile(zodToJsonSchema(getDatasetSchemaArgs)),
161+
annotations: {
162+
title: 'Get dataset schema',
163+
readOnlyHint: true,
164+
openWorldHint: false,
165+
},
151166
call: async (toolArgs: InternalToolArgs) => {
152167
const { args, apifyToken } = toolArgs;
153168
const parsed = getDatasetSchemaArgs.parse(args);

src/tools/dataset_collection.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ USAGE EXAMPLES:
4242
- user_input: List unnamed datasets`,
4343
inputSchema: zodToJsonSchema(getUserDatasetsListArgs) as ToolInputSchema,
4444
ajvValidate: ajv.compile(zodToJsonSchema(getUserDatasetsListArgs)),
45+
annotations: {
46+
title: 'Get user datasets list',
47+
readOnlyHint: true,
48+
openWorldHint: false,
49+
},
4550
call: async (toolArgs: InternalToolArgs) => {
4651
const { args, apifyToken } = toolArgs;
4752
const parsed = getUserDatasetsListArgs.parse(args);

src/tools/fetch-actor-details.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ USAGE EXAMPLES:
2929
- user_input: What is the pricing for apify/instagram-scraper?`,
3030
inputSchema: zodToJsonSchema(fetchActorDetailsToolArgsSchema) as ToolInputSchema,
3131
ajvValidate: ajv.compile(zodToJsonSchema(fetchActorDetailsToolArgsSchema)),
32+
annotations: {
33+
title: 'Fetch Actor details',
34+
readOnlyHint: true,
35+
openWorldHint: false,
36+
},
3237
call: async (toolArgs: InternalToolArgs) => {
3338
const { args, apifyToken } = toolArgs;
3439
const parsed = fetchActorDetailsToolArgsSchema.parse(args);

src/tools/fetch-apify-docs.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ USAGE EXAMPLES:
2828
- user_input: Fetch https://docs.apify.com/academy`,
2929
inputSchema: zodToJsonSchema(fetchApifyDocsToolArgsSchema) as ToolInputSchema,
3030
ajvValidate: ajv.compile(zodToJsonSchema(fetchApifyDocsToolArgsSchema)),
31+
annotations: {
32+
title: 'Fetch Apify docs',
33+
readOnlyHint: true,
34+
openWorldHint: false,
35+
},
3136
call: async (toolArgs: InternalToolArgs) => {
3237
const { args } = toolArgs;
3338

src/tools/get-actor-output.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ Note: This tool is automatically included if the Apify MCP Server is configured
8888
* Allow additional properties for Skyfire mode to pass `skyfire-pay-id`.
8989
*/
9090
ajvValidate: ajv.compile({ ...zodToJsonSchema(getActorOutputArgs), additionalProperties: true }),
91+
annotations: {
92+
title: 'Get Actor output',
93+
readOnlyHint: true,
94+
openWorldHint: false,
95+
},
9196
call: async (toolArgs: InternalToolArgs) => {
9297
const { args, apifyToken, apifyMcpServer } = toolArgs;
9398

src/tools/get-html-skeleton.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ USAGE EXAMPLES:
5252
- user_input: Get next chunk of HTML skeleton for https://example.com (chunk=2)`,
5353
inputSchema: zodToJsonSchema(getHtmlSkeletonArgs) as ToolInputSchema,
5454
ajvValidate: ajv.compile(zodToJsonSchema(getHtmlSkeletonArgs)),
55+
annotations: {
56+
title: 'Get HTML skeleton',
57+
readOnlyHint: true,
58+
openWorldHint: true,
59+
},
5560
call: async (toolArgs: InternalToolArgs) => {
5661
const { args, apifyToken } = toolArgs;
5762
const parsed = getHtmlSkeletonArgs.parse(args);

0 commit comments

Comments
 (0)