@apify/actors-mcp-server 0.12.0 → 0.12.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/dist/apify_client.js +1 -4
  2. package/dist/apify_client.js.map +1 -1
  3. package/dist/const.js +1 -4
  4. package/dist/const.js.map +1 -1
  5. package/dist/dev_server.js +1 -4
  6. package/dist/dev_server.js.map +1 -1
  7. package/dist/errors.js +1 -4
  8. package/dist/errors.js.map +1 -1
  9. package/dist/index.js +1 -4
  10. package/dist/index.js.map +1 -1
  11. package/dist/index_internals.js +1 -4
  12. package/dist/index_internals.js.map +1 -1
  13. package/dist/input.js +1 -4
  14. package/dist/input.js.map +1 -1
  15. package/dist/instrument.js +1 -4
  16. package/dist/instrument.js.map +1 -1
  17. package/dist/mcp/actors.js +1 -4
  18. package/dist/mcp/actors.js.map +1 -1
  19. package/dist/mcp/client.js +1 -4
  20. package/dist/mcp/client.js.map +1 -1
  21. package/dist/mcp/const.js +1 -4
  22. package/dist/mcp/const.js.map +1 -1
  23. package/dist/mcp/proxy.js +1 -4
  24. package/dist/mcp/proxy.js.map +1 -1
  25. package/dist/mcp/server.d.ts +9 -0
  26. package/dist/mcp/server.d.ts.map +1 -1
  27. package/dist/mcp/server.js +115 -305
  28. package/dist/mcp/server.js.map +1 -1
  29. package/dist/mcp/task_execution.js +1 -4
  30. package/dist/mcp/task_execution.js.map +1 -1
  31. package/dist/mcp/tool_call_engine.d.ts +82 -0
  32. package/dist/mcp/tool_call_engine.d.ts.map +1 -0
  33. package/dist/mcp/tool_call_engine.js +301 -0
  34. package/dist/mcp/tool_call_engine.js.map +1 -0
  35. package/dist/mcp/tool_call_error_mapper.js +1 -4
  36. package/dist/mcp/tool_call_error_mapper.js.map +1 -1
  37. package/dist/mcp/tool_call_telemetry.js +1 -4
  38. package/dist/mcp/tool_call_telemetry.js.map +1 -1
  39. package/dist/mcp/tool_dispatch.d.ts +4 -0
  40. package/dist/mcp/tool_dispatch.d.ts.map +1 -1
  41. package/dist/mcp/tool_dispatch.js +3 -6
  42. package/dist/mcp/tool_dispatch.js.map +1 -1
  43. package/dist/mcp/utils.js +1 -4
  44. package/dist/mcp/utils.js.map +1 -1
  45. package/dist/payments/const.js +1 -4
  46. package/dist/payments/const.js.map +1 -1
  47. package/dist/payments/helpers.js +1 -4
  48. package/dist/payments/helpers.js.map +1 -1
  49. package/dist/payments/index.js +1 -4
  50. package/dist/payments/index.js.map +1 -1
  51. package/dist/payments/resolve.js +1 -4
  52. package/dist/payments/resolve.js.map +1 -1
  53. package/dist/payments/skyfire.js +1 -4
  54. package/dist/payments/skyfire.js.map +1 -1
  55. package/dist/payments/types.js +1 -4
  56. package/dist/payments/types.js.map +1 -1
  57. package/dist/payments/x402.js +1 -4
  58. package/dist/payments/x402.js.map +1 -1
  59. package/dist/prompts/index.js +1 -4
  60. package/dist/prompts/index.js.map +1 -1
  61. package/dist/resources/api_resources.js +1 -4
  62. package/dist/resources/api_resources.js.map +1 -1
  63. package/dist/resources/resource_service.js +1 -4
  64. package/dist/resources/resource_service.js.map +1 -1
  65. package/dist/resources/widgets.js +1 -4
  66. package/dist/resources/widgets.js.map +1 -1
  67. package/dist/server_card.js +1 -4
  68. package/dist/server_card.js.map +1 -1
  69. package/dist/state.js +1 -4
  70. package/dist/state.js.map +1 -1
  71. package/dist/stdio.js +1 -4
  72. package/dist/stdio.js.map +1 -1
  73. package/dist/telemetry.js +1 -4
  74. package/dist/telemetry.js.map +1 -1
  75. package/dist/tools/actor_input_schema.js +1 -4
  76. package/dist/tools/actor_input_schema.js.map +1 -1
  77. package/dist/tools/actor_tool_naming.js +1 -4
  78. package/dist/tools/actor_tool_naming.js.map +1 -1
  79. package/dist/tools/actors/actor_definition.js +1 -4
  80. package/dist/tools/actors/actor_definition.js.map +1 -1
  81. package/dist/tools/actors/actor_executor.js +1 -4
  82. package/dist/tools/actors/actor_executor.js.map +1 -1
  83. package/dist/tools/actors/actor_run_response.js +1 -4
  84. package/dist/tools/actors/actor_run_response.js.map +1 -1
  85. package/dist/tools/actors/actor_tools_factory.js +1 -4
  86. package/dist/tools/actors/actor_tools_factory.js.map +1 -1
  87. package/dist/tools/actors/add_actor.js +1 -4
  88. package/dist/tools/actors/add_actor.js.map +1 -1
  89. package/dist/tools/actors/call_actor.js +1 -4
  90. package/dist/tools/actors/call_actor.js.map +1 -1
  91. package/dist/tools/actors/fetch_actor_details.js +1 -4
  92. package/dist/tools/actors/fetch_actor_details.js.map +1 -1
  93. package/dist/tools/actors/search_actors.js +1 -4
  94. package/dist/tools/actors/search_actors.js.map +1 -1
  95. package/dist/tools/dev/report_problem.js +1 -4
  96. package/dist/tools/dev/report_problem.js.map +1 -1
  97. package/dist/tools/docs/fetch_apify_docs.js +1 -4
  98. package/dist/tools/docs/fetch_apify_docs.js.map +1 -1
  99. package/dist/tools/docs/search_apify_docs.js +1 -4
  100. package/dist/tools/docs/search_apify_docs.js.map +1 -1
  101. package/dist/tools/index.js +1 -4
  102. package/dist/tools/index.js.map +1 -1
  103. package/dist/tools/registry.js +1 -4
  104. package/dist/tools/registry.js.map +1 -1
  105. package/dist/tools/runs/abort_actor_run.js +1 -4
  106. package/dist/tools/runs/abort_actor_run.js.map +1 -1
  107. package/dist/tools/runs/get_actor_run.js +1 -4
  108. package/dist/tools/runs/get_actor_run.js.map +1 -1
  109. package/dist/tools/runs/get_actor_run_list.js +1 -4
  110. package/dist/tools/runs/get_actor_run_list.js.map +1 -1
  111. package/dist/tools/runs/get_actor_run_log.js +1 -4
  112. package/dist/tools/runs/get_actor_run_log.js.map +1 -1
  113. package/dist/tools/storage/get_dataset.js +1 -4
  114. package/dist/tools/storage/get_dataset.js.map +1 -1
  115. package/dist/tools/storage/get_dataset_items.js +1 -4
  116. package/dist/tools/storage/get_dataset_items.js.map +1 -1
  117. package/dist/tools/storage/get_dataset_list.js +1 -4
  118. package/dist/tools/storage/get_dataset_list.js.map +1 -1
  119. package/dist/tools/storage/get_dataset_schema.js +1 -4
  120. package/dist/tools/storage/get_dataset_schema.js.map +1 -1
  121. package/dist/tools/storage/get_key_value_store.js +1 -4
  122. package/dist/tools/storage/get_key_value_store.js.map +1 -1
  123. package/dist/tools/storage/get_key_value_store_keys.js +1 -4
  124. package/dist/tools/storage/get_key_value_store_keys.js.map +1 -1
  125. package/dist/tools/storage/get_key_value_store_list.js +1 -4
  126. package/dist/tools/storage/get_key_value_store_list.js.map +1 -1
  127. package/dist/tools/storage/get_key_value_store_record.js +1 -4
  128. package/dist/tools/storage/get_key_value_store_record.js.map +1 -1
  129. package/dist/tools/storage/storage_helpers.js +1 -4
  130. package/dist/tools/storage/storage_helpers.js.map +1 -1
  131. package/dist/tools/structured_output_schemas.js +1 -4
  132. package/dist/tools/structured_output_schemas.js.map +1 -1
  133. package/dist/tools/widgets/call_actor_widget.js +1 -4
  134. package/dist/tools/widgets/call_actor_widget.js.map +1 -1
  135. package/dist/tools/widgets/fetch_actor_details_widget.js +1 -4
  136. package/dist/tools/widgets/fetch_actor_details_widget.js.map +1 -1
  137. package/dist/tools/widgets/get_actor_run_widget.js +1 -4
  138. package/dist/tools/widgets/get_actor_run_widget.js.map +1 -1
  139. package/dist/tools/widgets/search_actors_widget.js +1 -4
  140. package/dist/tools/widgets/search_actors_widget.js.map +1 -1
  141. package/dist/tsconfig.tsbuildinfo +1 -1
  142. package/dist/types.js +1 -4
  143. package/dist/types.js.map +1 -1
  144. package/dist/utils/actor.js +1 -4
  145. package/dist/utils/actor.js.map +1 -1
  146. package/dist/utils/actor_card.js +1 -4
  147. package/dist/utils/actor_card.js.map +1 -1
  148. package/dist/utils/actor_details.js +1 -4
  149. package/dist/utils/actor_details.js.map +1 -1
  150. package/dist/utils/actor_search.js +1 -4
  151. package/dist/utils/actor_search.js.map +1 -1
  152. package/dist/utils/ajv.js +1 -4
  153. package/dist/utils/ajv.js.map +1 -1
  154. package/dist/utils/apify_docs.js +1 -4
  155. package/dist/utils/apify_docs.js.map +1 -1
  156. package/dist/utils/apify_errors.js +1 -4
  157. package/dist/utils/apify_errors.js.map +1 -1
  158. package/dist/utils/apify_properties.js +1 -4
  159. package/dist/utils/apify_properties.js.map +1 -1
  160. package/dist/utils/auth.js +1 -4
  161. package/dist/utils/auth.js.map +1 -1
  162. package/dist/utils/console_link.js +1 -4
  163. package/dist/utils/console_link.js.map +1 -1
  164. package/dist/utils/encode_text.js +1 -4
  165. package/dist/utils/encode_text.js.map +1 -1
  166. package/dist/utils/generic.js +1 -4
  167. package/dist/utils/generic.js.map +1 -1
  168. package/dist/utils/logging.js +1 -4
  169. package/dist/utils/logging.js.map +1 -1
  170. package/dist/utils/mcp.js +1 -4
  171. package/dist/utils/mcp.js.map +1 -1
  172. package/dist/utils/mcp_clients.js +1 -4
  173. package/dist/utils/mcp_clients.js.map +1 -1
  174. package/dist/utils/payment_errors.js +1 -4
  175. package/dist/utils/payment_errors.js.map +1 -1
  176. package/dist/utils/pricing_info.js +1 -4
  177. package/dist/utils/pricing_info.js.map +1 -1
  178. package/dist/utils/progress.js +1 -4
  179. package/dist/utils/progress.js.map +1 -1
  180. package/dist/utils/schema_generation.js +1 -4
  181. package/dist/utils/schema_generation.js.map +1 -1
  182. package/dist/utils/server-instructions/index.js +1 -4
  183. package/dist/utils/server-instructions/index.js.map +1 -1
  184. package/dist/utils/server_mode.js +1 -4
  185. package/dist/utils/server_mode.js.map +1 -1
  186. package/dist/utils/tool_categories_helpers.js +1 -4
  187. package/dist/utils/tool_categories_helpers.js.map +1 -1
  188. package/dist/utils/tool_status.js +1 -4
  189. package/dist/utils/tool_status.js.map +1 -1
  190. package/dist/utils/tools.js +1 -4
  191. package/dist/utils/tools.js.map +1 -1
  192. package/dist/utils/tools_loader.js +1 -4
  193. package/dist/utils/tools_loader.js.map +1 -1
  194. package/dist/utils/ttl_lru.js +1 -4
  195. package/dist/utils/ttl_lru.js.map +1 -1
  196. package/dist/utils/userid_cache.js +1 -4
  197. package/dist/utils/userid_cache.js.map +1 -1
  198. package/dist/utils/version.js +1 -4
  199. package/dist/utils/version.js.map +1 -1
  200. package/dist/web/dist/actor-run-widget.js +0 -2
  201. package/dist/web/dist/search-actors-widget.js +0 -2
  202. package/manifest.json +1 -1
  203. package/package.json +1 -1
  204. package/server.json +1 -1
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * Model Context Protocol (MCP) server for Apify Actors
3
3
  */
