@apify/actors-mcp-server 0.11.7-beta.6 → 0.11.7-beta.8
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.map +1 -1
- package/dist/mcp/server.js +80 -257
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool_dispatch.d.ts +49 -0
- package/dist/mcp/tool_dispatch.d.ts.map +1 -0
- package/dist/mcp/tool_dispatch.js +208 -0
- package/dist/mcp/tool_dispatch.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
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;
|
|
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
|
@@ -8,7 +8,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
8
8
|
import { getUiCapability, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
|
|
9
9
|
import { InMemoryTaskStore } from '@modelcontextprotocol/sdk/experimental/tasks/stores/in-memory.js';
|
|
10
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
|
-
import { CallToolRequestSchema,
|
|
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
12
|
import dedent from 'dedent';
|
|
13
13
|
import log from '@apify/log';
|
|
14
14
|
import { parseBooleanOrNull } from '@apify/utilities';
|
|
@@ -22,26 +22,24 @@ import { getServerInfo } from '../server_card.js';
|
|
|
22
22
|
import { buildReportedProblemProperties, getTelemetryEnv, trackReportedProblem, trackToolCall } from '../telemetry.js';
|
|
23
23
|
import { decodeDotPropertyNames } from '../tools/actor_input_schema.js';
|
|
24
24
|
import { legacyToolNameToNew } from '../tools/actor_tool_naming.js';
|
|
25
|
-
import { actorExecutor } from '../tools/actors/actor_executor.js';
|
|
26
25
|
import { checkPaymentProviderStandbyConflict } from '../tools/actors/call_actor.js';
|
|
27
26
|
import { appendReportProblemNudge } from '../tools/dev/report_problem.js';
|
|
28
27
|
import { getActorsAsTools } from '../tools/index.js';
|
|
29
28
|
import { SERVER_MODE, TOOL_TYPE } from '../types.js';
|
|
30
|
-
import { remoteMcpFailureDetail } from '../utils/apify_errors.js';
|
|
31
29
|
import { isMcpClientFaultMessage, logHttpError, sanitizeMezmoMessage } from '../utils/logging.js';
|
|
32
|
-
import { computeToolResponseBytes,
|
|
30
|
+
import { computeToolResponseBytes, respondOk } from '../utils/mcp.js';
|
|
33
31
|
import { isReportProblemBlockedForClient } from '../utils/mcp_clients.js';
|
|
34
32
|
import { createProgressTracker } from '../utils/progress.js';
|
|
35
33
|
import { getServerInstructions } from '../utils/server-instructions/index.js';
|
|
36
34
|
import { parseServerMode, resolveServerMode } from '../utils/server_mode.js';
|
|
37
|
-
import {
|
|
35
|
+
import { deriveResourceIds, extractAjvErrorDetails } from '../utils/tool_status.js';
|
|
38
36
|
import { buildActorFields, extractActorId, extractActorName, getToolFullName, getToolPublicFieldOnly, } from '../utils/tools.js';
|
|
39
37
|
import { getActors, getToolsForServerMode, toolNamesToInput } from '../utils/tools_loader.js';
|
|
40
38
|
import { getUserInfoCached } from '../utils/userid_cache.js';
|
|
41
39
|
import { getPackageVersion } from '../utils/version.js';
|
|
42
|
-
import {
|
|
43
|
-
import { EXTERNAL_TOOL_CALL_TIMEOUT_MSEC, LOG_LEVEL_MAP } from './const.js';
|
|
40
|
+
import { LOG_LEVEL_MAP } from './const.js';
|
|
44
41
|
import { buildToolCallErrorResult, TOOL_CALL_ERROR_KIND } from './tool_call_error_mapper.js';
|
|
42
|
+
import { dispatchToolCall } from './tool_dispatch.js';
|
|
45
43
|
import { createTaskCancellationWatcher, isTaskCancelled, isTaskNotFoundError, parseInputParamsFromUrl, storeTaskResultOrSkipIfExpired, } from './utils.js';
|
|
46
44
|
/**
|
|
47
45
|
* Returns true when the initialize request advertises the MCP Apps UI extension
|
|
@@ -843,7 +841,7 @@ export class ActorsMcpServer {
|
|
|
843
841
|
* @throws {McpError} - based on the McpServer class code from the typescript MCP SDK
|
|
844
842
|
*/
|
|
845
843
|
this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
846
|
-
var _a, _b, _c, _d, _e
|
|
844
|
+
var _a, _b, _c, _d, _e;
|
|
847
845
|
const params = request.params;
|
|
848
846
|
// eslint-disable-next-line prefer-const
|
|
849
847
|
let { name, arguments: args, _meta: meta } = params;
|
|
@@ -1090,152 +1088,34 @@ export class ActorsMcpServer {
|
|
|
1090
1088
|
callDiagnostics = outcome.callDiagnostics;
|
|
1091
1089
|
return captureResult(outcome.result);
|
|
1092
1090
|
}
|
|
1093
|
-
//
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
if (tool.type === TOOL_TYPE.ACTOR_MCP) {
|
|
1122
|
-
let client = null;
|
|
1123
|
-
try {
|
|
1124
|
-
client = await connectMCPClient(tool.serverUrl, apifyToken, mcpSessionId);
|
|
1125
|
-
if (!client) {
|
|
1126
|
-
const msg = dedent `
|
|
1127
|
-
Failed to connect to MCP server at "${tool.serverUrl}".
|
|
1128
|
-
Please verify the server URL is correct and accessible, and ensure you have a valid Apify token with appropriate permissions.
|
|
1129
|
-
`;
|
|
1130
|
-
log.softFail(msg, { mcpSessionId, failureCategory: FAILURE_CATEGORY.INTERNAL_ERROR });
|
|
1131
|
-
await this.server.sendLoggingMessage({ level: 'error', data: msg });
|
|
1132
|
-
toolStatus = TOOL_STATUS.SOFT_FAIL;
|
|
1133
|
-
callDiagnostics = { ...callDiagnostics, failure_category: FAILURE_CATEGORY.INTERNAL_ERROR };
|
|
1134
|
-
return captureResult(respondErrorNoTelemetry(msg));
|
|
1135
|
-
}
|
|
1136
|
-
// Only set up notification handlers if progressToken is provided by the client
|
|
1137
|
-
if (progressToken !== undefined && progressToken !== null) {
|
|
1138
|
-
// Set up notification handlers for the client
|
|
1139
|
-
for (const schema of ServerNotificationSchema.options) {
|
|
1140
|
-
const method = schema.shape.method.value;
|
|
1141
|
-
// Forward notifications from the proxy client to the server
|
|
1142
|
-
client.setNotificationHandler(schema, async (notification) => {
|
|
1143
|
-
log.debug('Sending MCP notification', {
|
|
1144
|
-
method,
|
|
1145
|
-
mcpSessionId,
|
|
1146
|
-
notification,
|
|
1147
|
-
});
|
|
1148
|
-
await extra.sendNotification(notification);
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
log.info('Calling Actor-MCP', {
|
|
1153
|
-
toolName: tool.name,
|
|
1154
|
-
actorMcpToolName: tool.originToolName,
|
|
1155
|
-
actorId: tool.actorId,
|
|
1156
|
-
mcpSessionId,
|
|
1157
|
-
input: logSafeArgs,
|
|
1158
|
-
});
|
|
1159
|
-
const res = await client.callTool({
|
|
1160
|
-
name: tool.originToolName,
|
|
1161
|
-
arguments: toolArgs,
|
|
1162
|
-
_meta: { progressToken },
|
|
1163
|
-
}, CallToolResultSchema, {
|
|
1164
|
-
timeout: EXTERNAL_TOOL_CALL_TIMEOUT_MSEC,
|
|
1165
|
-
});
|
|
1166
|
-
// TODO: actor-mcp responses are opaque — isError could be a user input problem
|
|
1167
|
-
// (e.g. invalid query) or a genuine server failure. We can't distinguish without
|
|
1168
|
-
// parsing the error text. Defaulting to INTERNAL_ERROR for now; revisit when
|
|
1169
|
-
// actor-mcp gets deeper telemetry treatment.
|
|
1170
|
-
if ('isError' in res && res.isError) {
|
|
1171
|
-
toolStatus = TOOL_STATUS.SOFT_FAIL;
|
|
1172
|
-
callDiagnostics = {
|
|
1173
|
-
failure_category: FAILURE_CATEGORY.INTERNAL_ERROR,
|
|
1174
|
-
...buildActorFields(actorName, actorId),
|
|
1175
|
-
};
|
|
1176
|
-
}
|
|
1177
|
-
return captureResult({ ...res });
|
|
1178
|
-
}
|
|
1179
|
-
catch (error) {
|
|
1180
|
-
toolStatus = getToolStatusFromError(error, Boolean((_e = extra.signal) === null || _e === void 0 ? void 0 : _e.aborted));
|
|
1181
|
-
const failureDetail = error instanceof Error ? error.message.slice(0, 200) : String(error).slice(0, 200);
|
|
1182
|
-
callDiagnostics = {
|
|
1183
|
-
failure_category: classifyFailureCategory(error),
|
|
1184
|
-
failure_detail: failureDetail,
|
|
1185
|
-
...buildActorFields(actorName, actorId),
|
|
1186
|
-
};
|
|
1187
|
-
logHttpError(error, `Failed to call MCP tool '${tool.originToolName}' on Actor '${tool.actorId}'`, {
|
|
1188
|
-
actorId: tool.actorId,
|
|
1189
|
-
toolName: tool.originToolName,
|
|
1190
|
-
failureCategory: callDiagnostics.failure_category,
|
|
1191
|
-
});
|
|
1192
|
-
return captureResult(respondErrorNoTelemetry(`Failed to call MCP tool '${tool.originToolName}' on Actor '${tool.actorId}': ${remoteMcpFailureDetail(error)}`));
|
|
1193
|
-
}
|
|
1194
|
-
finally {
|
|
1195
|
-
if (client)
|
|
1196
|
-
await client.close();
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
// Handle actor tool
|
|
1200
|
-
if (tool.type === TOOL_TYPE.ACTOR) {
|
|
1201
|
-
const progressTracker = createProgressTracker(progressToken, extra.sendNotification);
|
|
1202
|
-
try {
|
|
1203
|
-
log.info('Calling Actor', {
|
|
1204
|
-
toolName: tool.name,
|
|
1205
|
-
actorName: tool.actorFullName,
|
|
1206
|
-
mcpSessionId,
|
|
1207
|
-
input: logSafeArgs,
|
|
1208
|
-
});
|
|
1209
|
-
const executorResult = await actorExecutor.executeActorTool({
|
|
1210
|
-
actorFullName: tool.actorFullName,
|
|
1211
|
-
input: toolArgs,
|
|
1212
|
-
apifyClient: apifyClient,
|
|
1213
|
-
callOptions: { memory: tool.memoryMbytes },
|
|
1214
|
-
progressTracker,
|
|
1215
|
-
abortSignal: extra.signal,
|
|
1216
|
-
mcpSessionId,
|
|
1217
|
-
datasetItemsSchema: tool.datasetItemsSchema,
|
|
1218
|
-
});
|
|
1219
|
-
if (!executorResult) {
|
|
1220
|
-
toolStatus = TOOL_STATUS.ABORTED;
|
|
1221
|
-
// Receivers of cancellation notifications SHOULD NOT send a response for the cancelled request
|
|
1222
|
-
// https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation#behavior-requirements
|
|
1223
|
-
return captureResult({});
|
|
1224
|
-
}
|
|
1225
|
-
// Mirror the INTERNAL branch: read the telemetry the executor embedded on error
|
|
1226
|
-
// results (e.g. respondUserError → SOFT_FAIL/INVALID_INPUT), strip it from the wire,
|
|
1227
|
-
// and set failure_category so the report-problem nudge picks the softer variant.
|
|
1228
|
-
({ toolStatus, callDiagnostics } = applyToolTelemetry(executorResult, actorName, actorId, callDiagnostics));
|
|
1229
|
-
return captureResult(executorResult);
|
|
1230
|
-
}
|
|
1231
|
-
finally {
|
|
1232
|
-
if (progressTracker) {
|
|
1233
|
-
progressTracker.stop();
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
// If we reached here without returning, it means the tool type was not recognized (user error)
|
|
1238
|
-
toolStatus = TOOL_STATUS.SOFT_FAIL;
|
|
1091
|
+
// Progress tracker: opt in for the two INTERNAL tools that emit during a sync wait
|
|
1092
|
+
// (call-actor start+waitForFinish, get-actor-run when waitSecs > 0), and unconditionally
|
|
1093
|
+
// for ACTOR tools. ACTOR_MCP forwards notifications directly, not via a tracker.
|
|
1094
|
+
const progressTrackerOptIn = tool.type === TOOL_TYPE.ACTOR ||
|
|
1095
|
+
(tool.type === TOOL_TYPE.INTERNAL &&
|
|
1096
|
+
(tool.name === HELPER_TOOLS.ACTOR_CALL || tool.name === HELPER_TOOLS.ACTOR_RUNS_GET));
|
|
1097
|
+
const progressTracker = progressTrackerOptIn
|
|
1098
|
+
? createProgressTracker(progressToken, extra.sendNotification)
|
|
1099
|
+
: null;
|
|
1100
|
+
const dispatchResult = await dispatchToolCall({
|
|
1101
|
+
tool,
|
|
1102
|
+
toolArgs: toolArgs,
|
|
1103
|
+
logSafeArgs,
|
|
1104
|
+
apifyToken,
|
|
1105
|
+
apifyClient: apifyClient,
|
|
1106
|
+
apifyMcpServer: this,
|
|
1107
|
+
mcpSessionId,
|
|
1108
|
+
progressToken,
|
|
1109
|
+
progressTracker,
|
|
1110
|
+
shouldForwardNotifications: true,
|
|
1111
|
+
extra,
|
|
1112
|
+
actorName,
|
|
1113
|
+
actorId,
|
|
1114
|
+
taskMode: false,
|
|
1115
|
+
});
|
|
1116
|
+
toolStatus = dispatchResult.toolStatus;
|
|
1117
|
+
callDiagnostics = dispatchResult.callDiagnostics;
|
|
1118
|
+
return captureResult(dispatchResult.result);
|
|
1239
1119
|
}
|
|
1240
1120
|
catch (error) {
|
|
1241
1121
|
// Re-throw MCP protocol errors (e.g. from failInvalidParams) so the SDK
|
|
@@ -1244,8 +1124,8 @@ export class ActorsMcpServer {
|
|
|
1244
1124
|
// Re-throwing first is order-equivalent only because no McpError with an HTTP-range
|
|
1245
1125
|
// code reaches this catch: an McpError(402) WOULD satisfy the x402 predicate
|
|
1246
1126
|
// (getHttpStatusCode falls through to `.code`), but every remote-McpError route is
|
|
1247
|
-
// sealed by
|
|
1248
|
-
// negative ErrorCode.* values.
|
|
1127
|
+
// sealed by an inner catch (ACTOR_MCP branch, call-actor MCP passthrough) and all
|
|
1128
|
+
// in-repo McpErrors use negative ErrorCode.* values.
|
|
1249
1129
|
if (error instanceof McpError) {
|
|
1250
1130
|
throw error;
|
|
1251
1131
|
}
|
|
@@ -1253,7 +1133,7 @@ export class ActorsMcpServer {
|
|
|
1253
1133
|
toolName: name,
|
|
1254
1134
|
actorName,
|
|
1255
1135
|
actorId,
|
|
1256
|
-
isAborted: Boolean((
|
|
1136
|
+
isAborted: Boolean((_e = extra.signal) === null || _e === void 0 ? void 0 : _e.aborted),
|
|
1257
1137
|
});
|
|
1258
1138
|
toolStatus = errorResult.toolStatus;
|
|
1259
1139
|
// Propagate 402 Payment Required as a tool result per x402 MCP transport spec:
|
|
@@ -1316,18 +1196,6 @@ export class ActorsMcpServer {
|
|
|
1316
1196
|
});
|
|
1317
1197
|
}
|
|
1318
1198
|
}
|
|
1319
|
-
const availableTools = this.listToolNames();
|
|
1320
|
-
const msg = dedent `
|
|
1321
|
-
Unknown tool type for "${name}".
|
|
1322
|
-
Available tools: ${availableTools.length > 0 ? availableTools.join(', ') : 'none'}.
|
|
1323
|
-
Please verify the tool name and ensure the tool is properly registered.
|
|
1324
|
-
`;
|
|
1325
|
-
log.softFail(msg, { mcpSessionId, statusCode: 404 });
|
|
1326
|
-
await this.server.sendLoggingMessage({
|
|
1327
|
-
level: 'error',
|
|
1328
|
-
data: msg,
|
|
1329
|
-
});
|
|
1330
|
-
throw new McpError(ErrorCode.InvalidParams, msg);
|
|
1331
1199
|
});
|
|
1332
1200
|
}
|
|
1333
1201
|
/**
|
|
@@ -1379,7 +1247,7 @@ export class ActorsMcpServer {
|
|
|
1379
1247
|
}
|
|
1380
1248
|
}
|
|
1381
1249
|
}
|
|
1382
|
-
// TODO:
|
|
1250
|
+
// TODO: outer orchestration here (pre-flight, telemetry bookkeeping, task-store handling) still duplicates the CallToolRequestSchema handler's logic; the dispatch ladder is now shared. Refactor.
|
|
1383
1251
|
/**
|
|
1384
1252
|
* Executes a tool asynchronously for a long-running task and updates task status.
|
|
1385
1253
|
*
|
|
@@ -1420,6 +1288,13 @@ export class ActorsMcpServer {
|
|
|
1420
1288
|
result,
|
|
1421
1289
|
});
|
|
1422
1290
|
};
|
|
1291
|
+
// Terminal step shared by every task outcome: store the result (expiry-tolerant),
|
|
1292
|
+
// emit the status notification, record telemetry.
|
|
1293
|
+
const completeTask = async (storeStatus, taskResult, status, diagnostics) => {
|
|
1294
|
+
await storeTaskResultOrSkipIfExpired(this.taskStore, tool.name, taskId, storeStatus, taskResult, mcpSessionId);
|
|
1295
|
+
await emitTaskStatusNotification(taskId, mcpSessionId, this.taskStore, this.server);
|
|
1296
|
+
finishTaskTracking(status, diagnostics, taskResult);
|
|
1297
|
+
};
|
|
1423
1298
|
// Once a task is cancelled the spec forbids writing a result; every storage path
|
|
1424
1299
|
// must short-circuit here. `logSuffix` is concatenated after "Task was cancelled"
|
|
1425
1300
|
// so we keep the existing log format and the existing telemetry status per path.
|
|
@@ -1472,77 +1347,32 @@ export class ActorsMcpServer {
|
|
|
1472
1347
|
await this.taskStore.updateTaskStatus(taskId, 'working', message, mcpSessionId);
|
|
1473
1348
|
await emitTaskStatusNotification(taskId, mcpSessionId, this.taskStore, this.server);
|
|
1474
1349
|
};
|
|
1475
|
-
//
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
progressTracker.stop();
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
// Handle actor tool execution in task mode
|
|
1506
|
-
if (toolStatus === TOOL_STATUS.SUCCEEDED && tool.type === TOOL_TYPE.ACTOR) {
|
|
1507
|
-
const progressTracker = createProgressTracker(progressToken, extra.sendNotification, taskId, onStatusMessage);
|
|
1508
|
-
try {
|
|
1509
|
-
log.info('Calling Actor for task', {
|
|
1510
|
-
taskId,
|
|
1511
|
-
toolName: tool.name,
|
|
1512
|
-
actorName: tool.actorFullName,
|
|
1513
|
-
mcpSessionId,
|
|
1514
|
-
input: logSafeArgs,
|
|
1515
|
-
});
|
|
1516
|
-
const executorResult = await actorExecutor.executeActorTool({
|
|
1517
|
-
actorFullName: tool.actorFullName,
|
|
1518
|
-
input: toolArgs,
|
|
1519
|
-
apifyClient,
|
|
1520
|
-
callOptions: { memory: tool.memoryMbytes },
|
|
1521
|
-
progressTracker,
|
|
1522
|
-
abortSignal: cancelWatcher.signal,
|
|
1523
|
-
mcpSessionId,
|
|
1524
|
-
datasetItemsSchema: tool.datasetItemsSchema,
|
|
1525
|
-
taskMode: true,
|
|
1526
|
-
});
|
|
1527
|
-
if (!executorResult) {
|
|
1528
|
-
toolStatus = TOOL_STATUS.ABORTED;
|
|
1529
|
-
// Receivers of cancellation notifications SHOULD NOT send a response for the cancelled request
|
|
1530
|
-
// https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/cancellation#behavior-requirements
|
|
1531
|
-
result = {};
|
|
1532
|
-
}
|
|
1533
|
-
else {
|
|
1534
|
-
// Mirror the INTERNAL task branch: extract embedded telemetry so failure_category
|
|
1535
|
-
// drives the success-path nudge below and toolTelemetry is stripped from the wire.
|
|
1536
|
-
({ toolStatus, callDiagnostics } = applyToolTelemetry(executorResult, actorName, actorId, callDiagnostics));
|
|
1537
|
-
result = executorResult;
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
finally {
|
|
1541
|
-
if (progressTracker) {
|
|
1542
|
-
progressTracker.stop();
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1350
|
+
// ACTOR_MCP never reads the tracker (matching the sync path, which passes null for it);
|
|
1351
|
+
// INTERNAL/ACTOR get one built from taskId + onStatusMessage, which dispatch consumes
|
|
1352
|
+
// and stops.
|
|
1353
|
+
const progressTracker = tool.type === TOOL_TYPE.ACTOR_MCP
|
|
1354
|
+
? null
|
|
1355
|
+
: createProgressTracker(progressToken, extra.sendNotification, taskId, onStatusMessage);
|
|
1356
|
+
const dispatchResult = await dispatchToolCall({
|
|
1357
|
+
tool,
|
|
1358
|
+
toolArgs,
|
|
1359
|
+
logSafeArgs,
|
|
1360
|
+
apifyToken,
|
|
1361
|
+
apifyClient,
|
|
1362
|
+
apifyMcpServer: this,
|
|
1363
|
+
mcpSessionId,
|
|
1364
|
+
progressToken,
|
|
1365
|
+
progressTracker,
|
|
1366
|
+
shouldForwardNotifications: false,
|
|
1367
|
+
extra: taskExtra,
|
|
1368
|
+
actorName,
|
|
1369
|
+
actorId,
|
|
1370
|
+
taskMode: true,
|
|
1371
|
+
logContext: { messageSuffix: ' for task', fields: { taskId } },
|
|
1372
|
+
});
|
|
1373
|
+
result = dispatchResult.result;
|
|
1374
|
+
toolStatus = dispatchResult.toolStatus;
|
|
1375
|
+
callDiagnostics = dispatchResult.callDiagnostics;
|
|
1546
1376
|
// Check if task was cancelled before storing result
|
|
1547
1377
|
if (await skipIfTaskCancelled(', skipping result storage', toolStatus))
|
|
1548
1378
|
return;
|
|
@@ -1554,10 +1384,8 @@ export class ActorsMcpServer {
|
|
|
1554
1384
|
taskId,
|
|
1555
1385
|
mcpSessionId,
|
|
1556
1386
|
});
|
|
1557
|
-
await
|
|
1387
|
+
await completeTask('completed', result, toolStatus, callDiagnostics);
|
|
1558
1388
|
log.debug('Task completed successfully', { taskId, toolName: tool.name, mcpSessionId });
|
|
1559
|
-
await emitTaskStatusNotification(taskId, mcpSessionId, this.taskStore, this.server);
|
|
1560
|
-
finishTaskTracking(toolStatus, callDiagnostics, result);
|
|
1561
1389
|
}
|
|
1562
1390
|
catch (error) {
|
|
1563
1391
|
// Reached only when the task expired before the `working` transition (updateTaskStatus
|
|
@@ -1591,9 +1419,7 @@ export class ActorsMcpServer {
|
|
|
1591
1419
|
...buildActorFields(actorName, actorId),
|
|
1592
1420
|
}))
|
|
1593
1421
|
return;
|
|
1594
|
-
await
|
|
1595
|
-
await emitTaskStatusNotification(taskId, mcpSessionId, this.taskStore, this.server);
|
|
1596
|
-
finishTaskTracking(errorResult.toolStatus, errorResult.callDiagnostics, errorResult.response);
|
|
1422
|
+
await completeTask('completed', errorResult.response, errorResult.toolStatus, errorResult.callDiagnostics);
|
|
1597
1423
|
return;
|
|
1598
1424
|
}
|
|
1599
1425
|
if (errorResult.kind === TOOL_CALL_ERROR_KIND.APPROVAL) {
|
|
@@ -1606,9 +1432,7 @@ export class ActorsMcpServer {
|
|
|
1606
1432
|
...buildActorFields(actorName, actorId),
|
|
1607
1433
|
}))
|
|
1608
1434
|
return;
|
|
1609
|
-
await
|
|
1610
|
-
await emitTaskStatusNotification(taskId, mcpSessionId, this.taskStore, this.server);
|
|
1611
|
-
finishTaskTracking(errorResult.toolStatus, errorResult.callDiagnostics, errorResult.response);
|
|
1435
|
+
await completeTask('completed', errorResult.response, errorResult.toolStatus, errorResult.callDiagnostics);
|
|
1612
1436
|
return;
|
|
1613
1437
|
}
|
|
1614
1438
|
toolStatus = errorResult.toolStatus;
|
|
@@ -1650,10 +1474,11 @@ export class ActorsMcpServer {
|
|
|
1650
1474
|
taskId,
|
|
1651
1475
|
mcpSessionId,
|
|
1652
1476
|
});
|
|
1653
|
-
// Nudge on a genuinely-failed task result
|
|
1654
|
-
//
|
|
1655
|
-
// the
|
|
1656
|
-
//
|
|
1477
|
+
// Nudge on a genuinely-failed task result (mirrors the completed path and the sync
|
|
1478
|
+
// captureResult). INTERNAL_ERROR and an unknown category get the full nudge; a genuine
|
|
1479
|
+
// INVALID_INPUT gets the softer nudge; payment (402) is suppressed via the HTTP status and
|
|
1480
|
+
// AUTH / PERMISSION_APPROVAL_REQUIRED via NON_NUDGE_FAILURE_CATEGORIES. The 402 branch above
|
|
1481
|
+
// returns before reaching here, so this only sees non-payment failures.
|
|
1657
1482
|
const failedResult = this.withReportProblemNudge({
|
|
1658
1483
|
content: [
|
|
1659
1484
|
{
|
|
@@ -1664,9 +1489,7 @@ export class ActorsMcpServer {
|
|
|
1664
1489
|
isError: true,
|
|
1665
1490
|
internalToolStatus: toolStatus,
|
|
1666
1491
|
}, tool.name, callDiagnostics.failure_category, callDiagnostics.failure_http_status);
|
|
1667
|
-
await
|
|
1668
|
-
await emitTaskStatusNotification(taskId, mcpSessionId, this.taskStore, this.server);
|
|
1669
|
-
finishTaskTracking(toolStatus, callDiagnostics, failedResult);
|
|
1492
|
+
await completeTask('failed', failedResult, toolStatus, callDiagnostics);
|
|
1670
1493
|
}
|
|
1671
1494
|
finally {
|
|
1672
1495
|
cancelWatcher.dispose();
|