n8n-io/n8n · error · UserError
MCP server "${server.name}": invalid URL "${server.url}"
Error message
MCP server "${server.name}": invalid URL "${server.url}" What it means
Thrown by McpClientManager.validateConfigs when a configured MCP server has a non-empty url that cannot be parsed by the URL constructor. This is a UserError — the user supplied an invalid configuration. The check is the first of three (parseability, http(s) protocol, SSRF safety); only the parse step throws this specific message.
Source
Thrown at packages/@n8n/instance-ai/src/mcp/mcp-client-manager.ts:232
})();
inFlight.set(key, promise);
try {
return await promise;
} finally {
inFlight.delete(key);
}
}
private async validateConfigs(configs: McpServerConfig[]): Promise<void> {
for (const server of configs) {
if (!server.url) continue;
let parsed: URL;
try {
parsed = new URL(server.url);
} catch {
throw new UserError(`MCP server "${server.name}": invalid URL "${server.url}"`);
}
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
throw new UserError(
`MCP server "${server.name}": only http(s) URLs are allowed, got "${parsed.protocol}"`,
);
}
if (this.ssrfValidator) {
const result = await this.ssrfValidator.validateUrl(server.url);
if (!result.ok) {
throw new UserError(
`MCP server "${server.name}": URL blocked by SSRF policy - ${result.error.message}`,
);
}
}
}
}View on GitHub (pinned to 5ac6606e81)
Solutions
- Provide an absolute URL with an explicit scheme, e.g. 'https://mcp.example.com/sse'.
- If using a local server, prefix 'http://' (e.g. 'http://localhost:3000').
- Validate the URL string with `new URL(server.url)` in a scratch script to reproduce the exact parse failure.
Example fix
// before — missing scheme
{ name: 'my-mcp', url: 'mcp.local:3000/sse' }
// after — absolute http(s) URL
{ name: 'my-mcp', url: 'http://mcp.local:3000/sse' } Defensive patterns
Strategy: validation
Validate before calling
function isValidMcpUrl(url: string): boolean {
try {
const parsed = new URL(url);
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
} catch {
return false;
}
}
for (const server of configs) {
if (server.url && !isValidMcpUrl(server.url)) {
throw new Error(`server ${server.name} has an invalid MCP url: ${server.url}`);
}
} Type guard
function isParseableHttpUrl(url: string): boolean {
try {
const p = new URL(url);
return p.protocol === 'http:' || p.protocol === 'https:';
} catch {
return false;
}
} Try / catch
import { UserError } from 'n8n-workflow';
try {
await manager.validateConfigs(configs);
} catch (e) {
if (e instanceof UserError && /invalid URL/.test(e.message)) {
// surface the offending server config to the user; do not retry as-is
}
throw e;
} Prevention
- Always include the scheme (http:// or https://) in MCP server URLs.
- Validate URLs in the config form before persisting.
- Reject empty/bare-hostname URLs at the input boundary.
When it happens
Trigger: server.url is a relative path, a bare hostname without scheme, contains illegal characters, has malformed port, or is otherwise not a valid absolute URL string.
Common situations: User enters 'localhost:3000' (missing scheme) instead of 'http://localhost:3000'; a trailing slash in an unexpected position; copy-paste introduced a stray character; env-var templating left a placeholder unresolved.
Related errors
- Invalid Qdrant URL: ${url}. Please provide a valid URL with
- MCP tool name collision — the following tool names resolve t
- Model ID is required
- Invalid delegate sub-agent tool name "${name}": must start w
- ${toolName} requires resumeSubAgent and cancelSubAgent to be
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/9b4dd01f67dd8ed1.
Report an issue: GitHub.