Skip to content

Commit fdc2679

Browse files
committed
fix(workflow-mcp): preserve block-default input fields when editing param descriptions
updateFieldDescription read only from the subblock store, but the display memo falls back to the block's persisted inputFormat when the store entry is empty. For workflows whose fields are hydrated from block defaults, editing a description would have written [] and wiped every input field. Extract a shared resolveInputFormatFields helper used by both the memo and the writer, and guard against ever persisting an empty list.
1 parent 8ce8f0a commit fdc2679

1 file changed

Lines changed: 27 additions & 11 deletions

File tree

  • apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,22 @@ function haveSameServerSelection(a: string[], b: string[]): boolean {
6464
return a.every((id) => bSet.has(id))
6565
}
6666

67+
/**
68+
* Resolves the start block's input fields from the subblock store, falling back
69+
* to the block's persisted value when the store entry is empty (fields hydrated
70+
* from block defaults). Shared by the display memo and the description writer so
71+
* both read the exact same source — a writer that skipped the fallback could
72+
* persist `[]` and wipe every field.
73+
*/
74+
function resolveInputFormatFields(
75+
storeValue: unknown,
76+
blockFallbackValue: unknown
77+
): NormalizedField[] {
78+
const fromStore = normalizeInputFormatValue(storeValue) as NormalizedField[]
79+
if (fromStore.length > 0) return fromStore
80+
return normalizeInputFormatValue(blockFallbackValue) as NormalizedField[]
81+
}
82+
6783
/**
6884
* Component to query tools for a single server and report back via callback.
6985
*/
@@ -127,14 +143,10 @@ export function McpDeploy({
127143

128144
const inputFormat = useMemo((): NormalizedField[] => {
129145
if (!starterBlockId) return []
130-
131-
const storeValue = subBlockValues[starterBlockId]?.inputFormat
132-
const normalized = normalizeInputFormatValue(storeValue) as NormalizedField[]
133-
if (normalized.length > 0) return normalized
134-
135-
const startBlock = blocks[starterBlockId]
136-
const blockValue = startBlock?.subBlocks?.inputFormat?.value
137-
return normalizeInputFormatValue(blockValue) as NormalizedField[]
146+
return resolveInputFormatFields(
147+
subBlockValues[starterBlockId]?.inputFormat,
148+
blocks[starterBlockId]?.subBlocks?.inputFormat?.value
149+
)
138150
}, [starterBlockId, subBlockValues, blocks])
139151

140152
const [toolName, setToolName] = useState(() => sanitizeToolName(workflowName))
@@ -154,9 +166,13 @@ export function McpDeploy({
154166
const updateFieldDescription = useCallback(
155167
(fieldName: string, description: string) => {
156168
if (!starterBlockId) return
157-
const currentFields = normalizeInputFormatValue(
158-
useSubBlockStore.getState().getValue(starterBlockId, 'inputFormat')
159-
) as NormalizedField[]
169+
const currentFields = resolveInputFormatFields(
170+
useSubBlockStore.getState().getValue(starterBlockId, 'inputFormat'),
171+
useWorkflowStore.getState().blocks[starterBlockId]?.subBlocks?.inputFormat?.value
172+
)
173+
// Never persist an empty list: the description inputs only render when fields
174+
// exist, so an empty resolution means a transient state we must not write back.
175+
if (currentFields.length === 0) return
160176
const nextFields = currentFields.map((field) =>
161177
field.name === fieldName ? { ...field, description } : field
162178
)

0 commit comments

Comments
 (0)