{"record":{"id":"650ca66f0d1092ad","repo":"github/copilot-sdk","slug":"invalid-mcp-tool-name-must-not-be-null-or-empty","errorCode":null,"errorMessage":"Invalid mcp tool name: must not be null or empty. (template: Invalid <kind> tool name: must not be null or empty.)","messagePattern":"Invalid mcp tool name: must not be null or empty\\. \\(template: Invalid <kind> tool name: must not be null or empty\\.\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/rpc/ToolSet.java","lineNumber":112,"sourceCode":"     * server.\n     *\n     * @param toolName\n     *            the runtime's canonical wire name for the MCP tool (e.g.\n     *            {@code \"github-list_issues\"}), or {@code \"*\"} to match all MCP\n     *            tools from any server\n     * @return this {@code ToolSet} for chaining\n     * @throws IllegalArgumentException\n     *             if toolName is null, empty, or contains invalid characters\n     */\n    public ToolSet addMcp(String toolName) {\n        validateName(\"mcp\", toolName);\n        add(\"mcp:\" + toolName);\n        return this;\n    }\n\n    private static void validateName(String kind, String name) {\n        if (name == null || name.isEmpty()) {\n            throw new IllegalArgumentException(\"Invalid \" + kind + \" tool name: must not be null or empty.\");\n        }\n        if (\"*\".equals(name)) {\n            return;\n        }\n        if (!VALID_TOOL_NAME.matcher(name).matches()) {\n            throw new IllegalArgumentException(\"Invalid \" + kind + \" tool name '\" + name\n                    + \"': tool names must match /^[a-zA-Z0-9_-]+$/ or be the wildcard '*'.\");\n        }\n    }\n}\n","sourceCodeStart":94,"sourceCodeEnd":123,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/rpc/ToolSet.java#L94-L123","documentation":"ToolSet.validateName enforces that every tool name added via addBuiltIn/addCustom/addMcp is non-null and non-empty. When a null or empty name is passed (here for kind \"mcp\"), an IllegalArgumentException with this templated message is thrown before any entry is added to the set.","triggerScenarios":"Calling toolSet.addMcp(null) or addMcp(\"\") — usually a variable holding the server/tool name that is null or empty, or a missing config value for the MCP server name.","commonSituations":"MCP server names read from config/env that is unset; string splitting producing empty tokens; optional tool names defaulted to null instead of being skipped.","solutions":["Pass a non-empty tool name string to addMcp (and addBuiltIn/addCustom).","Validate/filter names before building the ToolSet, skipping entries with blank names.","Fix the configuration/env source supplying the MCP server name so it is populated."],"exampleFix":"// before\nString name = config.get(\"mcp.tool\"); // null\nset.addMcp(name);\n\n// after\nString name = config.get(\"mcp.tool\");\nif (name != null && !name.isEmpty()) set.addMcp(name);","handlingStrategy":"validation","validationCode":"if (name == null || name.isEmpty()) throw new IllegalArgumentException(\"mcp tool name required\");\nset.addMcp(name);","typeGuard":"static boolean validToolName(String n) { return n != null && !n.isEmpty(); }","tryCatchPattern":"try { set.addMcp(name); } catch (IllegalArgumentException e) {\n  log.error(\"skipping invalid tool name: {}\", e.getMessage());\n}","preventionTips":["Validate/trim MCP server names when loading configuration.","Skip (with a log) config entries whose names are blank instead of passing them through.","Default optional names to explicit sentinel values, not null/empty."],"tags":["java","validation","toolset","mcp"],"backgroundTag":"empty-required-field","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}