{"record":{"id":"c253d4392aa587ec","repo":"alibaba/spring-ai-alibaba","slug":"tool-definition-name-is-not-available","errorCode":null,"errorMessage":"Tool definition name is not available","messagePattern":"Tool definition name is not available","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-boot-starters/spring-ai-alibaba-starter-config-nacos/src/main/java/com/alibaba/cloud/ai/agent/nacos/tools/NacosMcpGatewayToolCallback.java","lineNumber":493,"sourceCode":"\t\t\t// 构建基础URL，根据协议类型调整\n\t\t\tString transportProtocol = StringUtils.hasText(serviceRef.getTransportProtocol()) ? serviceRef.getTransportProtocol() : \"http\";\n\t\t\tStringBuilder baseUrl;\n\t\t\tif (\"mcp-sse\".equalsIgnoreCase(protocol)) {\n\t\t\t\tbaseUrl = new StringBuilder(transportProtocol + \"://\" + mcpEndpointInfo.getAddress() + \":\" + mcpEndpointInfo.getPort());\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// mcp-streamable 或其他协议\n\t\t\t\tbaseUrl = new StringBuilder(transportProtocol + \"://\" + mcpEndpointInfo.getAddress() + \":\" + mcpEndpointInfo.getPort());\n\t\t\t}\n\n\t\t\tlogger.info(\"[handleMcpStreamProtocol] Processing {} protocol with args: {} and baseUrl: {}\", protocol,\n\t\t\t\t\targs, baseUrl.toString());\n\n\t\t\ttry {\n\t\t\t\t// 获取工具名称 - 从工具定义名称中提取实际的工具名称\n\t\t\t\tString toolDefinitionName = this.toolDefinition.name();\n\t\t\t\tif (toolDefinitionName == null || toolDefinitionName.isEmpty()) {\n\t\t\t\t\tthrow new RuntimeException(\"Tool definition name is not available\");\n\t\t\t\t}\n\n\t\t\t\t// 工具定义名称格式为: serverName_tools_toolName\n\t\t\t\t// 需要提取最后的 toolName 部分\n\t\t\t\tString toolName;\n\t\t\t\tif (toolDefinitionName.contains(\"_tools_\")) {\n\t\t\t\t\ttoolName = toolDefinitionName.substring(toolDefinitionName.lastIndexOf(\"_tools_\") + 7);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 如果没有 _tools_ 分隔符，使用整个名称\n\t\t\t\t\ttoolName = toolDefinitionName;\n\t\t\t\t}\n\n\t\t\t\tif (toolName.isEmpty()) {\n\t\t\t\t\tthrow new RuntimeException(\"Extracted tool name is empty\");\n\t\t\t\t}\n\n\t\t\t\t// 构建传输层","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-boot-starters/spring-ai-alibaba-starter-config-nacos/src/main/java/com/alibaba/cloud/ai/agent/nacos/tools/NacosMcpGatewayToolCallback.java#L475-L511","documentation":"To invoke a remote MCP tool over SSE/streamable HTTP, the gateway must know the actual MCP tool name. It derives it from toolDefinition.name(), which normally follows the pattern 'serverName_tools_toolName'. If the definition name is null or empty the extraction is impossible, so handleMcpStreamProtocol throws a RuntimeException.","triggerScenarios":"call() -> handleMcpStreamProtocol where this.toolDefinition.name() returns null or \"\" — e.g. the callback was built with a ToolDefinition lacking a name, or the name was blanked when wrapping/renaming the callback.","commonSituations":"Programmatic ToolDefinition construction that omitted .name(...); a wrapper/proxy callback that replaced the original definition with an unnamed one; data corruption in tool metadata synced from Nacos.","solutions":["Ensure the ToolDefinition passed to NacosMcpGatewayToolCallback is built with a non-empty name following the 'serverName_tools_toolName' convention.","Validate tool metadata coming from Nacos before creating callbacks; skip or repair definitions with blank names.","If wrapping the callback, delegate name() to the underlying definition instead of returning null."],"exampleFix":"// before\nToolDefinition.builder().description(desc).inputSchema(schema).build(); // no name\n// after\nToolDefinition.builder().name(serverName + \"_tools_\" + toolName).description(desc).inputSchema(schema).build();","handlingStrategy":"validation","validationCode":"String name = toolDefinition.name();\nif (name == null || name.isEmpty()) {\n    throw new IllegalArgumentException(\"ToolDefinition must have a non-empty name before gateway registration\");\n}","typeGuard":"if (toolDefinition == null || toolDefinition.name() == null || toolDefinition.name().isBlank()) { /* reject */ }","tryCatchPattern":"try { return callback.call(args); }\ncatch (RuntimeException e) {\n    if (\"Tool definition name is not available\".equals(e.getMessage())) { log.error(\"misconfigured tool definition\"); }\n    throw e;\n}","preventionTips":["Follow the 'serverName_tools_toolName' naming convention for gateway tools","Never wrap callbacks with definitions that drop the name","Validate definitions at registration time, not call time"],"tags":["nacos","mcp","tool-definition","missing-name"],"backgroundTag":"empty-required-field","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}