n8n-io/n8n · warning · McpToolNameValidationError
MCP tool "${name}" from ${source} has an invalid name
Error message
MCP tool "${name}" from ${source} has an invalid name What it means
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.
Source
Thrown at packages/@n8n/instance-ai/src/agent/mcp-tool-name-validation.ts:38
export function isSafeMcpIdentifierName(name: string): boolean {
const normalizedName = name.normalize('NFKC');
return (
normalizedName === name &&
MCP_TOOL_NAME_PATTERN.test(name) &&
isSafeObjectKey(normalizedName.toLowerCase())
);
}
export function normalizeMcpToolName(name: string): string {
return name
.normalize('NFKC')
.toLowerCase()
.replace(/[^a-z0-9]/g, '');
}
export function validateMcpToolName(name: string, source: string): string {
if (!isSafeMcpIdentifierName(name)) {
throw new McpToolNameValidationError(
`MCP tool "${name}" from ${source} has an invalid name`,
name,
source,
);
}
return normalizeMcpToolName(name);
}
export function createClaimedToolNames(names: Iterable<string>): Map<string, string> {
const claimed = new Map<string, string>();
for (const name of names) {
claimed.set(normalizeMcpToolName(name), name);
}
return claimed;
}
export function addSafeMcpTools(
target: McpToolRegistry,View on GitHub (pinned to 5ac6606e81)
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).
Example fix
// before — server exposes a tool with a space
{ name: 'search items', ... }
// after — alphanumerics + underscore/hyphen only
{ name: 'search_items', ... } Defensive patterns
Strategy: validation
Validate before calling
import { isSafeMcpIdentifierName } from './mcp-tool-name-validation';
function assertToolNamesValid(tools: { name: string }[], source: string): void {
for (const t of tools) {
if (!isSafeMcpIdentifierName(t.name)) {
throw new Error(`tool ${t.name} from ${source} has an invalid name; rename to match /^[A-Za-z][A-Za-z0-9_-]{0,63}$/`);
}
}
} Type guard
import { isSafeMcpIdentifierName } from './mcp-tool-name-validation';
function isValidMcpToolName(name: string): boolean {
return isSafeMcpIdentifierName(name);
} Try / catch
import { McpToolNameValidationError } from './mcp-tool-name-validation';
try {
validateMcpToolName(name, source);
} catch (e) {
if (e instanceof McpToolNameValidationError) {
// warn and skip this tool, or rename at the integration boundary
return;
}
throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- MCP tool "${name}" from ${options.source} conflicts with "${
- Deferred tool name "${tool.name}" is reserved
- Duplicate deferred tool name "${tool.name}"
- Invalid delegate sub-agent tool name "${name}": must start w
- Sub-agent task name must contain at least one alphanumeric c
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/e3cb221690c4d4c2.
Report an issue: GitHub.