diff --git a/apps/sim/app/workspace/[workspaceId]/settings/components/mcp/components/mcp-server-form-modal/mcp-server-form-modal.tsx b/apps/sim/app/workspace/[workspaceId]/settings/components/mcp/components/mcp-server-form-modal/mcp-server-form-modal.tsx
index 9c93dd8fa01..fe6d59e0967 100644
--- a/apps/sim/app/workspace/[workspaceId]/settings/components/mcp/components/mcp-server-form-modal/mcp-server-form-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/settings/components/mcp/components/mcp-server-form-modal/mcp-server-form-modal.tsx
@@ -157,7 +157,7 @@ function FormattedInput({
onChange={onChange}
onScroll={handleScroll}
onInput={handleScroll}
- inputClassName='text-transparent caret-[var(--text-primary)]'
+ inputClassName='font-medium font-sans text-transparent caret-[var(--text-primary)]'
/>
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/mcp-dynamic-args/mcp-dynamic-args.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/mcp-dynamic-args/mcp-dynamic-args.tsx
index 5fa807b3f73..3994248ef6d 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/mcp-dynamic-args/mcp-dynamic-args.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/mcp-dynamic-args/mcp-dynamic-args.tsx
@@ -15,6 +15,33 @@ import { formatParameterLabel } from '@/tools/params'
const logger = createLogger('McpDynamicArgs')
+/**
+ * The dropdown UI renders each enum member as a string label/value, so it can only
+ * represent JSON Schema enums whose members are primitives — a non-primitive member
+ * (object/array) would collapse to "[object Object]" and lose its identity. Callers
+ * route a non-primitive enum to the JSON editor (`long-input`) instead.
+ */
+function isPrimitiveEnum(
+ enumValues: unknown
+): enumValues is Array {
+ return (
+ Array.isArray(enumValues) &&
+ enumValues.every((value) => value === null || typeof value !== 'object')
+ )
+}
+
+/**
+ * True when the schema's actual value must be a JSON object/array (a plain
+ * object/array type, or a non-primitive enum member) rather than a string.
+ */
+function requiresJsonValue(paramSchema: any): boolean {
+ return (
+ paramSchema.type === 'object' ||
+ paramSchema.type === 'array' ||
+ (Array.isArray(paramSchema.enum) && !isPrimitiveEnum(paramSchema.enum))
+ )
+}
+
interface McpDynamicArgsProps {
blockId: string
subBlockId: string
@@ -116,7 +143,9 @@ export function McpDynamicArgs({
)
const getInputType = (paramSchema: any) => {
- if (paramSchema.enum) return 'dropdown'
+ if (Array.isArray(paramSchema.enum)) {
+ return isPrimitiveEnum(paramSchema.enum) ? 'dropdown' : 'long-input'
+ }
if (paramSchema.type === 'boolean') return 'switch'
if (paramSchema.type === 'number' || paramSchema.type === 'integer') {
if (paramSchema.minimum !== undefined && paramSchema.maximum !== undefined) {
@@ -241,6 +270,8 @@ export function McpDynamicArgs({
case 'long-input': {
const config = createParamConfig(paramName, paramSchema, 'long-input')
+ const displayValue =
+ typeof value === 'string' || value == null ? value || '' : JSON.stringify(value)
return (
updateParameter(paramName, newValue)}
+ value={displayValue}
+ onChange={(newValue) => {
+ if (!requiresJsonValue(paramSchema)) {
+ updateParameter(paramName, newValue)
+ return
+ }
+ try {
+ updateParameter(paramName, JSON.parse(newValue))
+ } catch {
+ updateParameter(paramName, newValue)
+ }
+ }}
isPreview={isPreview}
disabled={disabled}
workflowSearchValuePath={[paramName]}
diff --git a/apps/sim/lib/api/contracts/mcp.ts b/apps/sim/lib/api/contracts/mcp.ts
index dfcddac85ad..1c0159e9ec2 100644
--- a/apps/sim/lib/api/contracts/mcp.ts
+++ b/apps/sim/lib/api/contracts/mcp.ts
@@ -50,10 +50,12 @@ export const mcpToolSchemaPropertySchema: z.ZodType = z.l
.object({
type: z.union([z.string(), z.array(z.string())]).optional(),
description: z.string().optional(),
- items: mcpToolSchemaPropertySchema.optional(),
+ items: z
+ .union([mcpToolSchemaPropertySchema, z.array(mcpToolSchemaPropertySchema)])
+ .optional(),
properties: z.record(z.string(), mcpToolSchemaPropertySchema).optional(),
required: z.array(z.string()).optional(),
- enum: z.array(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional(),
+ enum: z.array(z.unknown()).optional(),
default: z.unknown().optional(),
})
.passthrough()
diff --git a/apps/sim/lib/mcp/types.ts b/apps/sim/lib/mcp/types.ts
index be506fd5b07..575e86ea2f8 100644
--- a/apps/sim/lib/mcp/types.ts
+++ b/apps/sim/lib/mcp/types.ts
@@ -68,10 +68,10 @@ export interface McpSecurityPolicy {
export interface McpToolSchemaProperty {
type?: string | string[]
description?: string
- items?: McpToolSchemaProperty
+ items?: McpToolSchemaProperty | McpToolSchemaProperty[]
properties?: Record
required?: string[]
- enum?: Array
+ enum?: unknown[]
default?: unknown
[key: string]: unknown
}