Skip to content

Commit 61abf3c

Browse files
matthvclaude
andcommitted
feat(workflow-executor): add sourceId to McpToolRef for MCP tool traceability
Add sourceId to McpToolRef so that persisted execution data (pendingData, executionParams) tracks which MCP server provided the tool. This fixes tool lookup on re-entry (confirmation flow) when multiple servers expose tools with the same name. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5db77cd commit 61abf3c

4 files changed

Lines changed: 17 additions & 10 deletions

File tree

packages/workflow-executor/src/executors/mcp-step-executor.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export default class McpStepExecutor extends BaseStepExecutor<McpStepDefinition>
5757
// Branches B & C -- First call
5858
const tools = this.getFilteredTools();
5959
const { toolName, args } = await this.selectTool(tools);
60-
const target: McpToolCall = { name: toolName, input: args };
60+
const selectedTool = tools.find(t => t.base.name === toolName);
61+
const target: McpToolCall = { name: toolName, sourceId: selectedTool!.sourceId, input: args };
6162

6263
if (this.context.stepDefinition.automaticExecution) {
6364
// Branch B -- direct execution
@@ -87,7 +88,7 @@ export default class McpStepExecutor extends BaseStepExecutor<McpStepDefinition>
8788
existingExecution?: McpStepExecutionData,
8889
): Promise<StepExecutionResult> {
8990
const tools = this.getFilteredTools();
90-
const tool = tools.find(t => t.base.name === target.name);
91+
const tool = tools.find(t => t.base.name === target.name && t.sourceId === target.sourceId);
9192
if (!tool) throw new McpToolNotFoundError(target.name);
9293

9394
let toolResult: unknown;
@@ -104,7 +105,7 @@ export default class McpStepExecutor extends BaseStepExecutor<McpStepDefinition>
104105
...existingExecution,
105106
type: 'mcp',
106107
stepIndex: this.context.stepIndex,
107-
executionParams: { name: target.name, input: target.input },
108+
executionParams: { name: target.name, sourceId: target.sourceId, input: target.input },
108109
executionResult: baseExecutionResult,
109110
};
110111

packages/workflow-executor/src/types/step-execution-data.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export interface TriggerRecordActionStepExecutionData extends BaseStepExecutionD
8383
/** Reference to an MCP tool by its sanitized name (OpenAI-safe, alphanumeric + underscores/hyphens). */
8484
export interface McpToolRef {
8585
name: string;
86+
sourceId: string;
8687
}
8788

8889
/** A resolved tool call: sanitized tool name + input parameters sent to the tool. */

packages/workflow-executor/test/executors/mcp-step-executor.test.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ describe('McpStepExecutor', () => {
145145
expect.objectContaining({
146146
type: 'mcp',
147147
stepIndex: 0,
148-
executionParams: { name: 'send_notification', input: { message: 'Hello' } },
148+
executionParams: { name: 'send_notification', sourceId: 'mcp-server-1', input: { message: 'Hello' } },
149149
executionResult: { success: true, toolResult: { result: 'notification sent' } },
150150
}),
151151
);
@@ -292,7 +292,7 @@ describe('McpStepExecutor', () => {
292292
expect.objectContaining({
293293
type: 'mcp',
294294
stepIndex: 0,
295-
pendingData: { name: 'send_notification', input: { message: 'Hello' } },
295+
pendingData: { name: 'send_notification', sourceId: 'mcp-server-1', input: { message: 'Hello' } },
296296
}),
297297
);
298298
});
@@ -331,6 +331,7 @@ describe('McpStepExecutor', () => {
331331
stepIndex: 0,
332332
pendingData: {
333333
name: 'send_notification',
334+
sourceId: 'mcp-server-1',
334335
input: { message: 'Hello' },
335336
userConfirmed: true,
336337
},
@@ -349,10 +350,11 @@ describe('McpStepExecutor', () => {
349350
'run-1',
350351
expect.objectContaining({
351352
type: 'mcp',
352-
executionParams: { name: 'send_notification', input: { message: 'Hello' } },
353+
executionParams: { name: 'send_notification', sourceId: 'mcp-server-1', input: { message: 'Hello' } },
353354
executionResult: { success: true, toolResult: 'email sent' },
354355
pendingData: {
355356
name: 'send_notification',
357+
sourceId: 'mcp-server-1',
356358
input: { message: 'Hello' },
357359
userConfirmed: true,
358360
},
@@ -374,6 +376,7 @@ describe('McpStepExecutor', () => {
374376
stepIndex: 0,
375377
pendingData: {
376378
name: 'send_notification',
379+
sourceId: 'mcp-server-1',
377380
input: { message: 'Hello' },
378381
userConfirmed: false,
379382
},
@@ -394,6 +397,7 @@ describe('McpStepExecutor', () => {
394397
executionResult: { skipped: true },
395398
pendingData: {
396399
name: 'send_notification',
400+
sourceId: 'mcp-server-1',
397401
input: { message: 'Hello' },
398402
userConfirmed: false,
399403
},
@@ -463,7 +467,7 @@ describe('McpStepExecutor', () => {
463467
const execution: McpStepExecutionData = {
464468
type: 'mcp',
465469
stepIndex: 0,
466-
pendingData: { name: 'deleted_tool', input: {}, userConfirmed: true },
470+
pendingData: { name: 'deleted_tool', sourceId: 'mcp-server-1', input: {}, userConfirmed: true },
467471
};
468472
const tool = new MockRemoteTool({ name: 'other_tool', sourceId: 'mcp-server-1' });
469473
const runStore = makeMockRunStore({
@@ -525,6 +529,7 @@ describe('McpStepExecutor', () => {
525529
stepIndex: 0,
526530
pendingData: {
527531
name: 'send_notification',
532+
sourceId: 'mcp-server-1',
528533
input: { message: 'Hello' },
529534
userConfirmed: true,
530535
},

packages/workflow-executor/test/executors/step-execution-formatters.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ describe('StepExecutionFormatters', () => {
6969
const execution: StepExecutionData = {
7070
type: 'mcp',
7171
stepIndex: 2,
72-
executionParams: { name: 'search_records', input: { query: 'foo' } },
72+
executionParams: { name: 'search_records', sourceId: 'mcp-server-1', input: { query: 'foo' } },
7373
executionResult: {
7474
success: true,
7575
toolResult: { items: [] },
@@ -84,7 +84,7 @@ describe('StepExecutionFormatters', () => {
8484
const execution: StepExecutionData = {
8585
type: 'mcp',
8686
stepIndex: 2,
87-
executionParams: { name: 'search_records', input: { query: 'foo' } },
87+
executionParams: { name: 'search_records', sourceId: 'mcp-server-1', input: { query: 'foo' } },
8888
executionResult: { success: true, toolResult: { items: [] } },
8989
};
9090

@@ -97,7 +97,7 @@ describe('StepExecutionFormatters', () => {
9797
const execution: StepExecutionData = {
9898
type: 'mcp',
9999
stepIndex: 2,
100-
pendingData: { name: 'search_records', input: {} },
100+
pendingData: { name: 'search_records', sourceId: 'mcp-server-1', input: {} },
101101
};
102102

103103
expect(StepExecutionFormatters.format(execution)).toBeNull();

0 commit comments

Comments
 (0)