From ed750c0904006e635eee5b0ac88dd580ca5ca4eb Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Wed, 17 Sep 2025 12:15:47 +0200 Subject: [PATCH 1/5] feat: Update tool descriptions --- src/tools/actor.ts | 18 ++++++++-------- src/tools/fetch-actor-details.ts | 19 +++++++++-------- src/tools/get-actor-output.ts | 15 ++++++++++--- src/tools/search-apify-docs.ts | 27 +++++++++++++++++------- src/tools/store_collection.ts | 36 +++++++++++++++++++------------- 5 files changed, 72 insertions(+), 43 deletions(-) diff --git a/src/tools/actor.ts b/src/tools/actor.ts index 139ac558..edc9cfa5 100644 --- a/src/tools/actor.ts +++ b/src/tools/actor.ts @@ -317,8 +317,7 @@ export const callActor: ToolEntry = { tool: { name: HelperTools.ACTOR_CALL, actorFullName: HelperTools.ACTOR_CALL, - description: `Call Any Actor from Apify Store - Two-Step Process - + description: `Call any Actor from Apify Store - two-step process This tool uses a mandatory two-step process to safely call any Actor from the Apify store. USAGE: @@ -328,13 +327,14 @@ USAGE: MANDATORY TWO-STEP WORKFLOW: Step 1: Get Actor Info (step="info", default) -• First call this tool with step="info" to get Actor details and input schema -• This returns the Actor description, documentation, and required input schema -• You MUST do this step first - it's required to understand how to call the Actor - -Step 2: Call Actor (step="call") -• Only after step 1, call again with step="call" and proper input based on the schema -• This executes the Actor and returns the results +- First call this tool with step="info" to get Actor details and input schema +- This returns the Actor description, documentation, and required input schema +- You MUST do this step first - it's required to understand how to call the Actor + +Step 2: Call Actor (step="call") +- Only after step 1, call again with step="call" and proper input based on the schema +- This calls and runs the Actor. It will create an output as an Apify dataset (with datasetId). +- This step returns a dataset preview, typically JSON-formatted tabular data. The step parameter enforces this workflow - you cannot call an Actor without first getting its info.`, inputSchema: zodToJsonSchema(callActorArgs), diff --git a/src/tools/fetch-actor-details.ts b/src/tools/fetch-actor-details.ts index 32742be1..c143bfcc 100644 --- a/src/tools/fetch-actor-details.ts +++ b/src/tools/fetch-actor-details.ts @@ -17,15 +17,16 @@ export const fetchActorDetailsTool: ToolEntry = { type: 'internal', tool: { name: HelperTools.ACTOR_GET_DETAILS, - description: `Get detailed information about an Actor by its ID or full name.\n` - + `This tool returns title, description, URL, README (Actor's documentation), input schema, and usage statistics. \n` - + `The Actor name is always composed of "username/name", for example, "apify/rag-web-browser".\n` - + `Present Actor information in user-friendly format as an Actor card.\n` - + `USAGE:\n` - + `- Use when user asks about an Actor its details, description, input schema, etc.\n` - + `EXAMPLES:\n` - + `- user_input: How to use apify/rag-web-browser\n` - + `- user_input: What is the input schema for apify/rag-web-browser`, + description: `Get detailed information about an Actor by its ID or full name. +This tool returns title, description, URL, README (Actor's documentation), input schema, and usage statistics. +The Actor name is always composed of "username/name", for example, "apify/rag-web-browser". +Present Actor information in user-friendly format as an Actor card. +USAGE: +- Use when user asks about an Actor its details, description, input schema, etc. +EXAMPLES: +- user_input: How to use apify/rag-web-browser +- user_input: What is the input schema for apify/rag-web-browser, +- user_input: What is pricing of apify/instagram-scraper?`, inputSchema: zodToJsonSchema(fetchActorDetailsToolArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(fetchActorDetailsToolArgsSchema)), call: async (toolArgs) => { diff --git a/src/tools/get-actor-output.ts b/src/tools/get-actor-output.ts index b6b6b1fe..cdae199e 100644 --- a/src/tools/get-actor-output.ts +++ b/src/tools/get-actor-output.ts @@ -68,10 +68,19 @@ export const getActorOutput: ToolEntry = { tool: { name: HelperTools.ACTOR_OUTPUT_GET, actorFullName: HelperTools.ACTOR_OUTPUT_GET, - description: `Retrieves the output of a specific Actor execution based on its dataset ID. -You can also retrieve only specific fields from the output if needed. Use this tool to get Actor output data outside of the Actor dataset output preview, or to access fields from the Actor output dataset schema that are not included in the preview. + description: `Fetch the dataset of a specific Actor run based on datasetId. +You can also retrieve only specific fields from the output if needed. -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\`).`, +USAGE: +- Use this tool to get Actor dataset outside of the preview, or to access fields from the Actor output +dataset schema that are not included in the preview. + +EXAMPLES: +- user_input: Get data of my last Actor run? +- user_input: Get number_of_likes from my dataset? + +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").`, inputSchema: zodToJsonSchema(getActorOutputArgs), /** * Allow additional properties for Skyfire mode to pass `skyfire-pay-id`. diff --git a/src/tools/search-apify-docs.ts b/src/tools/search-apify-docs.ts index ddf0ee6d..8375323e 100644 --- a/src/tools/search-apify-docs.ts +++ b/src/tools/search-apify-docs.ts @@ -30,12 +30,25 @@ export const searchApifyDocsTool: ToolEntry = { type: 'internal', tool: { name: HelperTools.DOCS_SEARCH, - description: `Apify documentation search tool. This tool allows you to search the Apify documentation using Algolia's full-text search.\n` - + 'You can use it to find relevant documentation pages based on keywords. 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. ' - + `You can then fetch the full content of the document using the ${HelperTools.DOCS_FETCH} tool by providing the URL.\n` - + 'Use this tool when a user asks for help with Apify documentation or when you need to find relevant documentation pages based on keywords. ' - + 'For example, when a user wants to build an Apify Actor, you can search "How to build Actors" to find relevant guidance.', + description: `Search Apify documentation using full-text search. + You can use it to find relevant documentation based on keywords. + 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), + + 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. + + Fetch the full content of the document using the ${HelperTools.DOCS_FETCH} tool by providing the URL. + + USAGE: + - Use when user asks about Apify documentation, Actor development, Crawlee, or Apify platform. + + EXAMPLES: + - query: How to use create Apify Actor? + - query: How to define Actor input schema? + - query: How scrape with Crawlee?`, args: searchApifyDocsToolArgsSchema, inputSchema: zodToJsonSchema(searchApifyDocsToolArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(searchApifyDocsToolArgsSchema)), @@ -59,7 +72,7 @@ export const searchApifyDocsTool: ToolEntry = { const textContent = `You can use the Apify docs fetch tool to retrieve the full content of a document by its URL. The document fragment refers to the section of the content containing the relevant part for the search result item. Search results for "${query}": - + ${results.map((result) => `- Document URL: ${result.url}${result.fragment ? `\n Document fragment: ${result.fragment}` : ''} Content: ${result.content}`).join('\n\n')}`; return { diff --git a/src/tools/store_collection.ts b/src/tools/store_collection.ts index 821f75ae..4f39d3c3 100644 --- a/src/tools/store_collection.ts +++ b/src/tools/store_collection.ts @@ -71,21 +71,27 @@ export const searchActors: ToolEntry = { type: 'internal', tool: { name: HelperTools.STORE_SEARCH, - description: `Search for Actors or Model Context Protocol (MCP) servers in the Apify Store using keywords.\n` - + `This tool returns a list of Actors with title, description, pricing model, usage statistics, and user ratings.\n` - + `Use simple space-separated keywords for best results, such as "web scraping", "data extraction", or "playwright mcp".\n` - + `You may need to use this tool several times to find the right Actor.\n` - + `Limit the number of results returned, but ensure that relevant results are included.\n` - + `Always present the results in a user-friendly format as an Actor cards.\n\n` - + `USAGE:\n` - + `- Use when user wants to find Actors for a specific task or technology\n` - + `- Use when user asks about available Actors in the Apify Store\n` - + `- Use when user needs to discover MCP servers or automation tools\n` - + `EXAMPLES:\n` - + `- user_input: Find Actors for web scraping\n` - + `- user_input: Search for MCP servers\n` - + `- user_input: What Actors are available for data extraction\n` - + `- user_input: Show me Actors that use Playwright`, + description: `Search the Apify Store for Actors or Model Context Protocol (MCP) servers using keywords. +Apify is the largest platform for web scrapers, AI agents, and automation tools, called Actors. +The store features solutions for scraping Instagram, Twitter, TikTok, LinkedIn, Bookings, Flights and more. +All Actors are verified and comply with scraping guidelines. + +This tool returns a curated list of Actors, including their title, description, pricing model, usage statistics, and user ratings. +For best results, use simple space-separated keywords (e.g., "instagram posts", "twitter profile", "playwright mcp"). +You may need to run multiple searches to find the most suitable Actor. +Limit the number of results to keep responses relevant and concise. +Results are always presented as user-friendly Actor cards. + +USAGE: +- Use when a user wants to find Actors for a specific task +- Use when a user asks about specific data and available Actors in the Apify Store +- Use when a user needs to discover MCP servers or automation tools + +EXAMPLES: +- user_input: Find Actors for scraping e-commerce +- user_input: Find browserbase MCP server +- user_input: I need to scrape instagram profiles/comments +- user_input: I need to get flights and airbnb data`, inputSchema: zodToJsonSchema(searchActorsArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(searchActorsArgsSchema)), call: async (toolArgs) => { From 4fefb7f3bbd7df6d8b9e629622ed4b17d75dbc0f Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Wed, 17 Sep 2025 13:57:12 +0200 Subject: [PATCH 2/5] feat: Update default tool RAG Web Browser --- package-lock.json | 8 ++-- package.json | 2 +- src/const.ts | 7 +-- src/tools/actor.ts | 82 +++++++++++++++++++--------------- src/tools/get-html-skeleton.ts | 10 ++--- src/tools/utils.ts | 60 ++++++++++++++++++++++++- 6 files changed, 118 insertions(+), 51 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5934bd9a..cf779849 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "dotenv": "^16.4.7", "eslint": "^9.19.0", "eventsource": "^3.0.2", - "tsx": "^4.6.2", + "tsx": "^4.20.5", "typescript": "^5.3.3", "typescript-eslint": "^8.23.0", "vitest": "^3.0.8" @@ -7905,9 +7905,9 @@ "license": "0BSD" }, "node_modules/tsx": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz", - "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==", + "version": "4.20.5", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz", + "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index ee4d3e5f..98e2219b 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "dotenv": "^16.4.7", "eslint": "^9.19.0", "eventsource": "^3.0.2", - "tsx": "^4.6.2", + "tsx": "^4.20.5", "typescript": "^5.3.3", "typescript-eslint": "^8.23.0", "vitest": "^3.0.8" diff --git a/src/const.ts b/src/const.ts index 5d4575b5..ec61c55c 100644 --- a/src/const.ts +++ b/src/const.ts @@ -47,15 +47,16 @@ export enum HelperTools { GET_HTML_SKELETON = 'get-html-skeleton', } -export const ACTOR_RAG_WEB_BROWSER = 'apify/rag-web-browser'; +export const RAG_WEB_BROWSER = 'apify/rag-web-browser'; +export const RAG_WEB_BROWSER_WHITELISTED_FIELDS = ['query', 'maxResults', 'outputFormats']; +export const RAG_WEB_BROWSER_ADDITIONAL_DESC = `This tool provides general web browsing functionality, for specific sites like e-commerce, social media it is always better to search for a specific Actor`; export const defaults = { actors: [ - ACTOR_RAG_WEB_BROWSER, + RAG_WEB_BROWSER, ], }; -export const ACTOR_ADDITIONAL_INSTRUCTIONS = 'Never call/execute tool/Actor unless confirmed by the user.'; export const SKYFIRE_MIN_CHARGE_USD = 5.0; export const SKYFIRE_SELLER_ID = process.env.SKYFIRE_SELLER_SERVICE_ID; diff --git a/src/tools/actor.ts b/src/tools/actor.ts index edc9cfa5..700c831f 100644 --- a/src/tools/actor.ts +++ b/src/tools/actor.ts @@ -7,9 +7,10 @@ import log from '@apify/log'; import { ApifyClient } from '../apify-client.js'; import { - ACTOR_ADDITIONAL_INSTRUCTIONS, ACTOR_MAX_MEMORY_MBYTES, HelperTools, + RAG_WEB_BROWSER, + RAG_WEB_BROWSER_ADDITIONAL_DESC, SKYFIRE_TOOL_INSTRUCTIONS, TOOL_MAX_OUTPUT_CHARS, } from '../const.js'; @@ -26,7 +27,11 @@ import type { ProgressTracker } from '../utils/progress.js'; import type { JsonSchemaProperty } from '../utils/schema-generation.js'; import { generateSchemaFromItems } from '../utils/schema-generation.js'; import { getActorDefinition } from './build.js'; -import { actorNameToToolName, fixedAjvCompile, getToolSchemaID, transformActorInputSchemaProperties } from './utils.js'; +import { + actorNameToToolName, + buildActorInputSchema, + fixedAjvCompile, +} from './utils.js'; // Define a named return type for callActorGetDataset export type CallActorGetDatasetResult = { @@ -156,45 +161,48 @@ export async function getNormalActorsAsTools( ): Promise { const tools: ToolEntry[] = []; - // Zip the results with their corresponding actorIDs for (const actorInfo of actorsInfo) { const { actorDefinitionPruned } = actorInfo; - if (actorDefinitionPruned) { - const schemaID = getToolSchemaID(actorDefinitionPruned.actorFullName); - if (actorDefinitionPruned.input && 'properties' in actorDefinitionPruned.input && actorDefinitionPruned.input) { - actorDefinitionPruned.input.properties = transformActorInputSchemaProperties(actorDefinitionPruned.input); - // Add schema $id, each valid JSON schema should have a unique $id - // see https://json-schema.org/understanding-json-schema/basics#declaring-a-unique-identifier - actorDefinitionPruned.input.$id = schemaID; - } - try { - const memoryMbytes = actorDefinitionPruned.defaultRunOptions?.memoryMbytes || ACTOR_MAX_MEMORY_MBYTES; - const tool: ToolEntry = { - type: 'actor', - tool: { - name: actorNameToToolName(actorDefinitionPruned.actorFullName), - actorFullName: actorDefinitionPruned.actorFullName, - description: `This tool calls the Actor "${actorDefinitionPruned.actorFullName}" and retrieves its output results. Use this tool instead of the "${HelperTools.ACTOR_CALL}" if user requests to use this specific Actor. -Actor description: ${actorDefinitionPruned.description} -Instructions: ${ACTOR_ADDITIONAL_INSTRUCTIONS}`, - inputSchema: actorDefinitionPruned.input - // So Actor without input schema works - MCP client expects JSON schema valid output - || { - type: 'object', - properties: {}, - required: [], - }, - // Additional props true to allow skyfire-pay-id - ajvValidate: fixedAjvCompile(ajv, { ...actorDefinitionPruned.input, additionalProperties: true }), - memoryMbytes: memoryMbytes > ACTOR_MAX_MEMORY_MBYTES ? ACTOR_MAX_MEMORY_MBYTES : memoryMbytes, - }, - }; - tools.push(tool); - } catch (validationError) { - log.error('Failed to compile AJV schema for Actor', { actorName: actorDefinitionPruned.actorFullName, error: validationError }); - } + if (!actorDefinitionPruned) continue; + + const isRag = actorDefinitionPruned.actorFullName === RAG_WEB_BROWSER; + const { inputSchema } = buildActorInputSchema(actorDefinitionPruned.actorFullName, actorDefinitionPruned.input, isRag); + + let description = `This tool calls the Actor "${actorDefinitionPruned.actorFullName}" and retrieves its output results. +Use this tool instead of the "${HelperTools.ACTOR_CALL}" if user requests this specific Actor. +Actor description: ${actorDefinitionPruned.description}`; + if (isRag) { + description += RAG_WEB_BROWSER_ADDITIONAL_DESC; + } + + const memoryMbytes = Math.min( + actorDefinitionPruned.defaultRunOptions?.memoryMbytes || ACTOR_MAX_MEMORY_MBYTES, + ACTOR_MAX_MEMORY_MBYTES, + ); + + let ajvValidate; + try { + ajvValidate = fixedAjvCompile(ajv, { ...inputSchema, additionalProperties: true }); + } catch (e) { + log.error('Failed to compile schema', { + actorName: actorDefinitionPruned.actorFullName, + error: e, + }); + continue; } + + tools.push({ + type: 'actor', + tool: { + name: actorNameToToolName(actorDefinitionPruned.actorFullName), + actorFullName: actorDefinitionPruned.actorFullName, + description, + inputSchema, + ajvValidate, + memoryMbytes, + }, + }); } return tools; } diff --git a/src/tools/get-html-skeleton.ts b/src/tools/get-html-skeleton.ts index 66e31a96..ea9674f4 100644 --- a/src/tools/get-html-skeleton.ts +++ b/src/tools/get-html-skeleton.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; import { ApifyClient } from '../apify-client.js'; -import { ACTOR_RAG_WEB_BROWSER, HelperTools, TOOL_MAX_OUTPUT_CHARS } from '../const.js'; +import { HelperTools, RAG_WEB_BROWSER, TOOL_MAX_OUTPUT_CHARS } from '../const.js'; import { getHtmlSkeletonCache } from '../state.js'; import type { InternalTool, ToolEntry } from '../types.js'; import { ajv } from '../utils/ajv.js'; @@ -58,7 +58,7 @@ export const getHtmlSkeleton: ToolEntry = { // Not in cache, call the Actor for scraping const client = new ApifyClient({ token: apifyToken }); - const run = await client.actor(ACTOR_RAG_WEB_BROWSER).call({ + const run = await client.actor(RAG_WEB_BROWSER).call({ query: parsed.url, outputFormats: [ 'html', @@ -68,16 +68,16 @@ export const getHtmlSkeleton: ToolEntry = { const datasetItems = await client.dataset(run.defaultDatasetId).listItems(); if (datasetItems.items.length === 0) { - return buildMCPResponse([`The scraping Actor (${ACTOR_RAG_WEB_BROWSER}) did not return any output for the URL: ${parsed.url}. Please check the Actor run for more details: ${run.id}`]); + return buildMCPResponse([`The scraping Actor (${RAG_WEB_BROWSER}) did not return any output for the URL: ${parsed.url}. Please check the Actor run for more details: ${run.id}`]); } const firstItem = datasetItems.items[0] as unknown as ScrapedPageItem; if (firstItem.crawl.httpStatusMessage.toLocaleLowerCase() !== 'ok') { - return buildMCPResponse([`The scraping Actor (${ACTOR_RAG_WEB_BROWSER}) returned an HTTP status ${firstItem.crawl.httpStatusCode} (${firstItem.crawl.httpStatusMessage}) for the URL: ${parsed.url}. Please check the Actor run for more details: ${run.id}`]); + return buildMCPResponse([`The scraping Actor (${RAG_WEB_BROWSER}) returned an HTTP status ${firstItem.crawl.httpStatusCode} (${firstItem.crawl.httpStatusMessage}) for the URL: ${parsed.url}. Please check the Actor run for more details: ${run.id}`]); } if (!firstItem.html) { - return buildMCPResponse([`The scraping Actor (${ACTOR_RAG_WEB_BROWSER}) did not return any HTML content for the URL: ${parsed.url}. Please check the Actor run for more details: ${run.id}`]); + return buildMCPResponse([`The scraping Actor (${RAG_WEB_BROWSER}) did not return any HTML content for the URL: ${parsed.url}. Please check the Actor run for more details: ${run.id}`]); } strippedHtml = stripHtml(firstItem.html); diff --git a/src/tools/utils.ts b/src/tools/utils.ts index 703e5626..eef3913f 100644 --- a/src/tools/utils.ts +++ b/src/tools/utils.ts @@ -1,7 +1,7 @@ import type { ValidateFunction } from 'ajv'; import type Ajv from 'ajv'; -import { ACTOR_ENUM_MAX_LENGTH, ACTOR_MAX_DESCRIPTION_LENGTH } from '../const.js'; +import { ACTOR_ENUM_MAX_LENGTH, ACTOR_MAX_DESCRIPTION_LENGTH, RAG_WEB_BROWSER_WHITELISTED_FIELDS } from '../const.js'; import type { ActorInputSchemaProperties, IActorInputSchema, ISchemaProperties } from '../types.js'; import { addGlobsProperties, @@ -151,6 +151,64 @@ export function markInputPropertiesAsRequired(input: IActorInputSchema): Record< return properties; } +/** + * Builds the final Actor input schema for MCP tool usage. + */ +export function buildActorInputSchema(actorFullName: string, input: IActorInputSchema | undefined, isRag: boolean) { + if (!input) { + return { + inputSchema: { + $id: getToolSchemaID(actorFullName), + type: 'object', + properties: {}, + required: [], + }, + }; + } + + // Work on a shallow cloned structure (deep clone only if needed later) + const working = structuredClone(input); + + if (working && typeof working === 'object' && 'properties' in working && working.properties) { + working.properties = transformActorInputSchemaProperties(working); + } + + let finalSchema = working; + if (isRag) { + finalSchema = pruneSchemaPropertiesByWhitelist(finalSchema, RAG_WEB_BROWSER_WHITELISTED_FIELDS); + } + + finalSchema.$id = getToolSchemaID(actorFullName); + return { inputSchema: finalSchema }; +} + +/** + * Returns a shallow-cloned input schema that keeps only whitelisted properties + * and filters the required array accordingly. All other top-level fields are preserved. + * If properties are missing, the original input is returned unchanged. + * + * This is used specifically for apify/rag-web-browser where we want to expose + * only a subset of input properties to the MCP tool without redefining the schema. + */ +export function pruneSchemaPropertiesByWhitelist( + input: IActorInputSchema, + whitelist: Iterable, +): IActorInputSchema { + if (!input || !input.properties || typeof input.properties !== 'object' || !whitelist) return input; + + const allowed = new Set(Array.from(whitelist)); + const newProps: Record = {}; + for (const key of Object.keys(input.properties)) { + if (allowed.has(key)) newProps[key] = input.properties[key]; + } + + const cloned: IActorInputSchema = { ...input, properties: newProps }; + if (Array.isArray(input.required)) { + cloned.required = input.required.filter((k) => allowed.has(k)); + } + return cloned; +} + /** * Helps determine the type of items in an array schema property. * Priority order: explicit type in items > prefill type > default value type > editor type. From 24c5e0d86733d9d80b563bc55193cfe31380b213 Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Thu, 18 Sep 2025 14:20:17 +0200 Subject: [PATCH 3/5] feat: Update tool description --- src/tools/actor.ts | 25 ++++++++---- src/tools/dataset.ts | 51 ++++++++++++++++--------- src/tools/dataset_collection.ts | 18 ++++++--- src/tools/fetch-actor-details.ts | 15 ++++---- src/tools/fetch-apify-docs.ts | 10 ++++- src/tools/get-actor-output.ts | 20 ++++++---- src/tools/get-html-skeleton.ts | 12 +++++- src/tools/helpers.ts | 17 ++++++--- src/tools/key_value_store.ts | 40 +++++++++++++------ src/tools/key_value_store_collection.ts | 18 ++++++--- src/tools/run.ts | 36 +++++++++++++---- src/tools/run_collection.ts | 13 +++++-- src/tools/store_collection.ts | 17 +++------ 13 files changed, 197 insertions(+), 95 deletions(-) diff --git a/src/tools/actor.ts b/src/tools/actor.ts index 700c831f..55cd7859 100644 --- a/src/tools/actor.ts +++ b/src/tools/actor.ts @@ -302,7 +302,7 @@ const callActorArgs = z.object({ .describe('The name of the Actor to call. For example, "apify/rag-web-browser".'), step: z.enum(['info', 'call']) .default('info') - .describe(`Step to perform: "info" to get Actor details and input schema (required first step), "call" to execute the Actor (only after getting info).`), + .describe(`Step to perform: "info" to get Actor details and input schema (required first step), "call" to run the Actor (only after getting info).`), input: z.object({}).passthrough() .optional() .describe(`The input JSON to pass to the Actor. For example, {"query": "apify", "maxResults": 5, "outputFormats": ["markdown"]}. Required only when step is "call".`), @@ -325,15 +325,23 @@ export const callActor: ToolEntry = { tool: { name: HelperTools.ACTOR_CALL, actorFullName: HelperTools.ACTOR_CALL, - description: `Call any Actor from Apify Store - two-step process -This tool uses a mandatory two-step process to safely call any Actor from the Apify store. + description: `Call any Actor from the Apify Store using a mandatory two-step workflow. +This ensures you first get the Actor’s input schema and details before executing it safely. -USAGE: -• ONLY for Actors that are NOT available as dedicated tools -• If a dedicated tool exists (e.g., ${actorNameToToolName('apify/rag-web-browser')}), use that instead +There are two ways to run Actors: +1. Dedicated Actor tools (e.g., ${actorNameToToolName('apify/rag-web-browser')}): These are pre-configured tools, offering a simpler and more direct experience. +2. Generic call-actor tool (${HelperTools.ACTOR_CALL}): Use this when a dedicated tool is not available or when you want to run any Actor dynamically. This tool is especially useful if you do not want to add specific tools or your client does not support dynamic tool registration. + +**Important:** -MANDATORY TWO-STEP WORKFLOW: +A successful run returns a \`datasetId\` (the Actor's output stored as an Apify dataset) and a short preview of items. +To fetch the full output, use the ${HelperTools.ACTOR_OUTPUT_GET} tool with the \`datasetId\`. + +USAGE: +- Always use dedicated tools when available (e.g., ${actorNameToToolName('apify/rag-web-browser')}) +- Use the generic call-actor tool only if a dedicated tool does not exist for your Actor. +MANDATORY TWO-STEP-WORKFLOW: Step 1: Get Actor Info (step="info", default) - First call this tool with step="info" to get Actor details and input schema - This returns the Actor description, documentation, and required input schema @@ -344,7 +352,8 @@ Step 2: Call Actor (step="call") - This calls and runs the Actor. It will create an output as an Apify dataset (with datasetId). - This step returns a dataset preview, typically JSON-formatted tabular data. -The step parameter enforces this workflow - you cannot call an Actor without first getting its info.`, +EXAMPLES: +- user_input: Get instagram posts using apify/instagram-scraper`, inputSchema: zodToJsonSchema(callActorArgs), ajvValidate: ajv.compile({ ...zodToJsonSchema(callActorArgs), diff --git a/src/tools/dataset.ts b/src/tools/dataset.ts index 48766fb7..be349817 100644 --- a/src/tools/dataset.ts +++ b/src/tools/dataset.ts @@ -46,11 +46,17 @@ export const getDataset: ToolEntry = { tool: { name: HelperTools.DATASET_GET, actorFullName: HelperTools.DATASET_GET, - description: 'Dataset is a collection of structured data created by an Actor run. ' - + 'Returns information about dataset object with metadata (itemCount, schema, fields, stats). ' - + `Fields describe the structure of the dataset and can be used to filter the data with the ${HelperTools.DATASET_GET_ITEMS} tool. ` - + 'Note: itemCount updates may have 5s delay.' - + 'The dataset can be accessed with the dataset URL: GET: https://api.apify.com/v2/datasets/:datasetId', + description: `Get metadata for a dataset (collection of structured data created by an Actor run). +The results will include dataset details such as itemCount, schema, fields, and stats. +Use fields to understand structure for filtering with ${HelperTools.DATASET_GET_ITEMS}. +Note: itemCount updates may be delayed by up to ~5 seconds. + +USAGE: +- Use when you need dataset metadata to understand its structure before fetching items. + +EXAMPLES: +- user_input: Show info for dataset 8TtYhCwKzQeQk7dJx +- user_input: What fields does username~my-dataset have?`, inputSchema: zodToJsonSchema(getDatasetArgs), ajvValidate: ajv.compile(zodToJsonSchema(getDatasetArgs)), call: async (toolArgs) => { @@ -74,16 +80,18 @@ export const getDatasetItems: ToolEntry = { tool: { name: HelperTools.DATASET_GET_ITEMS, actorFullName: HelperTools.DATASET_GET_ITEMS, - description: 'Returns dataset items with pagination support. ' - + 'Items can be sorted (newest to oldest) and filtered (clean mode skips empty items and hidden fields). ' - + 'Supports field selection - include specific fields or exclude unwanted ones using comma-separated lists. ' - + 'For nested objects, you must first flatten them using the flatten parameter before accessing their fields. ' - + 'Example: To get URLs from items like [{"metadata":{"url":"example.com"}}], ' - + 'use flatten="metadata" and then fields="metadata.url". ' - + 'The flattening transforms nested objects into dot-notation format ' - + '(e.g. {"metadata":{"url":"x"}} becomes {"metadata.url":"x"}). ' - + 'Retrieve only the fields you need, reducing the response size and improving performance. ' - + 'The response includes total count, offset, limit, and items array.', + description: `Retrieve dataset items with pagination, sorting, and field selection. +Use clean=true to skip empty items and hidden fields. Include or omit fields using comma-separated lists. +For nested objects, first flatten them (e.g., flatten="metadata"), then reference nested fields via dot notation (e.g., fields="metadata.url"). + +The results will include items along with pagination info (limit, offset) and total count. + +USAGE: +- Use when you need to read data from a dataset (all items or only selected fields). + +EXAMPLES: +- user_input: Get first 100 items from dataset 8TtYhCwKzQeQk7dJx +- user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`, inputSchema: zodToJsonSchema(getDatasetItemsArgs), ajvValidate: ajv.compile(zodToJsonSchema(getDatasetItemsArgs)), call: async (toolArgs) => { @@ -136,9 +144,16 @@ export const getDatasetSchema: ToolEntry = { tool: { name: HelperTools.DATASET_SCHEMA_GET, actorFullName: HelperTools.DATASET_SCHEMA_GET, - description: 'Generates a JSON schema from dataset items. ' - + 'The schema describes the structure of the data in the dataset, which can be used for validation, documentation, or data processing.' - + 'Since the dataset can be large it is convenient to understand the structure of the dataset before getting dataset items.', + description: `Generate a JSON schema from a sample of dataset items. +The schema describes the structure of the data and can be used for validation, documentation, or processing. +Use this to understand the dataset before fetching many items. + +USAGE: +- Use when you need to infer the structure of dataset items for downstream processing or validation. + +EXAMPLES: +- user_input: Generate schema for dataset 8TtYhCwKzQeQk7dJx using 10 items +- user_input: Show schema of username~my-dataset (clean items only)`, inputSchema: zodToJsonSchema(getDatasetSchemaArgs), ajvValidate: ajv.compile(zodToJsonSchema(getDatasetSchemaArgs)), call: async (toolArgs) => { diff --git a/src/tools/dataset_collection.ts b/src/tools/dataset_collection.ts index 7126c3ef..1e025d51 100644 --- a/src/tools/dataset_collection.ts +++ b/src/tools/dataset_collection.ts @@ -30,12 +30,18 @@ export const getUserDatasetsList: ToolEntry = { tool: { name: HelperTools.DATASET_LIST_GET, actorFullName: HelperTools.DATASET_LIST_GET, - description: 'Lists datasets (collections of Actor run data). ' - + 'Actor runs automatically produce unnamed datasets (use unnamed=true to include these). ' - + 'Users can also create named datasets manually. ' - + 'Each dataset includes itemCount, access settings, and usage stats (readCount, writeCount). ' - + 'Results are sorted by createdAt in ascending order (use desc=true for descending). ' - + 'Supports pagination with limit (max 20) and offset parameters.', + description: `List datasets (collections of Actor run data) for the authenticated user. +Actor runs automatically produce unnamed datasets (set unnamed=true to include them). Users can also create named datasets. + +The results will include datasets with itemCount, access settings, and usage stats, sorted by createdAt (ascending by default). +Use limit (max 20), offset, and desc to paginate and sort. + +USAGE: +- Use when you need to browse available datasets (named or unnamed) to locate data. + +EXAMPLES: +- user_input: List my last 10 datasets (newest first) +- user_input: List unnamed datasets`, inputSchema: zodToJsonSchema(getUserDatasetsListArgs), ajvValidate: ajv.compile(zodToJsonSchema(getUserDatasetsListArgs)), call: async (toolArgs) => { diff --git a/src/tools/fetch-actor-details.ts b/src/tools/fetch-actor-details.ts index c143bfcc..332ad070 100644 --- a/src/tools/fetch-actor-details.ts +++ b/src/tools/fetch-actor-details.ts @@ -17,16 +17,17 @@ export const fetchActorDetailsTool: ToolEntry = { type: 'internal', tool: { name: HelperTools.ACTOR_GET_DETAILS, - description: `Get detailed information about an Actor by its ID or full name. -This tool returns title, description, URL, README (Actor's documentation), input schema, and usage statistics. -The Actor name is always composed of "username/name", for example, "apify/rag-web-browser". -Present Actor information in user-friendly format as an Actor card. + description: `Get detailed information about an Actor by its ID or full name (format: "username/name", e.g., "apify/rag-web-browser"). +This returns the Actor’s title, description, URL, README (documentation), input schema, pricing/usage information, and basic stats. +Present the information in a user-friendly Actor card. + USAGE: -- Use when user asks about an Actor its details, description, input schema, etc. +- Use when a user asks about an Actor’s details, input schema, README, or how to use it. + EXAMPLES: - user_input: How to use apify/rag-web-browser -- user_input: What is the input schema for apify/rag-web-browser, -- user_input: What is pricing of apify/instagram-scraper?`, +- user_input: What is the input schema for apify/rag-web-browser? +- user_input: What is the pricing for apify/instagram-scraper?`, inputSchema: zodToJsonSchema(fetchActorDetailsToolArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(fetchActorDetailsToolArgsSchema)), call: async (toolArgs) => { diff --git a/src/tools/fetch-apify-docs.ts b/src/tools/fetch-apify-docs.ts index 4e3d36fb..073eb8ad 100644 --- a/src/tools/fetch-apify-docs.ts +++ b/src/tools/fetch-apify-docs.ts @@ -19,7 +19,15 @@ export const fetchApifyDocsTool: ToolEntry = { type: 'internal', tool: { name: HelperTools.DOCS_FETCH, - description: `Apify documentation fetch tool. This tool allows you to fetch the full content of an Apify documentation page by its URL.`, + description: `Fetch the full content of an Apify documentation page by its URL. +Use this after finding a relevant page with the ${HelperTools.DOCS_SEARCH} tool. + +USAGE: +- Use when you need the complete content of a specific docs page for detailed answers. + +EXAMPLES: +- user_input: Fetch https://docs.apify.com/platform/actors/running#builds +- user_input: Fetch https://docs.apify.com/academy`, args: fetchApifyDocsToolArgsSchema, inputSchema: zodToJsonSchema(fetchApifyDocsToolArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(fetchApifyDocsToolArgsSchema)), diff --git a/src/tools/get-actor-output.ts b/src/tools/get-actor-output.ts index cdae199e..30e6261b 100644 --- a/src/tools/get-actor-output.ts +++ b/src/tools/get-actor-output.ts @@ -68,19 +68,23 @@ export const getActorOutput: ToolEntry = { tool: { name: HelperTools.ACTOR_OUTPUT_GET, actorFullName: HelperTools.ACTOR_OUTPUT_GET, - description: `Fetch the dataset of a specific Actor run based on datasetId. -You can also retrieve only specific fields from the output if needed. + description: `Retrieve the output dataset items of a specific Actor run using its datasetId. +You can select specific fields to return (supports dot notation like "crawl.statusCode") and paginate results with offset and limit. +This tool is a simplified version of the get-dataset-items tool, focused on Actor run outputs. + +The results will include the dataset items from the specified dataset. If you provide fields, only those fields will be included (nested fields supported via dot notation). + +You can obtain the datasetId from an Actor run (e.g., after calling an Actor with the call-actor tool) or from the Apify Console (Runs → Run details → Dataset ID). USAGE: -- Use this tool to get Actor dataset outside of the preview, or to access fields from the Actor output -dataset schema that are not included in the preview. +- Use when you need to read Actor output data (full items or selected fields), especially when preview does not include all fields. EXAMPLES: -- user_input: Get data of my last Actor run? -- user_input: Get number_of_likes from my dataset? +- user_input: Get data of my last Actor run +- user_input: Get number_of_likes from my dataset +- user_input: Return only crawl.statusCode and url from dataset 8TtYhCwKzQeQk7dJx -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").`, +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").`, inputSchema: zodToJsonSchema(getActorOutputArgs), /** * Allow additional properties for Skyfire mode to pass `skyfire-pay-id`. diff --git a/src/tools/get-html-skeleton.ts b/src/tools/get-html-skeleton.ts index ea9674f4..4f258220 100644 --- a/src/tools/get-html-skeleton.ts +++ b/src/tools/get-html-skeleton.ts @@ -41,7 +41,17 @@ export const getHtmlSkeleton: ToolEntry = { tool: { name: HelperTools.GET_HTML_SKELETON, actorFullName: HelperTools.GET_HTML_SKELETON, - description: `Retrieves the HTML skeleton (clean structure) from a given URL by stripping unwanted elements like scripts, styles, and non-essential attributes. This tool keeps only the core HTML structure, links, images, and data attributes for analysis. Supports optional JavaScript rendering for dynamic content and provides chunked output to handle large HTML. This tool is useful for building web scrapers and data extraction tasks where a clean HTML structure is needed for writing concrete selectors or parsers.`, + description: `Retrieve the HTML skeleton (clean structure) of a webpage by stripping scripts, styles, and non-essential attributes. +This keeps the core HTML structure, links, images, and data attributes for analysis. Supports optional JavaScript rendering for dynamic pages. + +The results will include a chunked HTML skeleton if the content is large. Use the chunk parameter to paginate through the output. + +USAGE: +- Use when you need a clean HTML structure to design selectors or parsers for scraping. + +EXAMPLES: +- user_input: Get HTML skeleton for https://example.com +- user_input: Get next chunk of HTML skeleton for https://example.com (chunk=2)`, inputSchema: zodToJsonSchema(getHtmlSkeletonArgs), ajvValidate: ajv.compile(zodToJsonSchema(getHtmlSkeletonArgs)), call: async (toolArgs) => { diff --git a/src/tools/helpers.ts b/src/tools/helpers.ts index d030d793..fce5ca3d 100644 --- a/src/tools/helpers.ts +++ b/src/tools/helpers.ts @@ -15,12 +15,17 @@ export const addTool: ToolEntry = { type: 'internal', tool: { name: HelperTools.ACTOR_ADD, - description: `Add an Actor or MCP server to the available tools of the Apify MCP server.\n` - + 'A tool is an Actor or MCP server that can be called by the user.\n' - + 'Do not execute the tool, only add it and list it in the available tools.\n' - + 'For example, when a user wants to scrape a website, first search for relevant Actors\n' - + `using ${HelperTools.STORE_SEARCH} tool, and once the user selects one they want to use,\n` - + 'add it as a tool to the Apify MCP server.', + description: `Add an Actor or MCP server to the Apify MCP Server as an available tool. +This does not execute the Actor; it only registers it so it can be called later. + +You can first discover Actors using the ${HelperTools.STORE_SEARCH} tool, then add the selected Actor as a tool. + +USAGE: +- Use when a user has chosen an Actor to work with and you need to make it available as a callable tool. + +EXAMPLES: +- user_input: Add apify/rag-web-browser as a tool +- user_input: Add apify/instagram-scraper as a tool`, inputSchema: zodToJsonSchema(addToolArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(addToolArgsSchema)), // TODO: I don't like that we are passing apifyMcpServer and mcpServer to the tool diff --git a/src/tools/key_value_store.ts b/src/tools/key_value_store.ts index fe21d7e6..fe023f05 100644 --- a/src/tools/key_value_store.ts +++ b/src/tools/key_value_store.ts @@ -20,9 +20,15 @@ export const getKeyValueStore: ToolEntry = { tool: { name: HelperTools.KEY_VALUE_STORE_GET, actorFullName: HelperTools.KEY_VALUE_STORE_GET, - description: 'Gets an object that contains all the details about a specific key-value store. ' - + 'Returns store metadata including ID, name, owner, access settings, and usage statistics. ' - + 'Use store ID or username~store-name format to identify the store.', + description: `Get details about a key-value store by ID or username~store-name. +The results will include store metadata (ID, name, owner, access settings) and usage statistics. + +USAGE: +- Use when you need to inspect a store to locate records or understand its properties. + +EXAMPLES: +- user_input: Show info for key-value store username~my-store +- user_input: Get details for store 8TtYhCwKzQeQk7dJx`, inputSchema: zodToJsonSchema(getKeyValueStoreArgs), ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreArgs)), call: async (toolArgs) => { @@ -56,10 +62,16 @@ export const getKeyValueStoreKeys: ToolEntry = { tool: { name: HelperTools.KEY_VALUE_STORE_KEYS_GET, actorFullName: HelperTools.KEY_VALUE_STORE_KEYS_GET, - description: 'Returns a list of objects describing keys of a given key-value store, ' - + 'as well as some information about the values (e.g. size). ' - + 'Supports pagination using exclusiveStartKey and limit parameters. ' - + 'Use store ID or username~store-name format to identify the store.', + description: `List keys in a key-value store with optional pagination. +The results will include keys and basic info about stored values (e.g., size). +Use exclusiveStartKey and limit to paginate. + +USAGE: +- Use when you need to discover what records exist in a store. + +EXAMPLES: +- user_input: List first 100 keys in store username~my-store +- user_input: Continue listing keys in store 8TtYhCwKzQeQk7dJx from key data.json`, inputSchema: zodToJsonSchema(getKeyValueStoreKeysArgs), ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreKeysArgs)), call: async (toolArgs) => { @@ -92,11 +104,15 @@ export const getKeyValueStoreRecord: ToolEntry = { tool: { name: HelperTools.KEY_VALUE_STORE_RECORD_GET, actorFullName: HelperTools.KEY_VALUE_STORE_RECORD_GET, - description: 'Gets a value stored in the key-value store under a specific key. ' - + 'The response maintains the original Content-Encoding of the stored value. ' - + 'If the request does not specify the correct Accept-Encoding header, the record will be decompressed. ' - + 'Most HTTP clients handle decompression automatically.' - + 'The record can be accessed with the URL: GET: https://api.apify.com/v2/key-value-stores/:storeId/records/:recordKey', + description: `Get a value stored in a key-value store under a specific key. +The response preserves the original Content-Encoding; most clients handle decompression automatically. + +USAGE: +- Use when you need to retrieve a specific record (JSON, text, or binary) from a store. + +EXAMPLES: +- user_input: Get record INPUT from store 8TtYhCwKzQeQk7dJx +- user_input: Get record data.json from store username~my-store`, inputSchema: zodToJsonSchema(getKeyValueStoreRecordArgs), ajvValidate: ajv.compile(zodToJsonSchema(getKeyValueStoreRecordArgs)), call: async (toolArgs) => { diff --git a/src/tools/key_value_store_collection.ts b/src/tools/key_value_store_collection.ts index 9d82983d..f534c064 100644 --- a/src/tools/key_value_store_collection.ts +++ b/src/tools/key_value_store_collection.ts @@ -30,12 +30,18 @@ export const getUserKeyValueStoresList: ToolEntry = { tool: { name: HelperTools.KEY_VALUE_STORE_LIST_GET, actorFullName: HelperTools.KEY_VALUE_STORE_LIST_GET, - description: 'Lists key-value stores owned by the user. ' - + 'Actor runs automatically produce unnamed stores (use unnamed=true to include these). ' - + 'Users can also create named stores manually. ' - + 'Each store includes basic information about the store. ' - + 'Results are sorted by createdAt in ascending order (use desc=true for descending). ' - + 'Supports pagination with limit (max 1000) and offset parameters.', + description: `List key-value stores owned by the authenticated user. +Actor runs automatically produce unnamed stores (set unnamed=true to include them). Users can also create named stores. + +The results will include basic info for each store, sorted by createdAt (ascending by default). +Use limit, offset, and desc to paginate and sort. + +USAGE: +- Use when you need to browse available key-value stores (named or unnamed). + +EXAMPLES: +- user_input: List my last 10 key-value stores (newest first) +- user_input: List unnamed key-value stores`, inputSchema: zodToJsonSchema(getUserKeyValueStoresListArgs), ajvValidate: ajv.compile(zodToJsonSchema(getUserKeyValueStoresListArgs)), call: async (toolArgs) => { diff --git a/src/tools/run.ts b/src/tools/run.ts index 0319b192..fcd94833 100644 --- a/src/tools/run.ts +++ b/src/tools/run.ts @@ -27,9 +27,15 @@ export const getActorRun: ToolEntry = { tool: { name: HelperTools.ACTOR_RUNS_GET, actorFullName: HelperTools.ACTOR_RUNS_GET, - description: 'Gets detailed information about a specific Actor run including its status, status message, metrics, and resources. ' - + 'The response includes run metadata (ID, status, status message, timestamps), performance stats (CPU, memory, network), ' - + 'resource IDs (dataset, key-value store, request queue), and configuration options.', + description: `Get detailed information about a specific Actor run by runId. +The results will include run metadata (status, timestamps), performance stats, and resource IDs (datasetId, keyValueStoreId, requestQueueId). + +USAGE: +- Use when you need to inspect run status or retrieve associated resource IDs (e.g., datasetId for output). + +EXAMPLES: +- user_input: Show details of run y2h7sK3Wc +- user_input: What is the datasetId for run y2h7sK3Wc?`, inputSchema: zodToJsonSchema(getActorRunArgs), ajvValidate: ajv.compile(zodToJsonSchema(getActorRunArgs)), call: async (toolArgs) => { @@ -62,8 +68,15 @@ export const getActorRunLog: ToolEntry = { tool: { name: HelperTools.ACTOR_RUNS_LOG, actorFullName: HelperTools.ACTOR_RUNS_LOG, - description: 'Retrieves logs for a specific Actor run. ' - + 'Returns the log content as plain text.', + description: `Retrieve recent log lines for a specific Actor run. +The results will include the last N lines of the run’s log output (plain text). + +USAGE: +- Use when you need to inspect recent logs to debug or monitor a run. + +EXAMPLES: +- user_input: Show last 20 lines of logs for run y2h7sK3Wc +- user_input: Get logs for run y2h7sK3Wc`, inputSchema: zodToJsonSchema(GetRunLogArgs), ajvValidate: ajv.compile(zodToJsonSchema(GetRunLogArgs)), call: async (toolArgs) => { @@ -86,9 +99,16 @@ export const abortActorRun: ToolEntry = { tool: { name: HelperTools.ACTOR_RUNS_ABORT, actorFullName: HelperTools.ACTOR_RUNS_ABORT, - description: 'Aborts an Actor run that is currently starting or running. ' - + 'For runs with status FINISHED, FAILED, ABORTING, or TIMED-OUT, this call has no effect. ' - + 'Returns the updated run details after aborting.', + description: `Abort an Actor run that is currently starting or running. +For runs with status FINISHED, FAILED, ABORTING, or TIMED-OUT, this call has no effect. +The results will include the updated run details after the abort request. + +USAGE: +- Use when you need to stop a run that is taking too long or misconfigured. + +EXAMPLES: +- user_input: Abort run y2h7sK3Wc +- user_input: Gracefully abort run y2h7sK3Wc`, inputSchema: zodToJsonSchema(abortRunArgs), ajvValidate: ajv.compile(zodToJsonSchema(abortRunArgs)), call: async (toolArgs) => { diff --git a/src/tools/run_collection.ts b/src/tools/run_collection.ts index 2c564221..6f8b3922 100644 --- a/src/tools/run_collection.ts +++ b/src/tools/run_collection.ts @@ -30,9 +30,16 @@ export const getUserRunsList: ToolEntry = { tool: { name: HelperTools.ACTOR_RUN_LIST_GET, actorFullName: HelperTools.ACTOR_RUN_LIST_GET, - description: `Gets a paginated list of Actor runs with run details, datasetId, and keyValueStoreId.\n` - + 'Filter by status: READY (not allocated), RUNNING (executing), SUCCEEDED (finished), FAILED (failed),\n' - + 'TIMING-OUT (timing out), TIMED-OUT (timed out), ABORTING (being aborted), ABORTED (aborted).', + description: `List Actor runs for the authenticated user with optional filtering and sorting. +The results will include run details (including datasetId and keyValueStoreId) and can be filtered by status. +Valid statuses: READY (not allocated), RUNNING (executing), SUCCEEDED (finished), FAILED (failed), TIMING-OUT, TIMED-OUT, ABORTING, ABORTED. + +USAGE: +- Use when you need to browse or filter recent Actor runs. + +EXAMPLES: +- user_input: List my last 10 runs (newest first) +- user_input: Show only SUCCEEDED runs`, inputSchema: zodToJsonSchema(getUserRunsListArgs), ajvValidate: ajv.compile(zodToJsonSchema(getUserRunsListArgs)), call: async (toolArgs) => { diff --git a/src/tools/store_collection.ts b/src/tools/store_collection.ts index 4f39d3c3..368caa01 100644 --- a/src/tools/store_collection.ts +++ b/src/tools/store_collection.ts @@ -72,25 +72,20 @@ export const searchActors: ToolEntry = { tool: { name: HelperTools.STORE_SEARCH, description: `Search the Apify Store for Actors or Model Context Protocol (MCP) servers using keywords. -Apify is the largest platform for web scrapers, AI agents, and automation tools, called Actors. -The store features solutions for scraping Instagram, Twitter, TikTok, LinkedIn, Bookings, Flights and more. -All Actors are verified and comply with scraping guidelines. +Apify Store features solutions for web scraping, automation, and AI agents (e.g., Instagram, TikTok, LinkedIn, flights, bookings). -This tool returns a curated list of Actors, including their title, description, pricing model, usage statistics, and user ratings. +The results will include curated Actor cards with title, description, pricing model, usage statistics, and ratings. For best results, use simple space-separated keywords (e.g., "instagram posts", "twitter profile", "playwright mcp"). -You may need to run multiple searches to find the most suitable Actor. -Limit the number of results to keep responses relevant and concise. -Results are always presented as user-friendly Actor cards. +For detailed information about a specific Actor, use the ${HelperTools.ACTOR_GET_DETAILS} tool. USAGE: -- Use when a user wants to find Actors for a specific task -- Use when a user asks about specific data and available Actors in the Apify Store -- Use when a user needs to discover MCP servers or automation tools +- Use when you need to discover Actors for a specific task or find MCP servers. +- Use to explore available tools in the Apify ecosystem based on keywords. EXAMPLES: - user_input: Find Actors for scraping e-commerce - user_input: Find browserbase MCP server -- user_input: I need to scrape instagram profiles/comments +- user_input: I need to scrape instagram profiles and comments - user_input: I need to get flights and airbnb data`, inputSchema: zodToJsonSchema(searchActorsArgsSchema), ajvValidate: ajv.compile(zodToJsonSchema(searchActorsArgsSchema)), From 7f7969d3eadde9c593cc321334a8f33efb3ddeda Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Mon, 22 Sep 2025 15:00:30 +0200 Subject: [PATCH 4/5] fix: Review comments --- docs/claude-code-tools.json | 508 ++++++++++++++++++++++++ src/tools/actor.ts | 9 +- src/tools/dataset.ts | 6 +- src/tools/dataset_collection.ts | 2 +- src/tools/fetch-actor-details.ts | 2 +- src/tools/fetch-apify-docs.ts | 2 +- src/tools/get-actor-output.ts | 2 +- src/tools/get-html-skeleton.ts | 2 +- src/tools/helpers.ts | 2 +- src/tools/key_value_store.ts | 6 +- src/tools/key_value_store_collection.ts | 2 +- src/tools/run.ts | 6 +- src/tools/run_collection.ts | 2 +- src/tools/search-apify-docs.ts | 2 +- src/tools/store_collection.ts | 2 +- 15 files changed, 531 insertions(+), 24 deletions(-) create mode 100644 docs/claude-code-tools.json diff --git a/docs/claude-code-tools.json b/docs/claude-code-tools.json new file mode 100644 index 00000000..c1f68f3f --- /dev/null +++ b/docs/claude-code-tools.json @@ -0,0 +1,508 @@ +{ + "tools": [ + { + "name": "Task", + "description": "Launch a new agent to handle complex, multi-step tasks autonomously. \n\nAvailable agent types and the tools they have access to:\n- general-purpose: General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. (Tools: *)\n- statusline-setup: Use this agent to configure the user's Claude Code status line setting. (Tools: Read, Edit)\n- output-style-setup: Use this agent to create a Claude Code output style. (Tools: Read, Write, Edit, Glob, LS, Grep)\n\nWhen using the Task tool, you must specify a subagent_type parameter to select which agent type to use.\n\n\n\nWhen NOT to use the Agent tool:\n- If you want to read a specific file path, use the Read or Glob tool instead of the Agent tool, to find the match more quickly\n- If you are searching for a specific class definition like \"class Foo\", use the Glob tool instead, to find the match more quickly\n- If you are searching for code within a specific file or set of 2-3 files, use the Read tool instead of the Agent tool, to find the match more quickly\n- Other tasks that are not related to the agent descriptions above\n\n\nUsage notes:\n1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses\n2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.\n3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.\n4. The agent's outputs should generally be trusted\n5. Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.), since it is not aware of the user's intent\n6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.\n\nExample usage:\n\n\n\"code-reviewer\": use this agent after you are done writing a signficant piece of code\n\"greeting-responder\": use this agent when to respond to user greetings with a friendly joke\n\n\n\nuser: \"Please write a function that checks if a number is prime\"\nassistant: Sure let me write a function that checks if a number is prime\nassistant: First let me use the Write tool to write a function that checks if a number is prime\nassistant: I'm going to use the Write tool to write the following code:\n\nfunction isPrime(n) {\n if (n <= 1) return false\n for (let i = 2; i * i <= n; i++) {\n if (n % i === 0) return false\n }\n return true\n}\n\n\nSince a signficant piece of code was written and the task was completed, now use the code-reviewer agent to review the code\n\nassistant: Now let me use the code-reviewer agent to review the code\nassistant: Uses the Task tool to launch the with the code-reviewer agent \n\n\n\nuser: \"Hello\"\n\nSince the user is greeting, use the greeting-responder agent to respond with a friendly joke\n\nassistant: \"I'm going to use the Task tool to launch the with the greeting-responder agent\"\n\n", + "input_schema": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "A short (3-5 word) description of the task" + }, + "prompt": { + "type": "string", + "description": "The task for the agent to perform" + }, + "subagent_type": { + "type": "string", + "description": "The type of specialized agent to use for this task" + } + }, + "required": [ + "description", + "prompt", + "subagent_type" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "Bash", + "description": "Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.\n\nBefore executing the command, please follow these steps:\n\n1. Directory Verification:\n - If the command will create new directories or files, first use the LS tool to verify the parent directory exists and is the correct location\n - For example, before running \"mkdir foo/bar\", first use LS to check that \"foo\" exists and is the intended parent directory\n\n2. Command Execution:\n - Always quote file paths that contain spaces with double quotes (e.g., cd \"path with spaces/file.txt\")\n - Examples of proper quoting:\n - cd \"/Users/name/My Documents\" (correct)\n - cd /Users/name/My Documents (incorrect - will fail)\n - python \"/path/with spaces/script.py\" (correct)\n - python /path/with spaces/script.py (incorrect - will fail)\n - After ensuring proper quoting, execute the command.\n - Capture the output of the command.\n\nUsage notes:\n - The command argument is required.\n - You can specify an optional timeout in milliseconds (up to 600000ms / 10 minutes). If not specified, commands will timeout after 120000ms (2 minutes).\n - It is very helpful if you write a clear, concise description of what this command does in 5-10 words.\n - If the output exceeds 30000 characters, output will be truncated before being returned to you.\n - You can use the `run_in_background` parameter to run the command in the background, which allows you to continue working while the command runs. You can monitor the output using the Bash tool as it becomes available. Never use `run_in_background` to run 'sleep' as it will return immediately. You do not need to use '&' at the end of the command when using this parameter.\n - VERY IMPORTANT: You MUST avoid using search commands like `find` and `grep`. Instead use Grep, Glob, or Task to search. You MUST avoid read tools like `cat`, `head`, `tail`, and `ls`, and use Read and LS to read files.\n - If you _still_ need to run `grep`, STOP. ALWAYS USE ripgrep at `rg` first, which all Claude Code users have pre-installed.\n - When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings).\n - Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of `cd`. You may use `cd` if the User explicitly requests it.\n \n pytest /foo/bar/tests\n \n \n cd /foo/bar && pytest tests\n \n\n\n# Committing changes with git\n\nWhen the user asks you to create a new git commit, follow these steps carefully:\n\n1. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following bash commands in parallel, each using the Bash tool:\n - Run a git status command to see all untracked files.\n - Run a git diff command to see both staged and unstaged changes that will be committed.\n - Run a git log command to see recent commit messages, so that you can follow this repository's commit message style.\n2. Analyze all staged changes (both previously staged and newly added) and draft a commit message:\n - Summarize the nature of the changes (eg. new feature, enhancement to an existing feature, bug fix, refactoring, test, docs, etc.). Ensure the message accurately reflects the changes and their purpose (i.e. \"add\" means a wholly new feature, \"update\" means an enhancement to an existing feature, \"fix\" means a bug fix, etc.).\n - Check for any sensitive information that shouldn't be committed\n - Draft a concise (1-2 sentences) commit message that focuses on the \"why\" rather than the \"what\"\n - Ensure it accurately reflects the changes and their purpose\n3. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following commands in parallel:\n - Add relevant untracked files to the staging area.\n - Create the commit with a message ending with:\n 🤖 Generated with [Claude Code](https://claude.ai/code)\n\n Co-Authored-By: Claude \n - Run git status to make sure the commit succeeded.\n4. If the commit fails due to pre-commit hook changes, retry the commit ONCE to include these automated changes. If it fails again, it usually means a pre-commit hook is preventing the commit. If the commit succeeds but you notice that files were modified by the pre-commit hook, you MUST amend your commit to include them.\n\nImportant notes:\n- NEVER update the git config\n- NEVER run additional commands to read or explore code, besides git bash commands\n- NEVER use the TodoWrite or Task tools\n- DO NOT push to the remote repository unless the user explicitly asks you to do so\n- IMPORTANT: Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported.\n- If there are no changes to commit (i.e., no untracked files and no modifications), do not create an empty commit\n- In order to ensure good formatting, ALWAYS pass the commit message via a HEREDOC, a la this example:\n\ngit commit -m \"$(cat <<'EOF'\n Commit message here.\n\n 🤖 Generated with [Claude Code](https://claude.ai/code)\n\n Co-Authored-By: Claude \n EOF\n )\"\n\n\n# Creating pull requests\nUse the gh command via the Bash tool for ALL GitHub-related tasks including working with issues, pull requests, checks, and releases. If given a Github URL use the gh command to get the information needed.\n\nIMPORTANT: When the user asks you to create a pull request, follow these steps carefully:\n\n1. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following bash commands in parallel using the Bash tool, in order to understand the current state of the branch since it diverged from the main branch:\n - Run a git status command to see all untracked files\n - Run a git diff command to see both staged and unstaged changes that will be committed\n - Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote\n - Run a git log command and `git diff [base-branch]...HEAD` to understand the full commit history for the current branch (from the time it diverged from the base branch)\n2. Analyze all changes that will be included in the pull request, making sure to look at all relevant commits (NOT just the latest commit, but ALL commits that will be included in the pull request!!!), and draft a pull request summary\n3. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following commands in parallel:\n - Create new branch if needed\n - Push to remote with -u flag if needed\n - Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.\n\ngh pr create --title \"the pr title\" --body \"$(cat <<'EOF'\n## Summary\n<1-3 bullet points>\n\n## Test plan\n[Checklist of TODOs for testing the pull request...]\n\n🤖 Generated with [Claude Code](https://claude.ai/code)\nEOF\n)\"\n\n\nImportant:\n- NEVER update the git config\n- DO NOT use the TodoWrite or Task tools\n- Return the PR URL when you're done, so the user can see it\n\n# Other common operations\n- View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments", + "input_schema": { + "type": "object", + "properties": { + "command": { + "type": "string", + "description": "The command to execute" + }, + "timeout": { + "type": "number", + "description": "Optional timeout in milliseconds (max 600000)" + }, + "description": { + "type": "string", + "description": " Clear, concise description of what this command does in 5-10 words. Examples:\nInput: ls\nOutput: Lists files in current directory\n\nInput: git status\nOutput: Shows working tree status\n\nInput: npm install\nOutput: Installs package dependencies\n\nInput: mkdir foo\nOutput: Creates directory 'foo'" + }, + "run_in_background": { + "type": "boolean", + "description": "Set to true to run this command in the background. Use BashOutput to read the output later." + } + }, + "required": [ + "command" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "Glob", + "description": "- Fast file pattern matching tool that works with any codebase size\n- Supports glob patterns like \"**/*.js\" or \"src/**/*.ts\"\n- Returns matching file paths sorted by modification time\n- Use this tool when you need to find files by name patterns\n- When you are doing an open ended search that may require multiple rounds of globbing and grepping, use the Agent tool instead\n- You have the capability to call multiple tools in a single response. It is always better to speculatively perform multiple searches as a batch that are potentially useful.", + "input_schema": { + "type": "object", + "properties": { + "pattern": { + "type": "string", + "description": "The glob pattern to match files against" + }, + "path": { + "type": "string", + "description": "The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter \"undefined\" or \"null\" - simply omit it for the default behavior. Must be a valid directory path if provided." + } + }, + "required": [ + "pattern" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "Grep", + "description": "A powerful search tool built on ripgrep\n\n Usage:\n - ALWAYS use Grep for search tasks. NEVER invoke `grep` or `rg` as a Bash command. The Grep tool has been optimized for correct permissions and access.\n - Supports full regex syntax (e.g., \"log.*Error\", \"function\\s+\\w+\")\n - Filter files with glob parameter (e.g., \"*.js\", \"**/*.tsx\") or type parameter (e.g., \"js\", \"py\", \"rust\")\n - Output modes: \"content\" shows matching lines, \"files_with_matches\" shows only file paths (default), \"count\" shows match counts\n - Use Task tool for open-ended searches requiring multiple rounds\n - Pattern syntax: Uses ripgrep (not grep) - literal braces need escaping (use `interface\\{\\}` to find `interface{}` in Go code)\n - Multiline matching: By default patterns match within single lines only. For cross-line patterns like `struct \\{[\\s\\S]*?field`, use `multiline: true`\n", + "input_schema": { + "type": "object", + "properties": { + "pattern": { + "type": "string", + "description": "The regular expression pattern to search for in file contents" + }, + "path": { + "type": "string", + "description": "File or directory to search in (rg PATH). Defaults to current working directory." + }, + "glob": { + "type": "string", + "description": "Glob pattern to filter files (e.g. \"*.js\", \"*.{ts,tsx}\") - maps to rg --glob" + }, + "output_mode": { + "type": "string", + "enum": [ + "content", + "files_with_matches", + "count" + ], + "description": "Output mode: \"content\" shows matching lines (supports -A/-B/-C context, -n line numbers, head_limit), \"files_with_matches\" shows file paths (supports head_limit), \"count\" shows match counts (supports head_limit). Defaults to \"files_with_matches\"." + }, + "-B": { + "type": "number", + "description": "Number of lines to show before each match (rg -B). Requires output_mode: \"content\", ignored otherwise." + }, + "-A": { + "type": "number", + "description": "Number of lines to show after each match (rg -A). Requires output_mode: \"content\", ignored otherwise." + }, + "-C": { + "type": "number", + "description": "Number of lines to show before and after each match (rg -C). Requires output_mode: \"content\", ignored otherwise." + }, + "-n": { + "type": "boolean", + "description": "Show line numbers in output (rg -n). Requires output_mode: \"content\", ignored otherwise." + }, + "-i": { + "type": "boolean", + "description": "Case insensitive search (rg -i)" + }, + "type": { + "type": "string", + "description": "File type to search (rg --type). Common types: js, py, rust, go, java, etc. More efficient than include for standard file types." + }, + "head_limit": { + "type": "number", + "description": "Limit output to first N lines/entries, equivalent to \"| head -N\". Works across all output modes: content (limits output lines), files_with_matches (limits file paths), count (limits count entries). When unspecified, shows all results from ripgrep." + }, + "multiline": { + "type": "boolean", + "description": "Enable multiline mode where . matches newlines and patterns can span lines (rg -U --multiline-dotall). Default: false." + } + }, + "required": [ + "pattern" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "LS", + "description": "Lists files and directories in a given path. The path parameter must be an absolute path, not a relative path. You can optionally provide an array of glob patterns to ignore with the ignore parameter. You should generally prefer the Glob and Grep tools, if you know which directories to search.", + "input_schema": { + "type": "object", + "properties": { + "path": { + "type": "string", + "description": "The absolute path to the directory to list (must be absolute, not relative)" + }, + "ignore": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of glob patterns to ignore" + } + }, + "required": [ + "path" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "ExitPlanMode", + "description": "Use this tool when you are in plan mode and have finished presenting your plan and are ready to code. This will prompt the user to exit plan mode. \nIMPORTANT: Only use this tool when the task requires planning the implementation steps of a task that requires writing code. For research tasks where you're gathering information, searching files, reading files or in general trying to understand the codebase - do NOT use this tool.\n\nEg. \n1. Initial task: \"Search for and understand the implementation of vim mode in the codebase\" - Do not use the exit plan mode tool because you are not planning the implementation steps of a task.\n2. Initial task: \"Help me implement yank mode for vim\" - Use the exit plan mode tool after you have finished planning the implementation steps of the task.\n", + "input_schema": { + "type": "object", + "properties": { + "plan": { + "type": "string", + "description": "The plan you came up with, that you want to run by the user for approval. Supports markdown. The plan should be pretty concise." + } + }, + "required": [ + "plan" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "Read", + "description": "Reads a file from the local filesystem. You can access any file directly by using this tool.\nAssume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.\n\nUsage:\n- The file_path parameter must be an absolute path, not a relative path\n- By default, it reads up to 2000 lines starting from the beginning of the file\n- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters\n- Any lines longer than 2000 characters will be truncated\n- Results are returned using cat -n format, with line numbers starting at 1\n- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.\n- This tool can read PDF files (.pdf). PDFs are processed page by page, extracting both text and visual content for analysis.\n- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.\n- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful. \n- You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png\n- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.", + "input_schema": { + "type": "object", + "properties": { + "file_path": { + "type": "string", + "description": "The absolute path to the file to read" + }, + "offset": { + "type": "number", + "description": "The line number to start reading from. Only provide if the file is too large to read at once" + }, + "limit": { + "type": "number", + "description": "The number of lines to read. Only provide if the file is too large to read at once." + } + }, + "required": [ + "file_path" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "Edit", + "description": "Performs exact string replacements in files. \n\nUsage:\n- You must use your `Read` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file. \n- When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if `old_string` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use `replace_all` to change every instance of `old_string`. \n- Use `replace_all` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.", + "input_schema": { + "type": "object", + "properties": { + "file_path": { + "type": "string", + "description": "The absolute path to the file to modify" + }, + "old_string": { + "type": "string", + "description": "The text to replace" + }, + "new_string": { + "type": "string", + "description": "The text to replace it with (must be different from old_string)" + }, + "replace_all": { + "type": "boolean", + "default": false, + "description": "Replace all occurences of old_string (default false)" + } + }, + "required": [ + "file_path", + "old_string", + "new_string" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "MultiEdit", + "description": "This is a tool for making multiple edits to a single file in one operation. It is built on top of the Edit tool and allows you to perform multiple find-and-replace operations efficiently. Prefer this tool over the Edit tool when you need to make multiple edits to the same file.\n\nBefore using this tool:\n\n1. Use the Read tool to understand the file's contents and context\n2. Verify the directory path is correct\n\nTo make multiple file edits, provide the following:\n1. file_path: The absolute path to the file to modify (must be absolute, not relative)\n2. edits: An array of edit operations to perform, where each edit contains:\n - old_string: The text to replace (must match the file contents exactly, including all whitespace and indentation)\n - new_string: The edited text to replace the old_string\n - replace_all: Replace all occurences of old_string. This parameter is optional and defaults to false.\n\nIMPORTANT:\n- All edits are applied in sequence, in the order they are provided\n- Each edit operates on the result of the previous edit\n- All edits must be valid for the operation to succeed - if any edit fails, none will be applied\n- This tool is ideal when you need to make several changes to different parts of the same file\n- For Jupyter notebooks (.ipynb files), use the NotebookEdit instead\n\nCRITICAL REQUIREMENTS:\n1. All edits follow the same requirements as the single Edit tool\n2. The edits are atomic - either all succeed or none are applied\n3. Plan your edits carefully to avoid conflicts between sequential operations\n\nWARNING:\n- The tool will fail if edits.old_string doesn't match the file contents exactly (including whitespace)\n- The tool will fail if edits.old_string and edits.new_string are the same\n- Since edits are applied in sequence, ensure that earlier edits don't affect the text that later edits are trying to find\n\nWhen making edits:\n- Ensure all edits result in idiomatic, correct code\n- Do not leave the code in a broken state\n- Always use absolute file paths (starting with /)\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.\n\nIf you want to create a new file, use:\n- A new file path, including dir name if needed\n- First edit: empty old_string and the new file's contents as new_string\n- Subsequent edits: normal edit operations on the created content", + "input_schema": { + "type": "object", + "properties": { + "file_path": { + "type": "string", + "description": "The absolute path to the file to modify" + }, + "edits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "old_string": { + "type": "string", + "description": "The text to replace" + }, + "new_string": { + "type": "string", + "description": "The text to replace it with" + }, + "replace_all": { + "type": "boolean", + "default": false, + "description": "Replace all occurences of old_string (default false)." + } + }, + "required": [ + "old_string", + "new_string" + ], + "additionalProperties": false + }, + "minItems": 1, + "description": "Array of edit operations to perform sequentially on the file" + } + }, + "required": [ + "file_path", + "edits" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "Write", + "description": "Writes a file to the local filesystem.\n\nUsage:\n- This tool will overwrite the existing file if there is one at the provided path.\n- If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.\n- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.", + "input_schema": { + "type": "object", + "properties": { + "file_path": { + "type": "string", + "description": "The absolute path to the file to write (must be absolute, not relative)" + }, + "content": { + "type": "string", + "description": "The content to write to the file" + } + }, + "required": [ + "file_path", + "content" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "NotebookEdit", + "description": "Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_number is 0-indexed. Use edit_mode=insert to add a new cell at the index specified by cell_number. Use edit_mode=delete to delete the cell at the index specified by cell_number.", + "input_schema": { + "type": "object", + "properties": { + "notebook_path": { + "type": "string", + "description": "The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)" + }, + "cell_id": { + "type": "string", + "description": "The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified." + }, + "new_source": { + "type": "string", + "description": "The new source for the cell" + }, + "cell_type": { + "type": "string", + "enum": [ + "code", + "markdown" + ], + "description": "The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required." + }, + "edit_mode": { + "type": "string", + "enum": [ + "replace", + "insert", + "delete" + ], + "description": "The type of edit to make (replace, insert, delete). Defaults to replace." + } + }, + "required": [ + "notebook_path", + "new_source" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "WebFetch", + "description": "\n- Fetches content from a specified URL and processes it using an AI model\n- Takes a URL and a prompt as input\n- Fetches the URL content, converts HTML to markdown\n- Processes the content with the prompt using a small, fast model\n- Returns the model's response about the content\n- Use this tool when you need to retrieve and analyze web content\n\nUsage notes:\n - IMPORTANT: If an MCP-provided web fetch tool is available, prefer using that tool instead of this one, as it may have fewer restrictions. All MCP-provided tools start with \"mcp__\".\n - The URL must be a fully-formed valid URL\n - HTTP URLs will be automatically upgraded to HTTPS\n - The prompt should describe what information you want to extract from the page\n - This tool is read-only and does not modify any files\n - Results may be summarized if the content is very large\n - Includes a self-cleaning 15-minute cache for faster responses when repeatedly accessing the same URL\n - When a URL redirects to a different host, the tool will inform you and provide the redirect URL in a special format. You should then make a new WebFetch request with the redirect URL to fetch the content.\n", + "input_schema": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The URL to fetch content from" + }, + "prompt": { + "type": "string", + "description": "The prompt to run on the fetched content" + } + }, + "required": [ + "url", + "prompt" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "TodoWrite", + "description": "Use this tool to create and manage a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.\nIt also helps the user understand the progress of the task and overall progress of their requests.\n\n## When to Use This Tool\nUse this tool proactively in these scenarios:\n\n1. Complex multi-step tasks - When a task requires 3 or more distinct steps or actions\n2. Non-trivial and complex tasks - Tasks that require careful planning or multiple operations\n3. User explicitly requests todo list - When the user directly asks you to use the todo list\n4. User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)\n5. After receiving new instructions - Immediately capture user requirements as todos\n6. When you start working on a task - Mark it as in_progress BEFORE beginning work. Ideally you should only have one todo as in_progress at a time\n7. After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation\n\n## When NOT to Use This Tool\n\nSkip using this tool when:\n1. There is only a single, straightforward task\n2. The task is trivial and tracking it provides no organizational benefit\n3. The task can be completed in less than 3 trivial steps\n4. The task is purely conversational or informational\n\nNOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.\n\n## Examples of When to Use the Todo List\n\n\nUser: I want to add a dark mode toggle to the application settings. Make sure you run the tests and build when you're done!\nAssistant: I'll help add a dark mode toggle to your application settings. Let me create a todo list to track this implementation.\n*Creates todo list with the following items:*\n1. Create dark mode toggle component in Settings page\n2. Add dark mode state management (context/store)\n3. Implement CSS-in-JS styles for dark theme\n4. Update existing components to support theme switching\n5. Run tests and build process, addressing any failures or errors that occur\n*Begins working on the first task*\n\n\nThe assistant used the todo list because:\n1. Adding dark mode is a multi-step feature requiring UI, state management, and styling changes\n2. The user explicitly requested tests and build be run afterward\n3. The assistant inferred that tests and build need to pass by adding \"Ensure tests and build succeed\" as the final task\n\n\n\n\nUser: Help me rename the function getCwd to getCurrentWorkingDirectory across my project\nAssistant: Let me first search through your codebase to find all occurrences of 'getCwd'.\n*Uses grep or search tools to locate all instances of getCwd in the codebase*\nAssistant: I've found 15 instances of 'getCwd' across 8 different files. Let me create a todo list to track these changes.\n*Creates todo list with specific items for each file that needs updating*\n\n\nThe assistant used the todo list because:\n1. First, the assistant searched to understand the scope of the task\n2. Upon finding multiple occurrences across different files, it determined this was a complex task with multiple steps\n3. The todo list helps ensure every instance is tracked and updated systematically\n4. This approach prevents missing any occurrences and maintains code consistency\n\n\n\n\n\nUser: I need to implement these features for my e-commerce site: user registration, product catalog, shopping cart, and checkout flow.\nAssistant: I'll help implement these features. First, let's add all the features to the todo list.\n*Creates a todo list breaking down each feature into specific tasks based on the project architecture*\nAssistant: Let's start with user registration. This will involve creating database models, API endpoints, and frontend forms that integrate with your existing authentication system.\n\n\nThe assistant used the todo list because:\n1. The user provided multiple complex features to implement in a comma separated list\n2. The todo list helps organize these large features into manageable tasks\n3. This approach allows for tracking progress across the entire implementation\n\n\n\n\nUser: Can you help optimize my React application? It's rendering slowly and has performance issues.\nAssistant: I'll help optimize your React application. First, let me examine your codebase to identify potential performance bottlenecks.\n*Reviews component structure, render patterns, state management, and data fetching*\nAssistant: After analyzing your codebase, I've identified several performance issues. Let me create a todo list to track our optimization efforts.\n*Creates todo list with items like: 1) Implement memoization for expensive calculations in ProductList, 2) Add virtualization for long lists in Dashboard, 3) Optimize image loading in Gallery component, 4) Fix state update loops in ShoppingCart, 5) Review bundle size and implement code splitting*\nLet's start by implementing memoization for the expensive calculations in your ProductList component.\n\n\nThe assistant used the todo list because:\n1. First, the assistant examined the codebase to identify specific performance issues\n2. Based on this analysis, it identified multiple optimization opportunities\n3. Performance optimization is a non-trivial task requiring multiple steps\n4. The todo list helps methodically track improvements across different components\n5. This systematic approach ensures all performance bottlenecks are addressed\n\n\n\n## Examples of When NOT to Use the Todo List\n\n\nUser: How do I print 'Hello World' in Python?\nAssistant: In Python, you can print \"Hello World\" with this simple code:\n\npython\nprint(\"Hello World\")\n\nThis will output the text \"Hello World\" to the console when executed.\n\n\nThe assistant did not use the todo list because this is a single, trivial task that can be completed in one step. There's no need to track multiple tasks or steps for such a straightforward request.\n\n\n\n\nUser: What does the git status command do?\nAssistant: The git status command shows the current state of your working directory and staging area. It displays which changes have been staged, which haven't, and which files aren't being tracked by Git. This is a fundamental command for understanding the current state of your repository before making commits.\n\n\nThe assistant did not use the todo list because this is an informational request with no actual coding task to complete. The user is simply asking for an explanation, not for the assistant to perform multiple steps or tasks.\n\n\n\n\nUser: Can you add a comment to the calculateTotal function to explain what it does?\nAssistant: Sure, let me add a comment to the calculateTotal function to explain what it does.\n* Uses the Edit tool to add a comment to the calculateTotal function *\n\n\nThe assistant did not use the todo list because this is a single, straightforward task confined to one location in the code. Adding a comment doesn't require tracking multiple steps or systematic organization.\n\n\n\n\nUser: Run npm install for me and tell me what happens.\nAssistant: I'll run the npm install command for you.\n\n*Executes: npm install*\n\nThe command completed successfully. Here's the output:\n[Output of npm install command]\n\nAll dependencies have been installed according to your package.json file.\n\n\nThe assistant did not use the todo list because this is a single command execution with immediate results. There are no multiple steps to track or organize, making the todo list unnecessary for this straightforward task.\n\n\n\n## Task States and Management\n\n1. **Task States**: Use these states to track progress:\n - pending: Task not yet started\n - in_progress: Currently working on (limit to ONE task at a time)\n - completed: Task finished successfully\n\n2. **Task Management**:\n - Update task status in real-time as you work\n - Mark tasks complete IMMEDIATELY after finishing (don't batch completions)\n - Only have ONE task in_progress at any time\n - Complete current tasks before starting new ones\n - Remove tasks that are no longer relevant from the list entirely\n\n3. **Task Completion Requirements**:\n - ONLY mark a task as completed when you have FULLY accomplished it\n - If you encounter errors, blockers, or cannot finish, keep the task as in_progress\n - When blocked, create a new task describing what needs to be resolved\n - Never mark a task as completed if:\n - Tests are failing\n - Implementation is partial\n - You encountered unresolved errors\n - You couldn't find necessary files or dependencies\n\n4. **Task Breakdown**:\n - Create specific, actionable items\n - Break complex tasks into smaller, manageable steps\n - Use clear, descriptive task names\n\nWhen in doubt, use this tool. Being proactive with task management demonstrates attentiveness and ensures you complete all requirements successfully.\n", + "input_schema": { + "type": "object", + "properties": { + "todos": { + "type": "array", + "items": { + "type": "object", + "properties": { + "content": { + "type": "string", + "minLength": 1 + }, + "status": { + "type": "string", + "enum": [ + "pending", + "in_progress", + "completed" + ] + }, + "id": { + "type": "string" + } + }, + "required": [ + "content", + "status", + "id" + ], + "additionalProperties": false + }, + "description": "The updated todo list" + } + }, + "required": [ + "todos" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "WebSearch", + "description": "\n- Allows Claude to search the web and use the results to inform responses\n- Provides up-to-date information for current events and recent data\n- Returns search result information formatted as search result blocks\n- Use this tool for accessing information beyond Claude's knowledge cutoff\n- Searches are performed automatically within a single API call\n\nUsage notes:\n - Domain filtering is supported to include or block specific websites\n - Web search is only available in the US\n - Account for \"Today's date\" in . For example, if says \"Today's date: 2025-07-01\", and the user wants the latest docs, do not use 2024 in the search query. Use 2025.\n", + "input_schema": { + "type": "object", + "properties": { + "query": { + "type": "string", + "minLength": 2, + "description": "The search query to use" + }, + "allowed_domains": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Only include search results from these domains" + }, + "blocked_domains": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Never include search results from these domains" + } + }, + "required": [ + "query" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "BashOutput", + "description": "\n- Retrieves output from a running or completed background bash shell\n- Takes a shell_id parameter identifying the shell\n- Always returns only new output since the last check\n- Returns stdout and stderr output along with shell status\n- Supports optional regex filtering to show only lines matching a pattern\n- Use this tool when you need to monitor or check the output of a long-running shell\n- Shell IDs can be found using the /bashes command\n", + "input_schema": { + "type": "object", + "properties": { + "bash_id": { + "type": "string", + "description": "The ID of the background shell to retrieve output from" + }, + "filter": { + "type": "string", + "description": "Optional regular expression to filter the output lines. Only lines matching this regex will be included in the result. Any lines that do not match will no longer be available to read." + } + }, + "required": [ + "bash_id" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + }, + { + "name": "KillBash", + "description": "\n- Kills a running background bash shell by its ID\n- Takes a shell_id parameter identifying the shell to kill\n- Returns a success or failure status \n- Use this tool when you need to terminate a long-running shell\n- Shell IDs can be found using the /bashes command\n", + "input_schema": { + "type": "object", + "properties": { + "shell_id": { + "type": "string", + "description": "The ID of the background shell to kill" + } + }, + "required": [ + "shell_id" + ], + "additionalProperties": false, + "$schema": "http://json-schema.org/draft-07/schema#" + } + } + ] +} diff --git a/src/tools/actor.ts b/src/tools/actor.ts index 0cb5e50d..93575dcb 100644 --- a/src/tools/actor.ts +++ b/src/tools/actor.ts @@ -244,8 +244,7 @@ async function getMCPServersAsTools( // Skip this Actor, connectMCPClient will log the error return []; } - const serverTools = await getMCPServerTools(actorId, client, mcpServerUrl); - return serverTools; + return await getMCPServerTools(actorId, client, mcpServerUrl); } finally { if (client) await client.close(); } @@ -340,7 +339,7 @@ There are two ways to run Actors: **Important:** -A successful run returns a \`datasetId\` (the Actor's output stored as an Apify dataset) and a short preview of items. +Typically, a successful run returns a \`datasetId\` (the Actor's output stored as an Apify dataset) and a short preview of items. To fetch the full output, use the ${HelperTools.ACTOR_OUTPUT_GET} tool with the \`datasetId\`. USAGE: @@ -354,8 +353,8 @@ Step 1: Get Actor Info (step="info", default) - You MUST do this step first - it's required to understand how to call the Actor Step 2: Call Actor (step="call") -- Only after step 1, call again with step="call" and proper input based on the schema -- This calls and runs the Actor. It will create an output as an Apify dataset (with datasetId). +- Only after step 1, call this tool again with step="call" and proper input based on the schema +- This runs the Actor. It will create an output as an Apify dataset (with datasetId). - This step returns a dataset preview, typically JSON-formatted tabular data. EXAMPLES: diff --git a/src/tools/dataset.ts b/src/tools/dataset.ts index be349817..55e0b726 100644 --- a/src/tools/dataset.ts +++ b/src/tools/dataset.ts @@ -54,7 +54,7 @@ Note: itemCount updates may be delayed by up to ~5 seconds. USAGE: - Use when you need dataset metadata to understand its structure before fetching items. -EXAMPLES: +USAGE EXAMPLES: - user_input: Show info for dataset 8TtYhCwKzQeQk7dJx - user_input: What fields does username~my-dataset have?`, inputSchema: zodToJsonSchema(getDatasetArgs), @@ -89,7 +89,7 @@ The results will include items along with pagination info (limit, offset) and to USAGE: - Use when you need to read data from a dataset (all items or only selected fields). -EXAMPLES: +USAGE EXAMPLES: - user_input: Get first 100 items from dataset 8TtYhCwKzQeQk7dJx - user_input: Get only metadata.url and title from dataset username~my-dataset (flatten metadata)`, inputSchema: zodToJsonSchema(getDatasetItemsArgs), @@ -151,7 +151,7 @@ Use this to understand the dataset before fetching many items. USAGE: - Use when you need to infer the structure of dataset items for downstream processing or validation. -EXAMPLES: +USAGE EXAMPLES: - user_input: Generate schema for dataset 8TtYhCwKzQeQk7dJx using 10 items - user_input: Show schema of username~my-dataset (clean items only)`, inputSchema: zodToJsonSchema(getDatasetSchemaArgs), diff --git a/src/tools/dataset_collection.ts b/src/tools/dataset_collection.ts index 1e025d51..fb172274 100644 --- a/src/tools/dataset_collection.ts +++ b/src/tools/dataset_collection.ts @@ -39,7 +39,7 @@ Use limit (max 20), offset, and desc to paginate and sort. USAGE: - Use when you need to browse available datasets (named or unnamed) to locate data. -EXAMPLES: +USAGE EXAMPLES: - user_input: List my last 10 datasets (newest first) - user_input: List unnamed datasets`, inputSchema: zodToJsonSchema(getUserDatasetsListArgs), diff --git a/src/tools/fetch-actor-details.ts b/src/tools/fetch-actor-details.ts index 332ad070..1fb22f39 100644 --- a/src/tools/fetch-actor-details.ts +++ b/src/tools/fetch-actor-details.ts @@ -24,7 +24,7 @@ Present the information in a user-friendly Actor card. USAGE: - Use when a user asks about an Actor’s details, input schema, README, or how to use it. -EXAMPLES: +USAGE EXAMPLES: - user_input: How to use apify/rag-web-browser - user_input: What is the input schema for apify/rag-web-browser? - user_input: What is the pricing for apify/instagram-scraper?`, diff --git a/src/tools/fetch-apify-docs.ts b/src/tools/fetch-apify-docs.ts index 073eb8ad..7eb80b94 100644 --- a/src/tools/fetch-apify-docs.ts +++ b/src/tools/fetch-apify-docs.ts @@ -25,7 +25,7 @@ Use this after finding a relevant page with the ${HelperTools.DOCS_SEARCH} tool. USAGE: - Use when you need the complete content of a specific docs page for detailed answers. -EXAMPLES: +USAGE EXAMPLES: - user_input: Fetch https://docs.apify.com/platform/actors/running#builds - user_input: Fetch https://docs.apify.com/academy`, args: fetchApifyDocsToolArgsSchema, diff --git a/src/tools/get-actor-output.ts b/src/tools/get-actor-output.ts index 30e6261b..098752d1 100644 --- a/src/tools/get-actor-output.ts +++ b/src/tools/get-actor-output.ts @@ -79,7 +79,7 @@ You can obtain the datasetId from an Actor run (e.g., after calling an Actor wit USAGE: - Use when you need to read Actor output data (full items or selected fields), especially when preview does not include all fields. -EXAMPLES: +USAGE EXAMPLES: - user_input: Get data of my last Actor run - user_input: Get number_of_likes from my dataset - user_input: Return only crawl.statusCode and url from dataset 8TtYhCwKzQeQk7dJx diff --git a/src/tools/get-html-skeleton.ts b/src/tools/get-html-skeleton.ts index 4f258220..ba73cdae 100644 --- a/src/tools/get-html-skeleton.ts +++ b/src/tools/get-html-skeleton.ts @@ -49,7 +49,7 @@ The results will include a chunked HTML skeleton if the content is large. Use th USAGE: - Use when you need a clean HTML structure to design selectors or parsers for scraping. -EXAMPLES: +USAGE EXAMPLES: - user_input: Get HTML skeleton for https://example.com - user_input: Get next chunk of HTML skeleton for https://example.com (chunk=2)`, inputSchema: zodToJsonSchema(getHtmlSkeletonArgs), diff --git a/src/tools/helpers.ts b/src/tools/helpers.ts index fce5ca3d..f5f2f8de 100644 --- a/src/tools/helpers.ts +++ b/src/tools/helpers.ts @@ -23,7 +23,7 @@ You can first discover Actors using the ${HelperTools.STORE_SEARCH} tool, then a USAGE: - Use when a user has chosen an Actor to work with and you need to make it available as a callable tool. -EXAMPLES: +USAGE EXAMPLES: - user_input: Add apify/rag-web-browser as a tool - user_input: Add apify/instagram-scraper as a tool`, inputSchema: zodToJsonSchema(addToolArgsSchema), diff --git a/src/tools/key_value_store.ts b/src/tools/key_value_store.ts index fe023f05..ae49af8c 100644 --- a/src/tools/key_value_store.ts +++ b/src/tools/key_value_store.ts @@ -26,7 +26,7 @@ The results will include store metadata (ID, name, owner, access settings) and u USAGE: - Use when you need to inspect a store to locate records or understand its properties. -EXAMPLES: +USAGE EXAMPLES: - user_input: Show info for key-value store username~my-store - user_input: Get details for store 8TtYhCwKzQeQk7dJx`, inputSchema: zodToJsonSchema(getKeyValueStoreArgs), @@ -69,7 +69,7 @@ Use exclusiveStartKey and limit to paginate. USAGE: - Use when you need to discover what records exist in a store. -EXAMPLES: +USAGE EXAMPLES: - user_input: List first 100 keys in store username~my-store - user_input: Continue listing keys in store 8TtYhCwKzQeQk7dJx from key data.json`, inputSchema: zodToJsonSchema(getKeyValueStoreKeysArgs), @@ -110,7 +110,7 @@ The response preserves the original Content-Encoding; most clients handle decomp USAGE: - Use when you need to retrieve a specific record (JSON, text, or binary) from a store. -EXAMPLES: +USAGE EXAMPLES: - user_input: Get record INPUT from store 8TtYhCwKzQeQk7dJx - user_input: Get record data.json from store username~my-store`, inputSchema: zodToJsonSchema(getKeyValueStoreRecordArgs), diff --git a/src/tools/key_value_store_collection.ts b/src/tools/key_value_store_collection.ts index f534c064..7f266c0f 100644 --- a/src/tools/key_value_store_collection.ts +++ b/src/tools/key_value_store_collection.ts @@ -39,7 +39,7 @@ Use limit, offset, and desc to paginate and sort. USAGE: - Use when you need to browse available key-value stores (named or unnamed). -EXAMPLES: +USAGE EXAMPLES: - user_input: List my last 10 key-value stores (newest first) - user_input: List unnamed key-value stores`, inputSchema: zodToJsonSchema(getUserKeyValueStoresListArgs), diff --git a/src/tools/run.ts b/src/tools/run.ts index fcd94833..6a053c51 100644 --- a/src/tools/run.ts +++ b/src/tools/run.ts @@ -33,7 +33,7 @@ The results will include run metadata (status, timestamps), performance stats, a USAGE: - Use when you need to inspect run status or retrieve associated resource IDs (e.g., datasetId for output). -EXAMPLES: +USAGE EXAMPLES: - user_input: Show details of run y2h7sK3Wc - user_input: What is the datasetId for run y2h7sK3Wc?`, inputSchema: zodToJsonSchema(getActorRunArgs), @@ -74,7 +74,7 @@ The results will include the last N lines of the run’s log output (plain text) USAGE: - Use when you need to inspect recent logs to debug or monitor a run. -EXAMPLES: +USAGE EXAMPLES: - user_input: Show last 20 lines of logs for run y2h7sK3Wc - user_input: Get logs for run y2h7sK3Wc`, inputSchema: zodToJsonSchema(GetRunLogArgs), @@ -106,7 +106,7 @@ The results will include the updated run details after the abort request. USAGE: - Use when you need to stop a run that is taking too long or misconfigured. -EXAMPLES: +USAGE EXAMPLES: - user_input: Abort run y2h7sK3Wc - user_input: Gracefully abort run y2h7sK3Wc`, inputSchema: zodToJsonSchema(abortRunArgs), diff --git a/src/tools/run_collection.ts b/src/tools/run_collection.ts index 6f8b3922..59abfeb2 100644 --- a/src/tools/run_collection.ts +++ b/src/tools/run_collection.ts @@ -37,7 +37,7 @@ Valid statuses: READY (not allocated), RUNNING (executing), SUCCEEDED (finished) USAGE: - Use when you need to browse or filter recent Actor runs. -EXAMPLES: +USAGE EXAMPLES: - user_input: List my last 10 runs (newest first) - user_input: Show only SUCCEEDED runs`, inputSchema: zodToJsonSchema(getUserRunsListArgs), diff --git a/src/tools/search-apify-docs.ts b/src/tools/search-apify-docs.ts index 8375323e..2520956a 100644 --- a/src/tools/search-apify-docs.ts +++ b/src/tools/search-apify-docs.ts @@ -45,7 +45,7 @@ export const searchApifyDocsTool: ToolEntry = { USAGE: - Use when user asks about Apify documentation, Actor development, Crawlee, or Apify platform. - EXAMPLES: + USAGE EXAMPLES: - query: How to use create Apify Actor? - query: How to define Actor input schema? - query: How scrape with Crawlee?`, diff --git a/src/tools/store_collection.ts b/src/tools/store_collection.ts index 368caa01..1ad5d6ac 100644 --- a/src/tools/store_collection.ts +++ b/src/tools/store_collection.ts @@ -82,7 +82,7 @@ USAGE: - Use when you need to discover Actors for a specific task or find MCP servers. - Use to explore available tools in the Apify ecosystem based on keywords. -EXAMPLES: +USAGE EXAMPLES: - user_input: Find Actors for scraping e-commerce - user_input: Find browserbase MCP server - user_input: I need to scrape instagram profiles and comments From 99af46ae1093a863d20fbbaa8e0e200b5d8548a8 Mon Sep 17 00:00:00 2001 From: Jiri Spilka Date: Mon, 22 Sep 2025 21:32:40 +0200 Subject: [PATCH 5/5] fix: Add todo --- src/tools/actor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/actor.ts b/src/tools/actor.ts index 93575dcb..6eb6c67e 100644 --- a/src/tools/actor.ts +++ b/src/tools/actor.ts @@ -419,6 +419,7 @@ EXAMPLES: return buildMCPResponse([`Actor information for '${baseActorName}' was not found. Please check the Actor ID or name and ensure the Actor exists.`]); } const content = [ + // TODO: update result to say: this is result of info step, you must now call again with step=call and proper input { type: 'text', text: `**Input Schema:**\n${JSON.stringify(details.inputSchema, null, 0)}` }, ]; /**