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

  1. Rename the tool on the MCP server to match /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.
  2. If renaming is impossible, wrap/alias the tool name at the integration boundary before validation.
  3. 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

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


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/e3cb221690c4d4c2. Report an issue: GitHub.