{"record":{"id":"d12ea95fcc313938","repo":"spring-projects/spring-ai","slug":"prefix-or-toolname-cannot-be-null-or-empty","errorCode":null,"errorMessage":"Prefix or toolName cannot be null or empty","messagePattern":"Prefix or toolName cannot be null or empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"mcp/common/src/main/java/org/springframework/ai/mcp/McpToolUtils.java","lineNumber":95,"sourceCode":"\t/**\n\t * The name of tool context key used to store the MCP exchange object.\n\t */\n\tpublic static final String TOOL_CONTEXT_MCP_EXCHANGE_KEY = \"exchange\";\n\n\tprivate McpToolUtils() {\n\t}\n\n\t/**\n\t * @param prefix Client name, combination of client info name and the 'server'\n\t * connection name.\n\t * @param title Server connection name\n\t * @param toolName original MCP server tool name.\n\t * @return the prefix to use for the tool to avoid name collisions.\n\t */\n\tpublic static String prefixedToolName(String prefix, @Nullable String title, String toolName) {\n\n\t\tif (StringUtils.isEmpty(prefix) || StringUtils.isEmpty(toolName)) {\n\t\t\tthrow new IllegalArgumentException(\"Prefix or toolName cannot be null or empty\");\n\t\t}\n\n\t\tString input = shorten(format(prefix));\n\t\tif (!StringUtils.isEmpty(title)) {\n\t\t\tinput = input + \"_\" + format(title); // Do not shorten the title.\n\t\t}\n\n\t\tinput = input + \"_\" + format(toolName);\n\n\t\t// If the string is longer than 64 characters, keep the last 64 characters\n\t\tif (input.length() > 64) {\n\t\t\tinput = input.substring(input.length() - 64);\n\t\t}\n\n\t\treturn input;\n\t}\n\n\tpublic static String prefixedToolName(String prefix, String toolName) {","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/mcp/common/src/main/java/org/springframework/ai/mcp/McpToolUtils.java#L77-L113","documentation":"McpToolUtils.prefixedToolName() builds a namespaced MCP tool name from an optional title plus a mandatory connection prefix and the original tool name. It fails fast with IllegalArgumentException when the prefix or the toolName is null/empty, because a missing prefix would defeat collision avoidance and an empty tool name cannot be addressed.","triggerScenarios":"Calling McpToolUtils.prefixedToolName(prefix, title, toolName) directly with a null/empty prefix or toolName, or indirectly via McpToolUtils.getToolCallbacksFromMcpClients / tool callback providers with a client whose connectionNamePrefix is null/empty or where the server advertises a tool with a blank name.","commonSituations":"Constructing an MCP client without setting the connection name/prefix (the spring.ai.mcp.client.connections key left empty); calling the utility manually with \"\" as prefix; an MCP server registering a tool with an empty name (misbehaving server).","solutions":["Provide a non-empty connection name prefix for each MCP client (e.g. connectionNamePrefix(\"weather\"))","Check spring.ai.mcp.client.connections.<name> properties — the connection key that becomes the prefix must not be empty","Verify the MCP server is not advertising tools with empty names (fix or replace the server)","If calling the utility manually, guard prefix/toolName with StringUtils.hasText before invoking"],"exampleFix":"// before\nString name = McpToolUtils.prefixedToolName(null, null, \"get_forecast\");\n// after\nString name = McpToolUtils.prefixedToolName(\"weatherServer\", null, \"get_forecast\");\n// -> weatherServer_get_forecast","handlingStrategy":"validation","validationCode":"if (!StringUtils.hasText(prefix) || !StringUtils.hasText(toolName)) {\n    throw new IllegalArgumentException(\"prefix and toolName must be non-empty before calling prefixedToolName\");\n}","typeGuard":"boolean validToolNameArgs(String prefix, String toolName) {\n    return prefix != null && !prefix.isBlank() && toolName != null && !toolName.isBlank();\n}","tryCatchPattern":"try {\n    String name = McpToolUtils.prefixedToolName(prefix, title, toolName);\n} catch (IllegalArgumentException e) {\n    logger.error(\"Bad MCP tool naming inputs: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Set connection name/prefix explicitly for each MCP client in config","Check spring.ai.mcp.client.connections keys are non-empty","Reject servers advertising blank tool names at discovery time","Validate inputs with StringUtils.hasText before calling the utility"],"tags":["mcp","argument-validation","tool-naming"],"backgroundTag":"null-argument","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"}