Skip to content

Commit dae8bab

Browse files
j15zclaude
andcommitted
fix(workflow): thread custom-tool and MCP data into the search indexer; fix blockConfigs type
The search index now resolves tool names with the same data as the chip renderers: the single caller passes customTools and a live MCP name map into indexWorkflowSearchMatches, so indexed names match the panel for custom-tool references and MCP entries, not just registry-backed types. Also declare the optional name on WorkflowSearchIndexerOptions blockConfigs entries, fixing the next build type error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a23df48 commit dae8bab

4 files changed

Lines changed: 80 additions & 1 deletion

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/search-replace/workflow-search-replace.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ import {
3535
} from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/float'
3636
import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow'
3737
import { getBlock } from '@/blocks'
38+
import { useMcpTools } from '@/hooks/mcp/use-mcp-tools'
3839
import { useWorkspaceCredentials } from '@/hooks/queries/credentials'
40+
import { useCustomTools } from '@/hooks/queries/custom-tools'
3941
import { useFolderMap } from '@/hooks/queries/folders'
4042
import { isWorkflowEffectivelyLocked } from '@/hooks/queries/utils/folder-tree'
4143
import { useWorkflowMap } from '@/hooks/queries/workflows'
@@ -170,6 +172,15 @@ export function WorkflowSearchReplace() {
170172
const prevIsOpenRef = useRef(false)
171173
const afterReplaceIndexRef = useRef<number | null>(null)
172174
const { data: workspaceCredentials } = useWorkspaceCredentials({ workspaceId, enabled: isOpen })
175+
const { data: customTools = [] } = useCustomTools(isOpen && workspaceId ? workspaceId : '')
176+
const { mcpTools } = useMcpTools(isOpen && workspaceId ? workspaceId : '')
177+
const mcpToolNamesById = useMemo(() => {
178+
const names = new Map<string, string>()
179+
for (const t of mcpTools) {
180+
if (!names.has(t.id)) names.set(t.id, t.name)
181+
}
182+
return names
183+
}, [mcpTools])
173184

174185
useRegisterGlobalCommands([
175186
createCommand({
@@ -215,10 +226,14 @@ export function WorkflowSearchReplace() {
215226
workspaceId,
216227
workflowId,
217228
credentialTypeById,
229+
customTools,
230+
mcpToolNamesById,
218231
}),
219232
[
220233
currentWorkflow.isSnapshotView,
221234
credentialTypeById,
235+
customTools,
236+
mcpToolNamesById,
222237
query,
223238
readonlyReason,
224239
searchBlocks,

apps/sim/lib/workflows/search-replace/indexer.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,50 @@ describe('indexWorkflowSearchMatches', () => {
14231423
expect(matches.some((match) => match.valuePath.includes('schema'))).toBe(false)
14241424
})
14251425

1426+
it('indexes canonical MCP and custom-tool names over mutated stored titles', () => {
1427+
const workflow = createSearchReplaceWorkflowFixture()
1428+
workflow.blocks['tool-input-1'] = {
1429+
id: 'tool-input-1',
1430+
type: 'custom',
1431+
name: 'Tool Input Block',
1432+
position: { x: 0, y: 0 },
1433+
enabled: true,
1434+
outputs: {},
1435+
subBlocks: {
1436+
tools: {
1437+
id: 'tools',
1438+
type: 'tool-input',
1439+
value: [
1440+
{ type: 'mcp', toolId: 'mcp-tool-1', title: 'Mutated Title', params: {} },
1441+
{ type: 'custom-tool', customToolId: 'ct-1', title: 'Mutated Title', params: {} },
1442+
],
1443+
},
1444+
},
1445+
}
1446+
1447+
const matches = indexWorkflowSearchMatches({
1448+
workflow,
1449+
query: 'customer',
1450+
mode: 'text',
1451+
blockConfigs: {
1452+
...SEARCH_REPLACE_BLOCK_CONFIGS,
1453+
custom: {
1454+
subBlocks: [{ id: 'tools', title: 'Tools', type: 'tool-input' }],
1455+
},
1456+
},
1457+
customTools: [{ id: 'ct-1', title: 'Customer Records' }],
1458+
mcpToolNamesById: new Map([['mcp-tool-1', 'customer_lookup']]),
1459+
}).filter((match) => match.blockId === 'tool-input-1')
1460+
1461+
expect(matches).toEqual(
1462+
expect.arrayContaining([
1463+
expect.objectContaining({ valuePath: [0, 'title'], searchText: 'customer_lookup' }),
1464+
expect.objectContaining({ valuePath: [1, 'title'], searchText: 'Customer Records' }),
1465+
])
1466+
)
1467+
expect(matches.some((match) => match.searchText === 'Mutated Title')).toBe(false)
1468+
})
1469+
14261470
it('indexes explicit secret tool params for intentional replacement', () => {
14271471
const workflow = createSearchReplaceWorkflowFixture()
14281472
workflow.blocks['tool-input-1'] = {

apps/sim/lib/workflows/search-replace/indexer.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,8 @@ function addToolInputMatches({
932932
workflowId,
933933
credentialTypeById,
934934
blockConfigs,
935+
customTools,
936+
mcpToolNamesById,
935937
}: {
936938
matches: WorkflowSearchMatch[]
937939
block: WorkflowSearchBlockState
@@ -951,13 +953,17 @@ function addToolInputMatches({
951953
workflowId?: string
952954
credentialTypeById?: Record<string, string | undefined>
953955
blockConfigs?: WorkflowSearchIndexerOptions['blockConfigs']
956+
customTools?: WorkflowSearchIndexerOptions['customTools']
957+
mcpToolNamesById?: WorkflowSearchIndexerOptions['mcpToolNamesById']
954958
}) {
955959
const parentCanonicalModes = getSearchCanonicalModes(block)
956960

957961
parseStoredToolInputValue(value).forEach((tool, toolIndex) => {
958962
// Index the resolved display name (not the stored mutable title) so
959963
// search text and highlights match what the tool chip actually renders.
960964
const toolDisplayName = resolveStoredToolName(tool, {
965+
customTools,
966+
mcpToolNamesById,
961967
getBlockConfig: (type) => blockConfigs?.[type] ?? getBlock(type),
962968
})
963969
if (mode !== 'resource' && toolDisplayName) {
@@ -1234,6 +1240,8 @@ export function indexWorkflowSearchMatches(
12341240
workflowId,
12351241
blockConfigs = {},
12361242
credentialTypeById,
1243+
customTools,
1244+
mcpToolNamesById,
12371245
} = options
12381246

12391247
const matches: WorkflowSearchMatch[] = []
@@ -1369,6 +1377,8 @@ export function indexWorkflowSearchMatches(
13691377
workflowId,
13701378
credentialTypeById,
13711379
blockConfigs,
1380+
customTools,
1381+
mcpToolNamesById,
13721382
})
13731383
continue
13741384
}

apps/sim/lib/workflows/search-replace/types.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
WorkflowSearchSubflowEditableValue,
44
WorkflowSearchSubflowFieldId,
55
} from '@/lib/workflows/search-replace/subflow-fields'
6+
import type { StoredCustomToolRecord } from '@/lib/workflows/subblocks/display'
67
import type { SubBlockConfig } from '@/blocks/types'
78
import type { SelectorContext } from '@/hooks/selectors/types'
89
import type { BlockState, SubBlockState } from '@/stores/workflows/workflow/types'
@@ -96,10 +97,19 @@ export interface WorkflowSearchIndexerOptions {
9697
workflowId?: string
9798
blockConfigs?: Record<
9899
string,
99-
| { subBlocks?: SubBlockConfig[]; triggers?: { enabled?: boolean }; category?: string }
100+
| {
101+
name?: string
102+
subBlocks?: SubBlockConfig[]
103+
triggers?: { enabled?: boolean }
104+
category?: string
105+
}
100106
| undefined
101107
>
102108
credentialTypeById?: Record<string, string | undefined>
109+
/** Custom-tool records so indexed tool names match the rendered chips. */
110+
customTools?: StoredCustomToolRecord[]
111+
/** Live MCP tool names keyed by composite tool id, same as the chip renderers. */
112+
mcpToolNamesById?: ReadonlyMap<string, string>
103113
}
104114

105115
export interface WorkflowSearchReplacementOption {

0 commit comments

Comments
 (0)