diff --git a/src/const.ts b/src/const.ts index 2134155b..a797b90b 100644 --- a/src/const.ts +++ b/src/const.ts @@ -65,6 +65,8 @@ export const SKYFIRE_PAY_ID_PROPERTY_DESCRIPTION = `Skyfire PAY token ID used fo export const SKYFIRE_README_CONTENT = `The Apify MCP Server allows clients to interact with Apify Actors, storage, and documentation. Before running any Apify Actor, you need to set up a Skyfire PAY token for billing purposes. To set up the PAY token you need to use the create-pay-token tool from the Skyfire MCP server. The PAY token must be charged with a minimum of ${SKYFIRE_MIN_CHARGE_USD} USD to be valid.${SKYFIRE_SELLER_ID ? ` The Skyfire seller ID for Apify MCP server is "${SKYFIRE_SELLER_ID}".` : ''} When running an Actor using the call-actor tool, you must provide the Skyfire PAY token ID in the \`skyfire-pay-id\` input property. Similarly, when retrieving Actor output using the get-actor-output tool, you must also provide the same Skyfire PAY token ID in the \`skyfire-pay-id\` input property.`; +export const CALL_ACTOR_MCP_MISSING_TOOL_NAME_MSG = `When calling an MCP server Actor, you must specify the tool name in the actor parameter as "{actorName}:{toolName}" in the "actor" input property.`; + // Cache export const ACTOR_CACHE_MAX_SIZE = 500; export const ACTOR_CACHE_TTL_SECS = 30 * 60; // 30 minutes diff --git a/src/tools/actor.ts b/src/tools/actor.ts index 2378db41..579e7aea 100644 --- a/src/tools/actor.ts +++ b/src/tools/actor.ts @@ -8,6 +8,7 @@ import log from '@apify/log'; import { ApifyClient } from '../apify-client.js'; import { ACTOR_MAX_MEMORY_MBYTES, + CALL_ACTOR_MCP_MISSING_TOOL_NAME_MSG, HelperTools, RAG_WEB_BROWSER, RAG_WEB_BROWSER_ADDITIONAL_DESC, @@ -384,8 +385,7 @@ EXAMPLES: // For definition resolution we always use token-based client; Skyfire is only for actual Actor runs const apifyClientForDefinition = new ApifyClient({ token: apifyToken }); // Resolve MCP server URL - const needsMcpUrl = mcpToolName !== undefined || performStep === 'info'; - const mcpServerUrlOrFalse = needsMcpUrl ? await getActorMcpUrlCached(baseActorName, apifyClientForDefinition) : false; + const mcpServerUrlOrFalse = await getActorMcpUrlCached(baseActorName, apifyClientForDefinition); const isActorMcpServer = mcpServerUrlOrFalse && typeof mcpServerUrlOrFalse === 'string'; // Standby Actors, thus MCPs, are not supported in Skyfire mode @@ -465,7 +465,7 @@ EXAMPLES: // and does not provide the tool name. const isMcpToolNameInvalid = mcpToolName === undefined || mcpToolName.trim().length === 0; if (isActorMcpServer && isMcpToolNameInvalid) { - return buildMCPResponse([`When calling an MCP server Actor, you must specify the tool name in the actor parameter as "{actorName}:{toolName}" in the "actor" input property.`]); + return buildMCPResponse([CALL_ACTOR_MCP_MISSING_TOOL_NAME_MSG]); } // Handle MCP tool calls diff --git a/tests/integration/suite.ts b/tests/integration/suite.ts index 8a2a658d..78bef136 100644 --- a/tests/integration/suite.ts +++ b/tests/integration/suite.ts @@ -4,7 +4,7 @@ import { CallToolResultSchema, ToolListChangedNotificationSchema } from '@modelc import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { ApifyClient } from '../../src/apify-client.js'; -import { defaults, HelperTools } from '../../src/const.js'; +import { CALL_ACTOR_MCP_MISSING_TOOL_NAME_MSG, defaults, HelperTools } from '../../src/const.js'; import { addTool } from '../../src/tools/helpers.js'; import { defaultTools, toolCategories } from '../../src/tools/index.js'; import { actorNameToToolName } from '../../src/tools/utils.js'; @@ -989,5 +989,25 @@ export function createIntegrationTestsSuite( await client.close(); }); + + it.only('should return error message when tryging to call MCP server Actor without tool name in actor parameter', async () => { + client = await createClientFn({ tools: ['actors'] }); + + const response = await client.callTool({ + name: 'call-actor', + arguments: { + actor: ACTOR_MCP_SERVER_ACTOR_NAME, + step: 'call', + input: { url: 'https://docs.apify.com' }, + }, + }); + + expect(response.content).toBeDefined(); + const content = response.content as { text: string }[]; + expect(content.length).toBeGreaterThan(0); + expect(content[0].text).toContain(CALL_ACTOR_MCP_MISSING_TOOL_NAME_MSG); + + await client.close(); + }); }); }