n8n-io/n8n · warning · McpToolNameValidationError

MCP tool " " from 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.

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.

Appendix: 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)