4
-
5
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b2bdac72-d12f-5751-9e08-72a36e12d99e")}catch(e){}}();
6
4
  import { randomUUID } from 'node:crypto';
7
5
  // The ext-apps package exposes `./server` via conditional exports only (no `./server/index.js`
8
6
  // wildcard), so we can't satisfy the `import/extensions` rule on this subpath.
@@ -11,37 +9,28 @@ import { getUiCapability, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-a
11
9
  import { InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental/tasks/stores/in-memory.js';
12
10
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
13
11
  import { CallToolRequestSchema, CancelTaskRequestSchema, ErrorCode, GetPromptRequestSchema, GetTaskPayloadRequestSchema, GetTaskRequestSchema, InitializeRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListTasksRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema, RELATED_TASK_META_KEY, SetLevelRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
14
- import dedent from 'dedent';
15
12
  import log from '@apify/log';
16
13
  import { parseBooleanOrNull } from '@apify/utilities';
17
14
  import { ApifyClient } from '../apify_client.js';
18
- import { ALLOWED_TASK_TOOL_EXECUTION_MODES, DEFAULT_TELEMETRY_ENABLED, DEFAULT_TELEMETRY_ENV, FAILURE_CATEGORY, HELPER_TOOLS, TOOL_STATUS, } from '../const.js';
19
- import { prepareToolCallContext } from '../payments/helpers.js';
15
+ import { DEFAULT_TELEMETRY_ENABLED, DEFAULT_TELEMETRY_ENV, FAILURE_CATEGORY, HELPER_TOOLS, TOOL_STATUS, } from '../const.js';
20
16
  import { prompts } from '../prompts/index.js';
21
17
  import { createResourceService } from '../resources/resource_service.js';
22
18
  import { resolveAvailableWidgets } from '../resources/widgets.js';
23
19
  import { getServerInfo } from '../server_card.js';
24
20
  import { getTelemetryEnv } from '../telemetry.js';
25
- import { decodeDotPropertyNames } from '../tools/actor_input_schema.js';
26
- import { legacyToolNameToNew } from '../tools/actor_tool_naming.js';
27
- import { checkPaymentProviderStandbyConflict } from '../tools/actors/call_actor.js';
28
21
  import { withReportProblemNudge } from '../tools/dev/report_problem.js';
29
22
  import { getActorsAsTools } from '../tools/index.js';
30
23
  import { SERVER_MODE, TOOL_TYPE } from '../types.js';
31
- import { isMcpClientFaultMessage, logHttpError, sanitizeMezmoMessage } from '../utils/logging.js';
32
- import { respondOk } from '../utils/mcp.js';
24
+ import { isMcpClientFaultMessage, sanitizeMezmoMessage } from '../utils/logging.js';
33
25
  import { getRequestOriginForClient, isReportProblemBlockedForClient } from '../utils/mcp_clients.js';
34
- import { createProgressTracker } from '../utils/progress.js';
35
26
  import { getServerInstructions } from '../utils/server-instructions/index.js';
36
27
  import { parseServerMode, resolveServerMode } from '../utils/server_mode.js';
37
- import { extractAjvErrorDetails } from '../utils/tool_status.js';
38
- import { buildActorFields, extractActorId, extractActorName, getToolFullName, getToolPublicFieldOnly, } from '../utils/tools.js';
28
+ import { buildActorFields, getToolFullName, getToolPublicFieldOnly } from '../utils/tools.js';
39
29
  import { getActors, getToolsForServerMode, toolNamesToInput } from '../utils/tools_loader.js';
40
30
  import { LOG_LEVEL_MAP } from './const.js';
41
31
  import { emitTaskStatusNotification, executeToolAndUpdateTask } from './task_execution.js';
42
- import { buildToolCallErrorResult, TOOL_CALL_ERROR_KIND } from './tool_call_error_mapper.js';
32
+ import { buildPreflightFailureOutcome, classifyToolCallError, executeSyncToolCall, prepareToolCall, } from './tool_call_engine.js';
43
33
  import { logToolCallAndTelemetry, prepareTelemetryData } from './tool_call_telemetry.js';
44
- import { dispatchToolCall } from './tool_dispatch.js';
45
34
  import { parseInputParamsFromUrl, storeTaskResultOrSkipIfExpired } from './utils.js';
46
35
  /**
47
36
  * Returns true when the initialize request advertises the MCP Apps UI extension
@@ -56,24 +45,6 @@ function isUiSupportedByClient(request) {
56
45
  const uiCap = getUiCapability((_a = request === null || request === void 0 ? void 0 : request.params) === null || _a === void 0 ? void 0 : _a.capabilities);
57
46
  return (_c = (_b = uiCap === null || uiCap === void 0 ? void 0 : uiCap.mimeTypes) === null || _b === void 0 ? void 0 : _b.includes(RESOURCE_MIME_TYPE)) !== null && _c !== void 0 ? _c : false;
58
47
  }
59
- /**
60
- * Shared diagnostics for a pre-flight failure (standby-provider conflict or missing/invalid payment
61
- * signature) — a call outcome already known before any Actor runs. Standby rejection wins over the
62
- * generic payment-required failure so the agent gets the precise reason instead of a generic 402.
63
- * Pure: callers own their own post-handling (return the result directly, or store + notify + synthesize
64
- * a terminal task) — call this only once `standbyRejection ?? paymentRequiredResult` is already truthy.
65
- */
66
- function buildPreflightFailureOutcome(standbyRejection, paymentRequiredResult, actorName, actorId) {
67
- return {
68
- toolStatus: TOOL_STATUS.SOFT_FAIL,
69
- callDiagnostics: {
70
- failure_category: FAILURE_CATEGORY.INVALID_INPUT,
71
- ...(standbyRejection ? {} : { failure_http_status: 402 }),
72
- ...buildActorFields(actorName, actorId),
73
- },
74
- result: (standbyRejection !== null && standbyRejection !== void 0 ? standbyRejection : paymentRequiredResult),
75
- };
76
- }
77
48
  /**
78
49
  * Create Apify MCP server
79
50
  */
@@ -661,41 +632,43 @@ export class ActorsMcpServer {
661
632
  return await resourceService.listResourceTemplates();
662
633
  });
663
634
  }
635
+ /**
636
+ * Returns the prompts/list result.
637
+ */
638
+ listPrompts() {
639
+ return { prompts };
640
+ }
641
+ /**
642
+ * Builds the prompts/get result: find → not-found → validate → render.
643
+ * Throws {@link McpError} for an unknown prompt name or invalid arguments (v1 behavior).
644
+ */
645
+ getPrompt(name, args) {
646
+ const prompt = prompts.find((p) => p.name === name);
647
+ if (!prompt) {
648
+ throw new McpError(ErrorCode.InvalidParams, `Prompt ${name} not found. Available prompts: ${prompts.map((p) => p.name).join(', ')}`);
649
+ }
650
+ if (!prompt.ajvValidate(args)) {
651
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: args: ${JSON.stringify(args)} error: ${JSON.stringify(prompt.ajvValidate.errors)}`);
652
+ }
653
+ return {
654
+ description: prompt.description,
655
+ messages: [
656
+ {
657
+ role: 'user',
658
+ content: {
659
+ type: 'text',
660
+ text: prompt.render(args || {}),
661
+ },
662
+ },
663
+ ],
664
+ };
665
+ }
664
666
  /**
665
667
  * Sets up MCP request handlers for prompts.
666
668
  */
667
669
  setupPromptHandlers() {
668
- /**
669
- * Handles the prompts/list request.
670
- */
671
- this.server.setRequestHandler(ListPromptsRequestSchema, () => {
672
- return { prompts };
673
- });
674
- /**
675
- * Handles the prompts/get request.
676
- */
677
- this.server.setRequestHandler(GetPromptRequestSchema, (request) => {
678
- const { name, arguments: args } = request.params;
679
- const prompt = prompts.find((p) => p.name === name);
680
- if (!prompt) {
681
- throw new McpError(ErrorCode.InvalidParams, `Prompt ${name} not found. Available prompts: ${prompts.map((p) => p.name).join(', ')}`);
682
- }
683
- if (!prompt.ajvValidate(args)) {
684
- throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: args: ${JSON.stringify(args)} error: ${JSON.stringify(prompt.ajvValidate.errors)}`);
685
- }
686
- return {
687
- description: prompt.description,
688
- messages: [
689
- {
690
- role: 'user',
691
- content: {
692
- type: 'text',
693
- text: prompt.render(args || {}),
694
- },
695
- },
696
- ],
697
- };
698
- });
670
+ this.server.setRequestHandler(ListPromptsRequestSchema, () => this.listPrompts());
671
+ this.server.setRequestHandler(GetPromptRequestSchema, (request) => this.getPrompt(request.params.name, request.params.arguments));
699
672
  }
