@apify/actors-mcp-server 0.11.8-beta.3 → 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.
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +114 -301
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool_call_engine.d.ts +82 -0
- package/dist/mcp/tool_call_engine.d.ts.map +1 -0
- package/dist/mcp/tool_call_engine.js +301 -0
- package/dist/mcp/tool_call_engine.js.map +1 -0
- package/dist/mcp/tool_dispatch.d.ts +4 -0
- package/dist/mcp/tool_dispatch.d.ts.map +1 -1
- package/dist/mcp/tool_dispatch.js +2 -2
- package/dist/mcp/tool_dispatch.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/server.json +1 -1
package/dist/mcp/server.d.ts
CHANGED
|
@@ -195,6 +195,15 @@ export declare class ActorsMcpServer {
|
|
|
195
195
|
*/
|
|
196
196
|
private resolveApifyClient;
|
|
197
197
|
private setupResourceHandlers;
|
|
198
|
+
/**
|
|
199
|
+
* Returns the prompts/list result.
|
|
200
|
+
*/
|
|
201
|
+
private listPrompts;
|
|
202
|
+
/**
|
|
203
|
+
* Builds the prompts/get result: find → not-found → validate → render.
|
|
204
|
+
* Throws {@link McpError} for an unknown prompt name or invalid arguments (v1 behavior).
|
|
205
|
+
*/
|
|
206
|
+
private getPrompt;
|
|
198
207
|
/**
|
|
199
208
|
* Sets up MCP request handlers for prompts.
|
|
200
209
|
*/
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4DAA4D,CAAC;AAE5F,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -9,37 +9,28 @@ import { getUiCapability, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-a
|
|
|
9
9
|
import { InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental/tasks/stores/in-memory.js';
|
|
10
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
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';
|
|
12
|
-
import dedent from 'dedent';
|
|
13
12
|
import log from '@apify/log';
|
|
14
13
|
import { parseBooleanOrNull } from '@apify/utilities';
|
|
15
14
|
import { ApifyClient } from '../apify_client.js';
|
|
16
|
-
import {
|
|
17
|
-
import { prepareToolCallContext } from '../payments/helpers.js';
|
|
15
|
+
import { DEFAULT_TELEMETRY_ENABLED, DEFAULT_TELEMETRY_ENV, FAILURE_CATEGORY, HELPER_TOOLS, TOOL_STATUS, } from '../const.js';
|
|
18
16
|
import { prompts } from '../prompts/index.js';
|
|
19
17
|
import { createResourceService } from '../resources/resource_service.js';
|
|
20
18
|
import { resolveAvailableWidgets } from '../resources/widgets.js';
|
|
21
19
|
import { getServerInfo } from '../server_card.js';
|
|
22
20
|
import { getTelemetryEnv } from '../telemetry.js';
|
|
23
|
-
import { decodeDotPropertyNames } from '../tools/actor_input_schema.js';
|
|
24
|
-
import { legacyToolNameToNew } from '../tools/actor_tool_naming.js';
|
|
25
|
-
import { checkPaymentProviderStandbyConflict } from '../tools/actors/call_actor.js';
|
|
26
21
|
import { withReportProblemNudge } from '../tools/dev/report_problem.js';
|
|
27
22
|
import { getActorsAsTools } from '../tools/index.js';
|
|
28
23
|
import { SERVER_MODE, TOOL_TYPE } from '../types.js';
|
|
29
|
-
import { isMcpClientFaultMessage,
|
|
30
|
-
import { respondOk } from '../utils/mcp.js';
|
|
24
|
+
import { isMcpClientFaultMessage, sanitizeMezmoMessage } from '../utils/logging.js';
|
|
31
25
|
import { getRequestOriginForClient, isReportProblemBlockedForClient } from '../utils/mcp_clients.js';
|
|
32
|
-
import { createProgressTracker } from '../utils/progress.js';
|
|
33
26
|
import { getServerInstructions } from '../utils/server-instructions/index.js';
|
|
34
27
|
import { parseServerMode, resolveServerMode } from '../utils/server_mode.js';
|
|
35
|
-
import {
|
|
36
|
-
import { buildActorFields, extractActorId, extractActorName, getToolFullName, getToolPublicFieldOnly, } from '../utils/tools.js';
|
|
28
|
+
import { buildActorFields, getToolFullName, getToolPublicFieldOnly } from '../utils/tools.js';
|
|
37
29
|
import { getActors, getToolsForServerMode, toolNamesToInput } from '../utils/tools_loader.js';
|
|
38
30
|
import { LOG_LEVEL_MAP } from './const.js';
|
|
39
31
|
import { emitTaskStatusNotification, executeToolAndUpdateTask } from './task_execution.js';
|
|
40
|
-
import {
|
|
32
|
+
import { buildPreflightFailureOutcome, classifyToolCallError, executeSyncToolCall, prepareToolCall, } from './tool_call_engine.js';
|
|
41
33
|
import { logToolCallAndTelemetry, prepareTelemetryData } from './tool_call_telemetry.js';
|
|
42
|
-
import { dispatchToolCall } from './tool_dispatch.js';
|
|
43
34
|
import { parseInputParamsFromUrl, storeTaskResultOrSkipIfExpired } from './utils.js';
|
|
44
35
|
/**
|
|
45
36
|
* Returns true when the initialize request advertises the MCP Apps UI extension
|
|
@@ -54,24 +45,6 @@ function isUiSupportedByClient(request) {
|
|
|
54
45
|
const uiCap = getUiCapability((_a = request === null || request === void 0 ? void 0 : request.params) === null || _a === void 0 ? void 0 : _a.capabilities);
|
|
55
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;
|
|
56
47
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Shared diagnostics for a pre-flight failure (standby-provider conflict or missing/invalid payment
|
|
59
|
-
* signature) — a call outcome already known before any Actor runs. Standby rejection wins over the
|
|
60
|
-
* generic payment-required failure so the agent gets the precise reason instead of a generic 402.
|
|
61
|
-
* Pure: callers own their own post-handling (return the result directly, or store + notify + synthesize
|
|
62
|
-
* a terminal task) — call this only once `standbyRejection ?? paymentRequiredResult` is already truthy.
|
|
63
|
-
*/
|
|
64
|
-
function buildPreflightFailureOutcome(standbyRejection, paymentRequiredResult, actorName, actorId) {
|
|
65
|
-
return {
|
|
66
|
-
toolStatus: TOOL_STATUS.SOFT_FAIL,
|
|
67
|
-
callDiagnostics: {
|
|
68
|
-
failure_category: FAILURE_CATEGORY.INVALID_INPUT,
|
|
69
|
-
...(standbyRejection ? {} : { failure_http_status: 402 }),
|
|
70
|
-
...buildActorFields(actorName, actorId),
|
|
71
|
-
},
|
|
72
|
-
result: (standbyRejection !== null && standbyRejection !== void 0 ? standbyRejection : paymentRequiredResult),
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
48
|
/**
|
|
76
49
|
* Create Apify MCP server
|
|
77
50
|
*/
|
|
@@ -659,41 +632,43 @@ export class ActorsMcpServer {
|
|
|
659
632
|
return await resourceService.listResourceTemplates();
|
|
660
633
|
});
|
|
661
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
|
+
}
|
|
662
666
|
/**
|
|
663
667
|
* Sets up MCP request handlers for prompts.
|
|
664
668
|
*/
|
|
665
669
|
setupPromptHandlers() {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
*/
|
|
669
|
-
this.server.setRequestHandler(ListPromptsRequestSchema, () => {
|
|
670
|
-
return { prompts };
|
|
671
|
-
});
|
|
672
|
-
/**
|
|
673
|
-
* Handles the prompts/get request.
|
|
674
|
-
*/
|
|
675
|
-
this.server.setRequestHandler(GetPromptRequestSchema, (request) => {
|
|
676
|
-
const { name, arguments: args } = request.params;
|
|
677
|
-
const prompt = prompts.find((p) => p.name === name);
|
|
678
|
-
if (!prompt) {
|
|
679
|
-
throw new McpError(ErrorCode.InvalidParams, `Prompt ${name} not found. Available prompts: ${prompts.map((p) => p.name).join(', ')}`);
|
|
680
|
-
}
|
|
681
|
-
if (!prompt.ajvValidate(args)) {
|
|
682
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for prompt ${name}: args: ${JSON.stringify(args)} error: ${JSON.stringify(prompt.ajvValidate.errors)}`);
|
|
683
|
-
}
|
|
684
|
-
return {
|
|
685
|
-
description: prompt.description,
|
|
686
|
-
messages: [
|
|
687
|
-
{
|
|
688
|
-
role: 'user',
|
|
689
|
-
content: {
|
|
690
|
-
type: 'text',
|
|
691
|
-
text: prompt.render(args || {}),
|
|
692
|
-
},
|
|
693
|
-
},
|
|
694
|
-
],
|
|
695
|
-
};
|
|
696
|
-
});
|
|
670
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, () => this.listPrompts());
|
|
671
|
+
this.server.setRequestHandler(GetPromptRequestSchema, (request) => this.getPrompt(request.params.name, request.params.arguments));
|
|
697
672
|
}
|
|
698
673
|
/**
|
|
699
674
|
* Fetches a task by ID, softFail-logging and throwing a client-facing McpError if it doesn't exist.
|
|
@@ -792,8 +767,9 @@ export class ActorsMcpServer {
|
|
|
792
767
|
* `sendNotification`. Throws {@link McpError} to mirror the MCP SDK's McpServer error codes.
|
|
793
768
|
*/
|
|
794
769
|
this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
795
|
-
var _a, _b, _c
|
|
770
|
+
var _a, _b, _c;
|
|
796
771
|
const params = request.params;
|
|
772
|
+
// Keep telemetry on the decoded arguments.
|
|
797
773
|
// eslint-disable-next-line prefer-const
|
|
798
774
|
let { name, arguments: args, _meta: meta } = params;
|
|
799
775
|
const progressToken = meta === null || meta === void 0 ? void 0 : meta.progressToken;
|
|
@@ -814,157 +790,66 @@ export class ActorsMcpServer {
|
|
|
814
790
|
// this handler's `finally` — so its `Tool call completed` log line keeps the taskId the
|
|
815
791
|
// async path logs via finishTaskTracking.
|
|
816
792
|
let preflightTaskId;
|
|
817
|
-
//
|
|
793
|
+
// The nudge must be included in the measured result.
|
|
818
794
|
let toolResult = null;
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
const augmented = withReportProblemNudge({
|
|
824
|
-
result: r,
|
|
825
|
-
tools: this.tools,
|
|
826
|
-
failingToolName: resolvedToolName,
|
|
827
|
-
failureCategory: callDiagnostics.failure_category,
|
|
828
|
-
failureHttpStatus: callDiagnostics.failure_http_status,
|
|
829
|
-
});
|
|
830
|
-
toolResult = augmented;
|
|
831
|
-
return augmented;
|
|
832
|
-
};
|
|
833
|
-
const failInvalidParams = async (message, details, logFields) => {
|
|
834
|
-
toolStatus = TOOL_STATUS.SOFT_FAIL;
|
|
835
|
-
callDiagnostics = details;
|
|
836
|
-
log.softFail(message, {
|
|
837
|
-
mcpSessionId,
|
|
838
|
-
failureCategory: details.failure_category,
|
|
839
|
-
actorName: details.actor_name,
|
|
840
|
-
validationKeyword: details.validation_keyword,
|
|
841
|
-
validationPath: details.validation_path,
|
|
842
|
-
validationMissingProperty: details.validation_missing_property,
|
|
843
|
-
validationAdditionalProperty: details.validation_additional_property,
|
|
844
|
-
...logFields,
|
|
845
|
-
});
|
|
846
|
-
await this.server.sendLoggingMessage({ level: 'error', data: message });
|
|
847
|
-
throw new McpError(ErrorCode.InvalidParams, message);
|
|
848
|
-
};
|
|
849
|
-
// Initialize telemetry with raw tool name — updated below once the tool is resolved.
|
|
850
|
-
// 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.
|
|
851
799
|
const { telemetryData, userId } = await prepareTelemetryData({
|
|
852
800
|
toolName: name,
|
|
853
801
|
mcpSessionId,
|
|
854
802
|
apifyToken,
|
|
855
803
|
apifyMcpServer: this,
|
|
856
804
|
});
|
|
857
|
-
// actorName/actorId are declared here so they're available in the catch block for telemetry.
|
|
858
|
-
// Set after tool resolution (inside the try block).
|
|
859
|
-
let actorName;
|
|
860
|
-
let actorId;
|
|
861
805
|
try {
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
!((_a = this.options.paymentProvider) === null || _a === void 0 ? void 0 : _a.allowsUnauthenticated) &&
|
|
865
|
-
!this.options.allowUnauthMode) {
|
|
866
|
-
await failInvalidParams(dedent `
|
|
867
|
-
Apify API token is required but was not provided.
|
|
868
|
-
Please set the APIFY_TOKEN environment variable or pass it as a parameter in the request header as Authorization Bearer <token>.
|
|
869
|
-
You can get your Apify token from https://console.apify.com/account/integrations.
|
|
870
|
-
`, {
|
|
871
|
-
failure_category: FAILURE_CATEGORY.AUTH,
|
|
872
|
-
});
|
|
873
|
-
}
|
|
874
|
-
// TODO - if connection is /mcp client will not receive notification on tool change
|
|
875
|
-
// Find tool by name, actor full name, or legacy tool name (e.g. apify-slash-rag-web-browser → apify--rag-web-browser)
|
|
876
|
-
const newName = (_b = legacyToolNameToNew(name)) !== null && _b !== void 0 ? _b : name;
|
|
877
|
-
const toolEntry = Array.from(this.tools.values()).find((t) => t.name === newName || getToolFullName(t) === newName);
|
|
878
|
-
if (!toolEntry) {
|
|
879
|
-
const availableTools = this.listToolNames();
|
|
880
|
-
await failInvalidParams(dedent `
|
|
881
|
-
Tool "${name}" was not found.
|
|
882
|
-
Available tools: ${availableTools.length > 0 ? availableTools.join(', ') : 'none'}.
|
|
883
|
-
Please verify the tool name is correct. You can list all available tools using the tools/list request.
|
|
884
|
-
`, {
|
|
885
|
-
failure_category: FAILURE_CATEGORY.INVALID_INPUT,
|
|
886
|
-
});
|
|
887
|
-
}
|
|
888
|
-
const tool = toolEntry;
|
|
889
|
-
resolvedToolName = getToolFullName(tool);
|
|
890
|
-
// Update telemetry tool name now that we resolved the tool (uses actorFullName for actor tools).
|
|
891
|
-
if (telemetryData) {
|
|
892
|
-
telemetryData.tool_name = resolvedToolName;
|
|
893
|
-
}
|
|
894
|
-
// Extract actor name/id for telemetry — available even when validation fails later.
|
|
895
|
-
actorName = extractActorName(tool, args);
|
|
896
|
-
actorId = extractActorId(tool);
|
|
897
|
-
// Always populate actor fields so they're tracked on both success and failure paths.
|
|
898
|
-
callDiagnostics = { ...callDiagnostics, ...buildActorFields(actorName, actorId) };
|
|
899
|
-
if (!args) {
|
|
900
|
-
await failInvalidParams(dedent `
|
|
901
|
-
Missing arguments for tool "${name}".
|
|
902
|
-
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.
|
|
903
|
-
`, {
|
|
904
|
-
failure_category: FAILURE_CATEGORY.INVALID_INPUT,
|
|
905
|
-
...buildActorFields(actorName, actorId),
|
|
906
|
-
});
|
|
907
|
-
}
|
|
908
|
-
// Decode dot property names in arguments before validation,
|
|
909
|
-
// since validation expects the original, non-encoded property names.
|
|
910
|
-
args = decodeDotPropertyNames(args);
|
|
911
|
-
// Centralize all payment processing: validate, strip payment fields, create client.
|
|
912
|
-
// Must run before AJV validation so toolArgsWithoutPayment doesn't contain provider-specific fields.
|
|
913
|
-
const { toolArgsWithoutPayment: toolArgs, toolArgsRedacted: logSafeArgs, apifyClient, paymentRequiredResult, } = prepareToolCallContext({
|
|
914
|
-
provider: this.options.paymentProvider,
|
|
915
|
-
tool,
|
|
916
|
-
args: args,
|
|
806
|
+
const prepared = await prepareToolCall({
|
|
807
|
+
apifyMcpServer: this,
|
|
917
808
|
apifyToken,
|
|
809
|
+
name,
|
|
810
|
+
args,
|
|
918
811
|
meta,
|
|
919
|
-
requestHeaders: (
|
|
920
|
-
|
|
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,
|
|
921
817
|
});
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
Invalid arguments for tool "${tool.name}".
|
|
931
|
-
Validation errors: ${errorMessages}.
|
|
932
|
-
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.
|
|
933
|
-
`, {
|
|
934
|
-
failure_category: FAILURE_CATEGORY.INVALID_INPUT,
|
|
935
|
-
...ajvErrorDetails,
|
|
936
|
-
...buildActorFields(actorName, actorId),
|
|
937
|
-
});
|
|
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;
|
|
938
826
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
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,
|
|
949
843
|
});
|
|
844
|
+
await this.server.sendLoggingMessage({ level: 'error', data: prepared.message });
|
|
845
|
+
throw new McpError(ErrorCode.InvalidParams, prepared.message);
|
|
950
846
|
}
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
//
|
|
956
|
-
|
|
957
|
-
const { paymentProvider } = this.options;
|
|
958
|
-
const isCallActorTool = tool.name === HELPER_TOOLS.ACTOR_CALL || tool.name === HELPER_TOOLS.ACTOR_CALL_WIDGET;
|
|
959
|
-
const actorArg = toolArgs === null || toolArgs === void 0 ? void 0 : toolArgs.actor;
|
|
960
|
-
const standbyRejection = paymentProvider && isCallActorTool && typeof actorArg === 'string' && actorArg.length > 0
|
|
961
|
-
? await checkPaymentProviderStandbyConflict({
|
|
962
|
-
actorName: actorArg,
|
|
963
|
-
paymentProvider,
|
|
964
|
-
apifyToken,
|
|
965
|
-
mcpSessionId,
|
|
966
|
-
})
|
|
967
|
-
: 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;
|
|
968
853
|
// TODO: we should split this huge method into smaller parts as it is slowly getting out of hand
|
|
969
854
|
// Handle long-running task request
|
|
970
855
|
if (request.params.task) {
|
|
@@ -998,8 +883,7 @@ export class ActorsMcpServer {
|
|
|
998
883
|
// CreateTaskResult parse error; surface it as a protocol error instead.
|
|
999
884
|
// The pre-flight outcome left toolStatus=SOFT_FAIL, but a genuine store
|
|
1000
885
|
// outage is a hard failure — correct it before throwing so the handler
|
|
1001
|
-
// `finally` logs FAILED/INTERNAL_ERROR
|
|
1002
|
-
// these), not the stale pre-flight SOFT_FAIL.
|
|
886
|
+
// `finally` logs FAILED/INTERNAL_ERROR, not the stale pre-flight SOFT_FAIL.
|
|
1003
887
|
toolStatus = TOOL_STATUS.FAILED;
|
|
1004
888
|
callDiagnostics = {
|
|
1005
889
|
failure_category: FAILURE_CATEGORY.INTERNAL_ERROR,
|
|
@@ -1013,7 +897,14 @@ export class ActorsMcpServer {
|
|
|
1013
897
|
setImmediate(() => {
|
|
1014
898
|
void emitTaskStatusNotification(task.taskId, mcpSessionId, this.taskStore, this.server);
|
|
1015
899
|
});
|
|
1016
|
-
|
|
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
|
+
});
|
|
1017
908
|
// createTask returned status `working`; synthesize the terminal status instead of
|
|
1018
909
|
// re-fetching — if the task expired before the result store (the one case
|
|
1019
910
|
// storeTaskResultOrSkipIfExpired tolerates), a re-fetch would come back empty and a
|
|
@@ -1025,9 +916,9 @@ export class ActorsMcpServer {
|
|
|
1025
916
|
executeToolAndUpdateTask({
|
|
1026
917
|
taskId: task.taskId,
|
|
1027
918
|
tool,
|
|
1028
|
-
toolArgs
|
|
919
|
+
toolArgs,
|
|
1029
920
|
logSafeArgs,
|
|
1030
|
-
apifyClient
|
|
921
|
+
apifyClient,
|
|
1031
922
|
apifyToken,
|
|
1032
923
|
progressToken,
|
|
1033
924
|
extra,
|
|
@@ -1044,116 +935,38 @@ export class ActorsMcpServer {
|
|
|
1044
935
|
shouldTrackTelemetry = false;
|
|
1045
936
|
return { task };
|
|
1046
937
|
}
|
|
1047
|
-
// Sync path:
|
|
1048
|
-
|
|
1049
|
-
// 402, so the agent gets the precise reason.
|
|
1050
|
-
if (standbyRejection || paymentRequiredResult) {
|
|
1051
|
-
const outcome = buildPreflightFailureOutcome(standbyRejection, paymentRequiredResult, actorName, actorId);
|
|
1052
|
-
toolStatus = outcome.toolStatus;
|
|
1053
|
-
callDiagnostics = outcome.callDiagnostics;
|
|
1054
|
-
return captureResult(outcome.result);
|
|
1055
|
-
}
|
|
1056
|
-
// Progress tracker: opt in for the two INTERNAL tools that emit during a sync wait
|
|
1057
|
-
// (call-actor start+waitForFinish, get-actor-run when waitSecs > 0), and unconditionally
|
|
1058
|
-
// for ACTOR tools. ACTOR_MCP forwards notifications directly, not via a tracker.
|
|
1059
|
-
const progressTrackerOptIn = tool.type === TOOL_TYPE.ACTOR ||
|
|
1060
|
-
(tool.type === TOOL_TYPE.INTERNAL &&
|
|
1061
|
-
(tool.name === HELPER_TOOLS.ACTOR_CALL || tool.name === HELPER_TOOLS.ACTOR_RUNS_GET));
|
|
1062
|
-
const progressTracker = progressTrackerOptIn
|
|
1063
|
-
? createProgressTracker(progressToken, extra.sendNotification)
|
|
1064
|
-
: null;
|
|
1065
|
-
const dispatchResult = await dispatchToolCall({
|
|
1066
|
-
tool,
|
|
1067
|
-
toolArgs: toolArgs,
|
|
1068
|
-
logSafeArgs,
|
|
1069
|
-
apifyToken,
|
|
1070
|
-
apifyClient: apifyClient,
|
|
938
|
+
// Sync path: run the shared dispatch tail and project its neutral outcome by identity.
|
|
939
|
+
const outcome = await executeSyncToolCall(prepared, {
|
|
1071
940
|
apifyMcpServer: this,
|
|
941
|
+
apifyToken,
|
|
942
|
+
toolName: name,
|
|
1072
943
|
mcpSessionId,
|
|
1073
944
|
progressToken,
|
|
1074
|
-
progressTracker,
|
|
1075
|
-
shouldForwardNotifications: true,
|
|
1076
945
|
extra,
|
|
1077
|
-
actorName,
|
|
1078
|
-
actorId,
|
|
1079
|
-
taskMode: false,
|
|
1080
946
|
});
|
|
1081
|
-
toolStatus =
|
|
1082
|
-
callDiagnostics =
|
|
1083
|
-
|
|
947
|
+
toolStatus = outcome.toolStatus;
|
|
948
|
+
callDiagnostics = outcome.callDiagnostics;
|
|
949
|
+
toolResult = outcome.result;
|
|
950
|
+
return outcome.result;
|
|
1084
951
|
}
|
|
1085
952
|
catch (error) {
|
|
1086
|
-
//
|
|
1087
|
-
// returns them as JSON-RPC errors. failInvalidParams already set callDiagnostics
|
|
1088
|
-
// with the correct semantic category (e.g. AUTH), so we must not overwrite it.
|
|
1089
|
-
// Re-throwing first is order-equivalent only because no McpError with an HTTP-range
|
|
1090
|
-
// code reaches this catch: an McpError(402) WOULD satisfy the x402 predicate
|
|
1091
|
-
// (getHttpStatusCode falls through to `.code`), but every remote-McpError route is
|
|
1092
|
-
// sealed by an inner catch (ACTOR_MCP branch, call-actor MCP passthrough) and all
|
|
1093
|
-
// in-repo McpErrors use negative ErrorCode.* values.
|
|
953
|
+
// Match v1: classify task-creation failures, but re-throw protocol errors as JSON-RPC.
|
|
1094
954
|
if (error instanceof McpError) {
|
|
1095
955
|
throw error;
|
|
1096
956
|
}
|
|
1097
|
-
const
|
|
957
|
+
const outcome = classifyToolCallError(error, {
|
|
958
|
+
apifyMcpServer: this,
|
|
1098
959
|
toolName: name,
|
|
960
|
+
failingToolName: resolvedToolName,
|
|
1099
961
|
actorName,
|
|
1100
962
|
actorId,
|
|
1101
|
-
isAborted: Boolean((
|
|
963
|
+
isAborted: Boolean((_c = extra.signal) === null || _c === void 0 ? void 0 : _c.aborted),
|
|
964
|
+
mcpSessionId,
|
|
1102
965
|
});
|
|
1103
|
-
toolStatus =
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
// content[0].text (JSON) + isError: true. No log here (unlike the task path). The
|
|
1108
|
-
// concurrent-run limit also surfaces as 402 but is excluded by the predicate and
|
|
1109
|
-
// falls through to the generic run-limit handling below.
|
|
1110
|
-
callDiagnostics = errorResult.callDiagnostics;
|
|
1111
|
-
return captureResult(errorResult.response);
|
|
1112
|
-
}
|
|
1113
|
-
case TOOL_CALL_ERROR_KIND.APPROVAL: {
|
|
1114
|
-
callDiagnostics = errorResult.callDiagnostics;
|
|
1115
|
-
logHttpError(error, 'Permission approval required while calling tool', {
|
|
1116
|
-
toolName: name,
|
|
1117
|
-
mcpSessionId,
|
|
1118
|
-
});
|
|
1119
|
-
return captureResult(errorResult.response);
|
|
1120
|
-
}
|
|
1121
|
-
case TOOL_CALL_ERROR_KIND.EXECUTION: {
|
|
1122
|
-
callDiagnostics = {
|
|
1123
|
-
// Spread existing diagnostics first (e.g. validation_keyword from
|
|
1124
|
-
// failInvalidParams), then overwrite with the mapper's freshly computed fields
|
|
1125
|
-
// so they take precedence.
|
|
1126
|
-
...callDiagnostics,
|
|
1127
|
-
...errorResult.callDiagnostics,
|
|
1128
|
-
};
|
|
1129
|
-
logHttpError(error, 'Error occurred while calling tool', {
|
|
1130
|
-
toolName: name,
|
|
1131
|
-
toolStatus,
|
|
1132
|
-
mcpSessionId,
|
|
1133
|
-
failureCategory: callDiagnostics.failure_category,
|
|
1134
|
-
failureHttpStatus: callDiagnostics.failure_http_status,
|
|
1135
|
-
actorName: callDiagnostics.actor_name,
|
|
1136
|
-
validationKeyword: callDiagnostics.validation_keyword,
|
|
1137
|
-
validationPath: callDiagnostics.validation_path,
|
|
1138
|
-
validationMissingProperty: callDiagnostics.validation_missing_property,
|
|
1139
|
-
validationAdditionalProperty: callDiagnostics.validation_additional_property,
|
|
1140
|
-
});
|
|
1141
|
-
// This framework outer-catch path bypasses extractToolTelemetry (returned via
|
|
1142
|
-
// captureResult), so preserve the pre-existing wire shape { toolStatus } exactly:
|
|
1143
|
-
// reuse the local ABORTED-aware toolStatus, do NOT re-derive from the error (which
|
|
1144
|
-
// would drop ABORTED and leak failureCategory/failureHttpStatus onto the wire).
|
|
1145
|
-
return captureResult({
|
|
1146
|
-
...respondOk(errorResult.userText),
|
|
1147
|
-
isError: true,
|
|
1148
|
-
toolTelemetry: { toolStatus },
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
default:
|
|
1152
|
-
// Compile-time exhaustiveness guard (same `satisfies never` idiom as
|
|
1153
|
-
// dispatchToolCall's default arm): a new TOOL_CALL_ERROR_KIND makes `errorResult`
|
|
1154
|
-
// non-`never` here and fails to compile. Unreachable at runtime.
|
|
1155
|
-
throw new McpError(ErrorCode.InvalidParams, `Unknown tool-call error kind "${errorResult.kind}"`);
|
|
1156
|
-
}
|
|
966
|
+
toolStatus = outcome.toolStatus;
|
|
967
|
+
callDiagnostics = outcome.callDiagnostics;
|
|
968
|
+
toolResult = outcome.result;
|
|
969
|
+
return outcome.result;
|
|
1157
970
|
}
|
|
1158
971
|
finally {
|
|
1159
972
|
if (shouldTrackTelemetry) {
|