{"record":{"id":"086a376e2398a6fb","repo":"spring-projects/spring-ai","slug":"tool-call-arguments-are-null-or-empty-for-mcp-tool","errorCode":null,"errorMessage":"Tool call arguments are null or empty for MCP tool: <toolName>. Using empty JSON object as default.","messagePattern":"Tool call arguments are null or empty for MCP tool: <toolName>\\. Using empty JSON object as default\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mcp/common/src/main/java/org/springframework/ai/mcp/AsyncMcpToolCallback.java","lineNumber":116,"sourceCode":"\t\treturn McpToolUtils.createToolDefinition(this.prefixedToolName, this.tool);\n\t}\n\n\tpublic String getOriginalToolName() {\n\t\treturn this.tool.name();\n\t}\n\n\t@Override\n\tpublic String call(String toolCallInput) {\n\t\treturn this.call(toolCallInput, null);\n\t}\n\n\t@Override\n\tpublic String call(String toolCallInput, @Nullable ToolContext toolContext) {\n\n\t\t// Handle the possible null parameter situation in streaming mode.\n\t\tif (!StringUtils.hasText(toolCallInput)) {\n\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(\"Tool call arguments are null or empty for MCP tool: \" + this.tool.name()\n\t\t\t\t\t\t+ \". Using empty JSON object as default.\");\n\t\t\t}\n\t\t\ttoolCallInput = \"{}\";\n\t\t}\n\n\t\tMap<String, Object> arguments = jsonHelper.fromJsonToMap(toolCallInput);\n\n\t\tCallToolResult response;\n\t\ttry {\n\t\t\tvar mcpMeta = toolContext != null ? this.toolContextToMcpMetaConverter.convert(toolContext) : null;\n\n\t\t\t// Use the original tool name, not the prefixed one from getToolDefinition\n\t\t\tvar request = CallToolRequest.builder(this.tool.name()).arguments(arguments).meta(mcpMeta).build();\n\n\t\t\t// Only map non-McpError exceptions to ToolExecutionException. McpError is a\n\t\t\t// protocol-level signal (e.g. URL elicitation) that must propagate as a hard\n\t\t\t// failure rather than being conveyed to the model as an error result.\n\t\t\tresponse = this.mcpClient.callTool(request).onErrorMap(e -> !(e instanceof McpError), e -> {","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/common/src/main/java/org/springframework/ai/mcp/AsyncMcpToolCallback.java#L98-L134","documentation":"AsyncMcpToolCallback.call() received a null/empty tool call input (typical when a model's streaming response yields no arguments) and, rather than failing JSON parsing, logs this warning and substitutes an empty JSON object \"{}\". The MCP tool is then invoked with no arguments, which may or may not be what the tool expects.","triggerScenarios":"Calling call() on an async MCP tool callback where toolCallInput is null, empty, or whitespace — commonly when streaming model output produces tool calls without arguments, or when the caller passes an empty string.","commonSituations":"Models emitting argument-less tool invocations in streaming mode; frameworks forwarding blank tool inputs on tool-end events; integrations where the LLM decided no arguments were needed but the underlying MCP tool requires them (leading to a downstream tool error instead).","solutions":["Ensure the tool actually accepts zero arguments; if it requires arguments, fix the prompting/schema so the model provides them.","Validate toolCallInput has text before invoking the callback and provide a meaningful default or error.","Check the MCP tool's inputSchema and pass required fields explicitly in the tool call input JSON.","If the empty-object default is fine, this warning can be ignored or the logger level adjusted."],"exampleFix":"// before: caller passes possibly-blank input\nString result = toolCallback.call(modelToolInput);\n// after: guard before the call\nString result = toolCallback.call(\n    StringUtils.hasText(modelToolInput) ? modelToolInput : \"{\\\"mode\\\":\\\"default\\\"}\");","handlingStrategy":"type-guard","validationCode":"if (input == null || input.isBlank()) {\n    input = \"{}\"; // or build the required arguments explicitly\n}\nJson.parse(input); // fail fast if not valid JSON before calling the tool","typeGuard":"boolean hasToolArguments(String input) {\n    return input != null && !input.isBlank();\n}","tryCatchPattern":"// the library does not throw; handle downstream tool errors\ntry {\n    String result = callback.call(input);\n} catch (NonToolExecutionException e) {\n    logger.error(\"MCP tool rejected arguments\", e);\n}","preventionTips":["Check the MCP tool's inputSchema; make required parameters explicit in prompts.","Never forward raw streaming model strings directly to tool callbacks without inspection.","Treat blank tool input as a signal of a prompting or truncation problem.","Unit-test your tool pipeline with argument-less model outputs."],"tags":["mcp","tool-calling","empty-argument","streaming"],"backgroundTag":"empty-required-field","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}