700
673
  /**
701
674
  * Fetches a task by ID, softFail-logging and throwing a client-facing McpError if it doesn't exist.
@@ -794,8 +767,9 @@ export class ActorsMcpServer {
794
767
  * `sendNotification`. Throws {@link McpError} to mirror the MCP SDK's McpServer error codes.
795
768
  */
796
769
  this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
797
- var _a, _b, _c, _d, _e;
770
+ var _a, _b, _c;
798
771
  const params = request.params;
772
+ // Keep telemetry on the decoded arguments.
799
773
  // eslint-disable-next-line prefer-const
800
774
  let { name, arguments: args, _meta: meta } = params;
801
775
  const progressToken = meta === null || meta === void 0 ? void 0 : meta.progressToken;
@@ -816,157 +790,66 @@ export class ActorsMcpServer {
816
790
  // this handler's `finally` — so its `Tool call completed` log line keeps the taskId the
817
791
  // async path logs via finishTaskTracking.
818
792
  let preflightTaskId;
819
- // Captured by `captureResult` so the `finally` block can measure response size for telemetry.
793
+ // The nudge must be included in the measured result.
820
794
  let toolResult = null;
821
- const captureResult = (r) => {
822
- // On a failed result, nudge the agent to report the blocker via report-problem at the
823
- // moment it decides what to do next. Gated on the tool actually being served (see
824
- // isReportProblemServable), so clients where it is blocklisted or telemetry is off never see it.
825
- const augmented = withReportProblemNudge({
826
- result: r,
827
- tools: this.tools,
828
- failingToolName: resolvedToolName,
829
- failureCategory: callDiagnostics.failure_category,
830
- failureHttpStatus: callDiagnostics.failure_http_status,
831
- });
832
- toolResult = augmented;
833
- return augmented;
834
- };
835
- const failInvalidParams = async (message, details, logFields) => {
836
- toolStatus = TOOL_STATUS.SOFT_FAIL;
837
- callDiagnostics = details;
838
- log.softFail(message, {
839
- mcpSessionId,
840
- failureCategory: details.failure_category,
841
- actorName: details.actor_name,
842
- validationKeyword: details.validation_keyword,
843
- validationPath: details.validation_path,
844
- validationMissingProperty: details.validation_missing_property,
845
- validationAdditionalProperty: details.validation_additional_property,
846
- ...logFields,
847
- });
848
- await this.server.sendLoggingMessage({ level: 'error', data: message });
849
- throw new McpError(ErrorCode.InvalidParams, message);
850
- };
851
- // Initialize telemetry with raw tool name — updated below once the tool is resolved.
852
- // This ensures telemetry is available even for early failures (missing token, tool not found).
795
+ // Keep actor context available to the outer catch.
796
+ let actorName;
797
+ let actorId;
798
+ // Start with the raw name so early failures still have telemetry.
853
799
  const { telemetryData, userId } = await prepareTelemetryData({
854
800
  toolName: name,
855
801
  mcpSessionId,
856
802
  apifyToken,
857
803
  apifyMcpServer: this,
858
804
  });
859
- // actorName/actorId are declared here so they're available in the catch block for telemetry.
860
- // Set after tool resolution (inside the try block).
861
- let actorName;
862
- let actorId;
863
805
  try {
864
- // Validate token
865
- if (!apifyToken &&
866
- !((_a = this.options.paymentProvider) === null || _a === void 0 ? void 0 : _a.allowsUnauthenticated) &&
867
- !this.options.allowUnauthMode) {
868
- await failInvalidParams(dedent `
869
- Apify API token is required but was not provided.
870
- Please set the APIFY_TOKEN environment variable or pass it as a parameter in the request header as Authorization Bearer <token>.
871
- You can get your Apify token from https://console.apify.com/account/integrations.
872
- `, {
873
- failure_category: FAILURE_CATEGORY.AUTH,
874
- });
875
- }
876
- // TODO - if connection is /mcp client will not receive notification on tool change
877
- // Find tool by name, actor full name, or legacy tool name (e.g. apify-slash-rag-web-browser → apify--rag-web-browser)
878
- const newName = (_b = legacyToolNameToNew(name)) !== null && _b !== void 0 ? _b : name;
879
- const toolEntry = Array.from(this.tools.values()).find((t) => t.name === newName || getToolFullName(t) === newName);
880
- if (!toolEntry) {
881
- const availableTools = this.listToolNames();
882
- await failInvalidParams(dedent `
883
- Tool "${name}" was not found.
884
- Available tools: ${availableTools.length > 0 ? availableTools.join(', ') : 'none'}.
885
- Please verify the tool name is correct. You can list all available tools using the tools/list request.
886
- `, {
887
- failure_category: FAILURE_CATEGORY.INVALID_INPUT,
888
- });
889
- }
890
- const tool = toolEntry;
891
- resolvedToolName = getToolFullName(tool);
892
- // Update telemetry tool name now that we resolved the tool (uses actorFullName for actor tools).
893
- if (telemetryData) {
894
- telemetryData.tool_name = resolvedToolName;
895
- }
896
- // Extract actor name/id for telemetry — available even when validation fails later.
897
- actorName = extractActorName(tool, args);
898
- actorId = extractActorId(tool);
899
- // Always populate actor fields so they're tracked on both success and failure paths.
900
- callDiagnostics = { ...callDiagnostics, ...buildActorFields(actorName, actorId) };
901
- if (!args) {
902
- await failInvalidParams(dedent `
903
- Missing arguments for tool "${name}".
904
- Please provide the required arguments for this tool. Check the tool's input schema using ${HELPER_TOOLS.ACTOR_GET_DETAILS} tool to see what parameters are required.
905
- `, {
906
- failure_category: FAILURE_CATEGORY.INVALID_INPUT,
907
- ...buildActorFields(actorName, actorId),
908
- });
909
- }
910
- // Decode dot property names in arguments before validation,
911
- // since validation expects the original, non-encoded property names.
912
- args = decodeDotPropertyNames(args);
913
- // Centralize all payment processing: validate, strip payment fields, create client.
914
- // Must run before AJV validation so toolArgsWithoutPayment doesn't contain provider-specific fields.
915
- const { toolArgsWithoutPayment: toolArgs, toolArgsRedacted: logSafeArgs, apifyClient, paymentRequiredResult, } = prepareToolCallContext({
916
- provider: this.options.paymentProvider,
917
- tool,
918
- args: args,
806
+ const prepared = await prepareToolCall({
807
+ apifyMcpServer: this,
919
808
  apifyToken,
809
+ name,
810
+ args,
920
811
  meta,
921
- requestHeaders: (_c = extra.requestInfo) === null || _c === void 0 ? void 0 : _c.headers,
922
- requestOrigin: getRequestOriginForClient(this.options.initializeRequestData),
812
+ requestHeaders: (_a = extra.requestInfo) === null || _a === void 0 ? void 0 : _a.headers,
813
+ isTaskRequest: Boolean(request.params.task),
814
+ mcpSessionId,
815
+ telemetryData,
816
+ extra,
923
817
  });
924
- log.debug('Validate arguments for tool', { toolName: tool.name, mcpSessionId, input: logSafeArgs });
925
- if (!tool.ajvValidate(toolArgs)) {
926
- const errors = tool.ajvValidate.errors || [];
927
- const ajvErrorDetails = extractAjvErrorDetails(errors);
928
- const errorMessages = errors
929
- .map((e) => `${e.instancePath || 'root'}: ${e.message || 'validation error'}`)
930
- .join('; ');
931
- await failInvalidParams(dedent `
932
- Invalid arguments for tool "${tool.name}".
933
- Validation errors: ${errorMessages}.
934
- Please check the tool's input schema using ${HELPER_TOOLS.ACTOR_GET_DETAILS} tool and ensure all required parameters are provided with correct types and values.
935
- `, {
936
- failure_category: FAILURE_CATEGORY.INVALID_INPUT,
937
- ...ajvErrorDetails,
938
- ...buildActorFields(actorName, actorId),
939
- });
818
+ if ('result' in prepared) {
819
+ // The engine already classified this post-resolution failure.
820
+ resolvedToolName = prepared.resolvedToolName;
821
+ args = prepared.decodedArgs;
822
+ toolStatus = prepared.toolStatus;
823
+ callDiagnostics = prepared.callDiagnostics;
824
+ toolResult = prepared.result;
825
+ return prepared.result;
940
826
  }
941
- // Check if tool call is a long-running task and the tool supports that
942
- // Cast to allowed task mode types ('optional' | 'required') for type-safe includes() check
943
- const taskSupport = (_d = tool.execution) === null || _d === void 0 ? void 0 : _d.taskSupport;
944
- if (request.params.task && !ALLOWED_TASK_TOOL_EXECUTION_MODES.includes(taskSupport)) {
945
- await failInvalidParams(dedent `
946
- Tool "${tool.name}" does not support long running task calls.
947
- Please remove the "task" parameter from the tool call request or use a different tool that supports long running tasks.
948
- `, {
949
- failure_category: FAILURE_CATEGORY.INVALID_INPUT,
950
- ...buildActorFields(actorName, actorId),
827
+ if ('message' in prepared) {
828
+ // Reproduce v1's invalid-params tail and preserve telemetry fields.
829
+ resolvedToolName = (_b = prepared.resolvedToolName) !== null && _b !== void 0 ? _b : resolvedToolName;
830
+ if (prepared.decodedArgs)
831
+ args = prepared.decodedArgs;
832
+ toolStatus = prepared.toolStatus;
833
+ callDiagnostics = prepared.callDiagnostics;
834
+ log.softFail(prepared.message, {
835
+ mcpSessionId,
836
+ failureCategory: prepared.callDiagnostics.failure_category,
837
+ actorName: prepared.callDiagnostics.actor_name,
838
+ validationKeyword: prepared.callDiagnostics.validation_keyword,
839
+ validationPath: prepared.callDiagnostics.validation_path,
840
+ validationMissingProperty: prepared.callDiagnostics.validation_missing_property,
841
+ validationAdditionalProperty: prepared.callDiagnostics.validation_additional_property,
842
+ ...prepared.logFields,
951
843
  });
844
+ await this.server.sendLoggingMessage({ level: 'error', data: prepared.message });
845
+ throw new McpError(ErrorCode.InvalidParams, prepared.message);
952
846
  }
953
- // Standby / MCP-server Actors are never payable via a third-party provider —
954
- // compute the rejection here so both the sync short-circuit and the task path
955
- // can use it. In task-mode we still create the task and store this rejection
956
- // as its result (instead of a generic 402), so the agent gets the precise reason
957
- // when fetching the task result. Task-mode `call-actor` declares
958
- // `taskSupport: 'optional'`, so without this both paths would 402 by default.
959
- const { paymentProvider } = this.options;
960
- const isCallActorTool = tool.name === HELPER_TOOLS.ACTOR_CALL || tool.name === HELPER_TOOLS.ACTOR_CALL_WIDGET;
961
- const actorArg = toolArgs === null || toolArgs === void 0 ? void 0 : toolArgs.actor;
962
- const standbyRejection = paymentProvider && isCallActorTool && typeof actorArg === 'string' && actorArg.length > 0
963
- ? await checkPaymentProviderStandbyConflict({
964
- actorName: actorArg,
965
- paymentProvider,
966
- apifyToken,
967
- mcpSessionId,
968
- })
969
- : null;
847
+ const { tool, toolArgs, logSafeArgs, apifyClient, standbyRejection, paymentRequiredResult } = prepared;
848
+ actorName = prepared.actorName;
849
+ actorId = prepared.actorId;
850
+ resolvedToolName = getToolFullName(tool);
851
+ // Telemetry uses the decoded arguments.
852
+ args = prepared.decodedArgs;
970
853
  // TODO: we should split this huge method into smaller parts as it is slowly getting out of hand
971
854
  // Handle long-running task request
972
855
  if (request.params.task) {
@@ -1000,8 +883,7 @@ export class ActorsMcpServer {
1000
883
  // CreateTaskResult parse error; surface it as a protocol error instead.
1001
884
  // The pre-flight outcome left toolStatus=SOFT_FAIL, but a genuine store
1002
885
  // outage is a hard failure — correct it before throwing so the handler
1003
- // `finally` logs FAILED/INTERNAL_ERROR (the outer McpError re-throw preserves
1004
- // these), not the stale pre-flight SOFT_FAIL.
886
+ // `finally` logs FAILED/INTERNAL_ERROR, not the stale pre-flight SOFT_FAIL.
1005
887
  toolStatus = TOOL_STATUS.FAILED;
1006
888
  callDiagnostics = {
1007
889
  failure_category: FAILURE_CATEGORY.INTERNAL_ERROR,
@@ -1015,7 +897,14 @@ export class ActorsMcpServer {
1015
897
  setImmediate(() => {
1016
898
  void emitTaskStatusNotification(task.taskId, mcpSessionId, this.taskStore, this.server);
1017
899
  });
1018
- captureResult(outcome.result);
900
+ // Measure the nudged result without changing the stored result.
901
+ toolResult = withReportProblemNudge({
902
+ result: outcome.result,
903
+ tools: this.tools,
904
+ failingToolName: resolvedToolName,
905
+ failureCategory: callDiagnostics.failure_category,
906
+ failureHttpStatus: callDiagnostics.failure_http_status,
907
+ });
1019
908
  // createTask returned status `working`; synthesize the terminal status instead of
1020
909
  // re-fetching — if the task expired before the result store (the one case
1021
910
  // storeTaskResultOrSkipIfExpired tolerates), a re-fetch would come back empty and a
@@ -1027,9 +916,9 @@ export class ActorsMcpServer {
1027
916
  executeToolAndUpdateTask({
1028
917
  taskId: task.taskId,
1029
918
  tool,
1030
- toolArgs: toolArgs,
919
+ toolArgs,
1031
920
  logSafeArgs,
1032
- apifyClient: apifyClient,
921
+ apifyClient,
1033
922
  apifyToken,
1034
923
  progressToken,
1035
924
  extra,
@@ -1046,116 +935,38 @@ export class ActorsMcpServer {
1046
935
  shouldTrackTelemetry = false;
1047
936
  return { task };
1048
937
  }
1049
- // Sync path: short-circuit on either pre-flight failure. buildPreflightFailureOutcome
1050
- // encodes the precedence — standby rejection wins over the generic payment-required
1051
- // 402, so the agent gets the precise reason.
1052
- if (standbyRejection || paymentRequiredResult) {
1053
- const outcome = buildPreflightFailureOutcome(standbyRejection, paymentRequiredResult, actorName, actorId);
1054
- toolStatus = outcome.toolStatus;
1055
- callDiagnostics = outcome.callDiagnostics;
1056
- return captureResult(outcome.result);
1057
- }
1058
- // Progress tracker: opt in for the two INTERNAL tools that emit during a sync wait
1059
- // (call-actor start+waitForFinish, get-actor-run when waitSecs > 0), and unconditionally
1060
- // for ACTOR tools. ACTOR_MCP forwards notifications directly, not via a tracker.
1061
- const progressTrackerOptIn = tool.type === TOOL_TYPE.ACTOR ||
1062
- (tool.type === TOOL_TYPE.INTERNAL &&
1063
- (tool.name === HELPER_TOOLS.ACTOR_CALL || tool.name === HELPER_TOOLS.ACTOR_RUNS_GET));
1064
- const progressTracker = progressTrackerOptIn
1065
- ? createProgressTracker(progressToken, extra.sendNotification)
1066
- : null;
1067
- const dispatchResult = await dispatchToolCall({
1068
- tool,
1069
- toolArgs: toolArgs,
1070
- logSafeArgs,
1071
- apifyToken,
1072
- apifyClient: apifyClient,
938
+ // Sync path: run the shared dispatch tail and project its neutral outcome by identity.
939
+ const outcome = await executeSyncToolCall(prepared, {
1073
940
  apifyMcpServer: this,
941
+ apifyToken,
942
+ toolName: name,
1074
943
  mcpSessionId,
1075
944
  progressToken,
1076
- progressTracker,
1077
- shouldForwardNotifications: true,
1078
945
  extra,
1079
- actorName,
1080
- actorId,
1081
- taskMode: false,
1082
946
  });
1083
- toolStatus = dispatchResult.toolStatus;
1084
- callDiagnostics = dispatchResult.callDiagnostics;
1085
- return captureResult(dispatchResult.result);
947
+ toolStatus = outcome.toolStatus;
948
+ callDiagnostics = outcome.callDiagnostics;
949
+ toolResult = outcome.result;
950
+ return outcome.result;
1086
951
  }
1087
952
  catch (error) {
1088
- // Re-throw MCP protocol errors (e.g. from failInvalidParams) so the SDK
1089
- // returns them as JSON-RPC errors. failInvalidParams already set callDiagnostics
1090
- // with the correct semantic category (e.g. AUTH), so we must not overwrite it.
1091
- // Re-throwing first is order-equivalent only because no McpError with an HTTP-range
1092
- // code reaches this catch: an McpError(402) WOULD satisfy the x402 predicate
1093
- // (getHttpStatusCode falls through to `.code`), but every remote-McpError route is
1094
- // sealed by an inner catch (ACTOR_MCP branch, call-actor MCP passthrough) and all
1095
- // in-repo McpErrors use negative ErrorCode.* values.
953
+ // Match v1: classify task-creation failures, but re-throw protocol errors as JSON-RPC.
1096
954
  if (error instanceof McpError) {
1097
955
  throw error;
1098
956
  }
1099
- const errorResult = buildToolCallErrorResult(error, {
957
+ const outcome = classifyToolCallError(error, {
958
+ apifyMcpServer: this,
1100
959
  toolName: name,
960
+ failingToolName: resolvedToolName,
1101
961
  actorName,
1102
962
  actorId,
1103
- isAborted: Boolean((_e = extra.signal) === null || _e === void 0 ? void 0 : _e.aborted),
963
+ isAborted: Boolean((_c = extra.signal) === null || _c === void 0 ? void 0 : _c.aborted),
964
+ mcpSessionId,
1104
965
  });
1105
- toolStatus = errorResult.toolStatus;
1106
- switch (errorResult.kind) {
1107
- case TOOL_CALL_ERROR_KIND.PAYMENT: {
1108
- // Propagate 402 Payment Required as a tool result per x402 MCP transport spec:
1109
- // content[0].text (JSON) + isError: true. No log here (unlike the task path). The
1110
- // concurrent-run limit also surfaces as 402 but is excluded by the predicate and
1111
- // falls through to the generic run-limit handling below.
1112
- callDiagnostics = errorResult.callDiagnostics;
1113
- return captureResult(errorResult.response);
1114
- }
1115
- case TOOL_CALL_ERROR_KIND.APPROVAL: {
1116
- callDiagnostics = errorResult.callDiagnostics;
1117
- logHttpError(error, 'Permission approval required while calling tool', {
1118
- toolName: name,
1119
- mcpSessionId,
1120
- });
1121
- return captureResult(errorResult.response);
1122
- }
1123
- case TOOL_CALL_ERROR_KIND.EXECUTION: {
1124
- callDiagnostics = {
1125
- // Spread existing diagnostics first (e.g. validation_keyword from
1126
- // failInvalidParams), then overwrite with the mapper's freshly computed fields
1127
- // so they take precedence.
1128
- ...callDiagnostics,
1129
- ...errorResult.callDiagnostics,
1130
- };
1131
- logHttpError(error, 'Error occurred while calling tool', {
1132
- toolName: name,
1133
- toolStatus,
1134
- mcpSessionId,
1135
- failureCategory: callDiagnostics.failure_category,
1136
- failureHttpStatus: callDiagnostics.failure_http_status,
1137
- actorName: callDiagnostics.actor_name,
1138
- validationKeyword: callDiagnostics.validation_keyword,
1139
- validationPath: callDiagnostics.validation_path,
1140
- validationMissingProperty: callDiagnostics.validation_missing_property,
1141
- validationAdditionalProperty: callDiagnostics.validation_additional_property,
1142
- });
1143
- // This framework outer-catch path bypasses extractToolTelemetry (returned via
1144
- // captureResult), so preserve the pre-existing wire shape { toolStatus } exactly:
1145
- // reuse the local ABORTED-aware toolStatus, do NOT re-derive from the error (which
1146
- // would drop ABORTED and leak failureCategory/failureHttpStatus onto the wire).
1147
- return captureResult({
1148
- ...respondOk(errorResult.userText),
1149
- isError: true,
1150
- toolTelemetry: { toolStatus },
1151
- });
1152
- }
1153
- default:
1154
- // Compile-time exhaustiveness guard (same `satisfies never` idiom as
1155
- // dispatchToolCall's default arm): a new TOOL_CALL_ERROR_KIND makes `errorResult`
1156
- // non-`never` here and fails to compile. Unreachable at runtime.
1157
- throw new McpError(ErrorCode.InvalidParams, `Unknown tool-call error kind "${errorResult.kind}"`);
1158
- }
966
+ toolStatus = outcome.toolStatus;
967
+ callDiagnostics = outcome.callDiagnostics;
968
+ toolResult = outcome.result;
969
+ return outcome.result;
1159
970
  }
1160
971
  finally {
1161
972
  if (shouldTrackTelemetry) {
@@ -1240,5 +1051,4 @@ export class ActorsMcpServer {
1240
1051
  await this.server.close();
1241
1052
  }
1242
1053
  }
1243
- //# sourceMappingURL=server.js.map
1244
- //# debugId=b2bdac72-d12f-5751-9e08-72a36e12d99e
1054
+ //# sourceMappingURL=server.js.map