From 6a731ef04d960888ef5997aabbab800cc076a32b Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 4 Jun 2026 11:07:12 -0700 Subject: [PATCH 1/3] fix(mcp): enforce tool name validation in deploy modal --- .../deploy-modal/components/mcp/mcp.tsx | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx index 0047c8e354d..09f8e67e031 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx @@ -14,6 +14,7 @@ import { Textarea, } from '@/components/emcn' import { generateToolInputSchema, sanitizeToolName } from '@/lib/mcp/workflow-tool-schema' +import { cn } from '@/lib/utils' import { normalizeInputFormatValue } from '@/lib/workflows/input-format' import { isInputDefinitionTrigger } from '@/lib/workflows/triggers/input-definition-triggers' import type { InputFormatField } from '@/lib/workflows/types' @@ -32,6 +33,10 @@ import { useWorkflowStore } from '@/stores/workflows/workflow/store' const logger = createLogger('McpToolDeploy') +/** MCP tool names allow lowercase letters, numbers, and underscores only */ +const TOOL_NAME_PATTERN = /^[a-z0-9_]+$/ +const MAX_TOOL_NAME_LENGTH = 64 + /** InputFormatField with guaranteed name (after normalization) */ type NormalizedField = InputFormatField & { name: string } @@ -166,6 +171,18 @@ export function McpDeploy({ [inputFormat, parameterDescriptions] ) + const toolNameError = useMemo(() => { + const trimmed = toolName.trim() + if (!trimmed) return null + if (trimmed.length > MAX_TOOL_NAME_LENGTH) { + return `Tool name must be ${MAX_TOOL_NAME_LENGTH} characters or fewer` + } + if (!TOOL_NAME_PATTERN.test(trimmed)) { + return 'Tool name can only contain lowercase letters, numbers, and underscores' + } + return null + }, [toolName]) + const [serverToolsMap, setServerToolsMap] = useState< Record >({}) @@ -270,11 +287,11 @@ export function McpDeploy({ (hasToolConfigurationChanges && selectedServerIdsForForm.length > 0) useEffect(() => { - onCanSaveChange?.(hasChanges && !!toolName.trim()) - }, [hasChanges, toolName, onCanSaveChange]) + onCanSaveChange?.(hasChanges && !!toolName.trim() && !toolNameError) + }, [hasChanges, toolName, toolNameError, onCanSaveChange]) const handleSave = async () => { - if (!toolName.trim()) return + if (!toolName.trim() || toolNameError) return const currentIds = new Set(selectedServerIds) const nextIds = new Set(selectedServerIdsForForm) @@ -492,9 +509,16 @@ export function McpDeploy({ value={toolName} onChange={(e) => setToolName(e.target.value)} placeholder='e.g., book_flight' + aria-invalid={!!toolNameError} + className={cn(toolNameError && 'border-[var(--text-error)]')} /> -

- Use lowercase letters, numbers, and underscores only +

+ {toolNameError ?? 'Use lowercase letters, numbers, and underscores only'}

@@ -564,7 +588,7 @@ export function McpDeploy({ placeholder='Select servers...' searchable searchPlaceholder='Search servers...' - disabled={!toolName.trim() || isPending} + disabled={!toolName.trim() || !!toolNameError || isPending} overlayContent={ {selectedServersLabel} } From 17e6b8fcc32c56306d62fca3492970c56f2ffa3e Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 4 Jun 2026 11:13:25 -0700 Subject: [PATCH 2/3] fix(mcp): correct cn import path to fix build --- .../deploy/components/deploy-modal/components/mcp/mcp.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx index 09f8e67e031..4cd07dd9b83 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx @@ -13,8 +13,8 @@ import { Skeleton, Textarea, } from '@/components/emcn' +import { cn } from '@/lib/core/utils/cn' import { generateToolInputSchema, sanitizeToolName } from '@/lib/mcp/workflow-tool-schema' -import { cn } from '@/lib/utils' import { normalizeInputFormatValue } from '@/lib/workflows/input-format' import { isInputDefinitionTrigger } from '@/lib/workflows/triggers/input-definition-triggers' import type { InputFormatField } from '@/lib/workflows/types' From 2979b35ac6108a53725572c5f863ed59343a25db Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 4 Jun 2026 11:15:11 -0700 Subject: [PATCH 3/3] fix(mcp): align tool-name regex with server sanitization, add disabled-combobox hint --- .../deploy-modal/components/mcp/mcp.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx index 4cd07dd9b83..455aa3f50fc 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/components/mcp/mcp.tsx @@ -33,8 +33,12 @@ import { useWorkflowStore } from '@/stores/workflows/workflow/store' const logger = createLogger('McpToolDeploy') -/** MCP tool names allow lowercase letters, numbers, and underscores only */ -const TOOL_NAME_PATTERN = /^[a-z0-9_]+$/ +/** + * Mirrors the server's `sanitizeToolName` output: lowercase alphanumerics with single + * underscores between segments. Disallows leading/trailing and consecutive underscores so + * the validated name matches exactly what the server persists (no silent rewrite). + */ +const TOOL_NAME_PATTERN = /^[a-z0-9]+(_[a-z0-9]+)*$/ const MAX_TOOL_NAME_LENGTH = 64 /** InputFormatField with guaranteed name (after normalization) */ @@ -178,7 +182,7 @@ export function McpDeploy({ return `Tool name must be ${MAX_TOOL_NAME_LENGTH} characters or fewer` } if (!TOOL_NAME_PATTERN.test(trimmed)) { - return 'Tool name can only contain lowercase letters, numbers, and underscores' + return 'Use lowercase letters and numbers, separated by single underscores' } return null }, [toolName]) @@ -593,11 +597,15 @@ export function McpDeploy({ {selectedServersLabel} } /> - {!toolName.trim() && ( + {!toolName.trim() ? (

Enter a tool name to select servers

- )} + ) : toolNameError ? ( +

+ Fix the tool name to select servers +

+ ) : null} {saveErrors.length > 0 && (