From 4364a771d443ba7a18e5144e073bbeb08eca697f Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Tue, 10 Feb 2026 15:42:51 +0400 Subject: [PATCH] fix(mcp): Validate required tool args and fix title fallback for existing blocks Backend: Add required-field validation in MCPToolBlock.run() before calling the MCP server. The executor-level validation is bypassed for MCP blocks because get_input_defaults() flattens tool_arguments, stripping tool_input_schema from the validation context. Frontend: NodeHeader now derives the MCP server label from the server URL hostname when server_name is missing (pruned by pruneEmptyValues). This fixes the title for existing blocks that don't have customized_name in metadata. --- .../backend/backend/blocks/mcp/block.py | 14 ++++++++++++++ .../nodes/CustomNode/components/NodeHeader.tsx | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/autogpt_platform/backend/backend/blocks/mcp/block.py b/autogpt_platform/backend/backend/blocks/mcp/block.py index ebb7aacc6b..92a57e7477 100644 --- a/autogpt_platform/backend/backend/blocks/mcp/block.py +++ b/autogpt_platform/backend/backend/blocks/mcp/block.py @@ -260,6 +260,20 @@ class MCPToolBlock(Block): yield "error", "No tool selected. Please select a tool from the dropdown." return + # Validate required tool arguments before calling the server. + # The executor-level validation is bypassed for MCP blocks because + # get_input_defaults() flattens tool_arguments, stripping tool_input_schema + # from the validation context. + required = set(input_data.tool_input_schema.get("required", [])) + if required: + missing = required - set(input_data.tool_arguments.keys()) + if missing: + yield "error", ( + f"Missing required argument(s): {', '.join(sorted(missing))}. " + f"Please fill in all required fields marked with * in the block form." + ) + return + # If no credentials were injected by the executor (e.g. legacy nodes # that don't have the credentials field set), try to auto-lookup # the stored MCP credential for this server URL. diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx index 817fe39bfe..a37cda2159 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/nodes/CustomNode/components/NodeHeader.tsx @@ -25,10 +25,24 @@ export const NodeHeader = ({ data, nodeId }: Props) => { data.block_id === SpecialBlockID.MCP_TOOL && !!data.hardcodedValues?.selected_tool; + // Derive MCP server label: prefer server_name, fall back to URL hostname. + let mcpServerLabel = "MCP"; + if (isMCPWithTool) { + mcpServerLabel = + data.hardcodedValues.server_name || + (() => { + try { + return new URL(data.hardcodedValues.server_url).hostname; + } catch { + return "MCP"; + } + })(); + } + const title = (data.metadata?.customized_name as string) || (isMCPWithTool - ? `${data.hardcodedValues.server_name || "MCP"}: ${beautifyString(data.hardcodedValues.selected_tool)}` + ? `${mcpServerLabel}: ${beautifyString(data.hardcodedValues.selected_tool)}` : null) || data.hardcodedValues?.agent_name || data.title;