{"record":{"id":"0b83803ae300b58b","repo":"n8n-io/n8n","slug":"mcp-server-name-cfg-name-is-already-registere","errorCode":null,"errorMessage":"MCP server name \"${cfg.name}\" is already registered","messagePattern":"MCP server name \"(.+?)\" is already registered","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/sdk/mcp-client.ts","lineNumber":78,"sourceCode":"\t * @param configs - Server configurations. Each must have either `url` or `command`.\n\t *   Duplicate names within the list are rejected.\n\t */\n\tconstructor(configs: McpServerConfig[]) {\n\t\tfor (const cfg of configs) {\n\t\t\tif (!cfg.url && !cfg.command) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`MCP server \"${cfg.name}\": exactly one of \"url\" or \"command\" must be provided`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (cfg.url && cfg.command) {\n\t\t\t\tthrow new Error(`MCP server \"${cfg.name}\": provide either \"url\" or \"command\", not both`);\n\t\t\t}\n\t\t}\n\n\t\tconst seen = new Set<string>();\n\t\tfor (const cfg of configs) {\n\t\t\tif (seen.has(cfg.name)) {\n\t\t\t\tthrow new Error(`MCP server name \"${cfg.name}\" is already registered`);\n\t\t\t}\n\t\t\tseen.add(cfg.name);\n\t\t}\n\n\t\tthis.configs = configs;\n\t\tthis.connections = configs.map((cfg) => new McpConnection(cfg));\n\t}\n\n\t/**\n\t * Returns the names of all configured MCP servers. Does NOT require a\n\t * network connection — safe to call before `listTools()` or `connect()`.\n\t */\n\tget serverNames(): string[] {\n\t\treturn this.configs.map((cfg) => cfg.name);\n\t}\n\n\t/**\n\t * Explicitly connect to all servers without listing tools.","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/sdk/mcp-client.ts#L60-L96","documentation":"Thrown by the McpClient constructor when two McpServerConfig entries share the same name. The name is used as a tool-name prefix and as the connection key, so duplicates would collide in the surfaced tool namespace.","triggerScenarios":"Passing an array with two entries whose .name is identical, e.g. [{ name: 'fs', ... }, { name: 'fs', ... }].","commonSituations":"Concatenating two config lists that both define a 'fs' server; loading MCP config from multiple sources without de-duplicating by name; copy-paste of a server block.","solutions":["Give each server a unique name (the name prefixes tool names, so pick something descriptive).","De-duplicate configs by name before constructing McpClient.","If you intended to replace a server, filter the older entry out before adding the new one."],"exampleFix":"// before\nnew McpClient([\n  { name: 'fs', command: 'npx', args: ['@anthropic/mcp-fs', '/a'] },\n  { name: 'fs', command: 'npx', args: ['@anthropic/mcp-fs', '/b'] },\n]);\n// after\nnew McpClient([\n  { name: 'fs-a', command: 'npx', args: ['@anthropic/mcp-fs', '/a'] },\n  { name: 'fs-b', command: 'npx', args: ['@anthropic/mcp-fs', '/b'] },\n]);","handlingStrategy":"validation","validationCode":"function assertUniqueNames(configs: { name: string }[]) {\n  const seen = new Set<string>();\n  for (const c of configs) {\n    if (seen.has(c.name)) throw new Error(`Duplicate MCP server name: ${c.name}`);\n    seen.add(c.name);\n  }\n}","typeGuard":"function mcpNamesUnique(configs: { name: string }[]): boolean {\n  return new Set(configs.map((c) => c.name)).size === configs.length;\n}","tryCatchPattern":null,"preventionTips":["De-duplicate server configs by name before constructing McpClient.","When merging config sources, namespace names by source to prevent collisions."],"tags":["mcp","config","duplicate","naming"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}