n8n-io/n8n · error · Error
MCP server "${cfg.name}": provide either "url" or "command",
Error message
MCP server "${cfg.name}": provide either "url" or "command", not both What it means
Thrown by the McpClient constructor when a McpServerConfig sets BOTH url and command. The MCP SDK cannot decide which transport to start; exactly one must be present.
Source
Thrown at packages/@n8n/agents/src/sdk/mcp-client.ts:71
* Per-server connection failures recorded during the last `listTools()`.
* Tools from these servers were skipped; the run continues with the
* remaining servers' tools. Read via `getConnectionFailures()`.
*/
private connectionFailures: McpConnectionFailedEvent[] = [];
/**
* @param configs - Server configurations. Each must have either `url` or `command`.
* Duplicate names within the list are rejected.
*/
constructor(configs: McpServerConfig[]) {
for (const cfg of configs) {
if (!cfg.url && !cfg.command) {
throw new Error(
`MCP server "${cfg.name}": exactly one of "url" or "command" must be provided`,
);
}
if (cfg.url && cfg.command) {
throw new Error(`MCP server "${cfg.name}": provide either "url" or "command", not both`);
}
}
const seen = new Set<string>();
for (const cfg of configs) {
if (seen.has(cfg.name)) {
throw new Error(`MCP server name "${cfg.name}" is already registered`);
}
seen.add(cfg.name);
}
this.configs = configs;
this.connections = configs.map((cfg) => new McpConnection(cfg));
}
/**
* Returns the names of all configured MCP servers. Does NOT require a
* network connection — safe to call before `listTools()` or `connect()`.View on GitHub (pinned to 5ac6606e81)
Solutions
- Delete one of url or command so only the intended transport remains.
- Branch your config builder on a transport discriminator before constructing the object.
- Assert with a unit test that each emitted config has url XOR command.
Example fix
// before
new McpClient([{ name: 's', url: 'http://x', command: 'npx' }]);
// after
new McpClient([{ name: 's', url: 'http://x', transport: 'streamableHttp' }]); Defensive patterns
Strategy: validation
Validate before calling
function assertExactlyOneTransport(c: { url?: string; command?: string }) {
if (c.url && c.command) {
throw new Error('Provide either url or command, not both');
}
} Type guard
function hasSingleTransport(c: { url?: string; command?: string }): boolean {
return Boolean(c.url) !== Boolean(c.command);
} Prevention
- Branch config construction on a 'transport: "stdio" | "sse" | "streamableHttp"' discriminator.
- Reject ambiguous configs in CI lint rather than at runtime.
When it happens
Trigger: Passing { name: 'foo', url: 'http://x', command: 'npx' } — the runtime cannot pick a transport.
Common situations: Copy-pasting a config block and forgetting to delete the unused transport field; templating configs where both fields get filled conditionally; YAML/JSON merge that leaves both keys.
Related errors
- MCP server "${cfg.name}": exactly one of "url" or "command"
- MCP server name "${cfg.name}" is already registered
- Unknown agents module: "${moduleName}". ${validTokens ? `Val
- Database type currently not supported
- Failed to parse ${label} at ${path}: ${msg}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/6f05cda04de8c1c0.
Report an issue: GitHub.