{"record":{"id":"e3cb221690c4d4c2","repo":"n8n-io/n8n","slug":"mcp-tool-name-from-source-has-an-invalid-n","errorCode":null,"errorMessage":"MCP tool \"${name}\" from ${source} has an invalid name","messagePattern":"MCP tool \"(.+?)\" from (.+?) has an invalid name","errorType":"validation","errorClass":"McpToolNameValidationError","httpStatus":null,"severity":"warning","filePath":"packages/@n8n/instance-ai/src/agent/mcp-tool-name-validation.ts","lineNumber":38,"sourceCode":"export function isSafeMcpIdentifierName(name: string): boolean {\n\tconst normalizedName = name.normalize('NFKC');\n\treturn (\n\t\tnormalizedName === name &&\n\t\tMCP_TOOL_NAME_PATTERN.test(name) &&\n\t\tisSafeObjectKey(normalizedName.toLowerCase())\n\t);\n}\n\nexport function normalizeMcpToolName(name: string): string {\n\treturn name\n\t\t.normalize('NFKC')\n\t\t.toLowerCase()\n\t\t.replace(/[^a-z0-9]/g, '');\n}\n\nexport function validateMcpToolName(name: string, source: string): string {\n\tif (!isSafeMcpIdentifierName(name)) {\n\t\tthrow new McpToolNameValidationError(\n\t\t\t`MCP tool \"${name}\" from ${source} has an invalid name`,\n\t\t\tname,\n\t\t\tsource,\n\t\t);\n\t}\n\treturn normalizeMcpToolName(name);\n}\n\nexport function createClaimedToolNames(names: Iterable<string>): Map<string, string> {\n\tconst claimed = new Map<string, string>();\n\tfor (const name of names) {\n\t\tclaimed.set(normalizeMcpToolName(name), name);\n\t}\n\treturn claimed;\n}\n\nexport function addSafeMcpTools(\n\ttarget: McpToolRegistry,","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/instance-ai/src/agent/mcp-tool-name-validation.ts#L20-L56","documentation":"Thrown by validateMcpToolName when an MCP tool name fails isSafeMcpIdentifierName. A valid name must: equal its own NFKC-normalized form, match /^[A-Za-z][A-Za-z0-9_-]{0,63}$/ (leading alpha, up to 64 chars of alphanumerics/underscore/hyphen), and be a safe object key once lowercased. The error names the offending tool and the source server so the operator can locate it.","triggerScenarios":"A tool name starting with a digit; containing characters outside [A-Za-z0-9_-] (spaces, dots, unicode); longer than 64 chars; a name that changes under NFKC normalization (e.g. ligatures); a name that is a reserved/unsafe object key.","commonSituations":"A third-party MCP server exposing tools with names designed for a different casing/character convention; a server returning display names with spaces; unicode look-alike characters that normalize differently.","solutions":["Rename the tool on the MCP server to match /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.","If renaming is impossible, wrap/alias the tool name at the integration boundary before validation.","Confirm the name is stable under NFKC normalization (avoid ligatures/combining marks)."],"exampleFix":"// before — server exposes a tool with a space\n{ name: 'search items', ... }\n\n// after — alphanumerics + underscore/hyphen only\n{ name: 'search_items', ... }","handlingStrategy":"validation","validationCode":"import { isSafeMcpIdentifierName } from './mcp-tool-name-validation';\n\nfunction assertToolNamesValid(tools: { name: string }[], source: string): void {\n  for (const t of tools) {\n    if (!isSafeMcpIdentifierName(t.name)) {\n      throw new Error(`tool ${t.name} from ${source} has an invalid name; rename to match /^[A-Za-z][A-Za-z0-9_-]{0,63}$/`);\n    }\n  }\n}","typeGuard":"import { isSafeMcpIdentifierName } from './mcp-tool-name-validation';\n\nfunction isValidMcpToolName(name: string): boolean {\n  return isSafeMcpIdentifierName(name);\n}","tryCatchPattern":"import { McpToolNameValidationError } from './mcp-tool-name-validation';\n\ntry {\n  validateMcpToolName(name, source);\n} catch (e) {\n  if (e instanceof McpToolNameValidationError) {\n    // warn and skip this tool, or rename at the integration boundary\n    return;\n  }\n  throw e;\n}","preventionTips":["Restrict tool names to /^[A-Za-z][A-Za-z0-9_-]{0,63}$/ at the server source.","Avoid unicode/ligatures in tool names — they may shift under NFKC.","Unit-test third-party MCP server tool names against the validator in CI."],"tags":["mcp","validation","naming","tool-registry"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}