different-ai/openwork · critical
MCP_URL_BLOCKED
MCP_URL_BLOCKED
Error message
MCP_URL_BLOCKED
What it means
MCP_URL_BLOCKED is raised when the configured MCP endpoint fails the gateway's SSRF guard, thrown as PrivateUrlError and classified as CONFIGURATION / security_blocked. The gateway deliberately refuses to call private/internal network addresses (loopback, RFC1918, link-local, metadata endpoints) from external MCP sources. It is non-retryable and owned by the organization admin since it requires either a public URL or an explicit policy change through security review.
Source
Thrown at ee/apps/den-api/src/capability-sources/external-mcp-diagnostics.ts:1201
? "Retry the capability, and reduce provider latency for this tool if it keeps running past the bounded deadline."
: "Reduce provider latency or catalog pagination so the complete MCP lifecycle finishes within the bounded deadline, then retry.",
}
}
if (error instanceof ExternalMcpResponseBodyLimitError) {
return {
phase: fallbackPhase,
category: "response_too_large",
code: "MCP_RESPONSE_BODY_LIMIT",
retryable: false,
actionOwner: "provider_admin",
operatorAction: "Reduce the provider response size, tool catalog, or event-stream payload before retrying.",
}
}
if (error instanceof PrivateUrlError) {
return {
phase: "CONFIGURATION",
category: "security_blocked",
code: "MCP_URL_BLOCKED",
retryable: false,
actionOwner: "organization_admin",
operatorAction: "Use a public HTTPS MCP URL or change the deployment's private-network policy through security review.",
}
}
if (hasForbiddenPortMessage(error)) {
return {
phase: "CONFIGURATION",
category: "unsupported_endpoint_port",
code: "MCP_FETCH_FORBIDDEN_PORT",
retryable: false,
actionOwner: "organization_admin",
operatorAction: "Use the provider's supported HTTPS MCP port or place the endpoint behind a standard HTTPS listener.",
}
}
const code = errorCode(error)
if (code) {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Use a public HTTPS MCP URL that the gateway can reach from its network.
- If internal access is genuinely required, change the deployment's private-network policy through security review to allowlist the address.
- Expose the internal MCP server via an approved public gateway/tunnel that passes the private-URL check.
Example fix
// before: private dev URL in external source config
{ "url": "http://localhost:8080/mcp" }
// after
{ "url": "https://mcp.mycompany.example.com/mcp" } Defensive patterns
Strategy: validation
Validate before calling
// pre-flight the configured URL against the private-address rules
function isPublicHttpsUrl(raw: string): boolean {
const u = new URL(raw)
if (u.protocol !== 'https:') return false
const host = u.hostname
if (host === 'localhost' || host.endsWith('.local')) return false
if (/^(10\.|127\.|192\.168\.|169\.254\.|172\.(1[6-9]|2\d|3[01])\.)/.test(host)) return false
return true
}
if (!isPublicHttpsUrl(config.url)) throw new Error('MCP URL must be public HTTPS') Type guard
function isUrlBlocked(d: { code: string }): boolean {
return d.code === 'MCP_URL_BLOCKED'
} Try / catch
try {
return await connectExternalMcp(config)
} catch (e) {
if (isUrlBlocked(e.diagnostic)) {
// non-retryable: configuration must change; do not attempt to bypass the SSRF guard
throw new Error(`blocked private MCP URL: ${config.url} — use public HTTPS or request a policy exception`)
}
throw e
} Prevention
- Only register public HTTPS URLs for external MCP sources.
- Reach internal MCP servers through an approved public gateway rather than private addresses.
- If an internal address is truly required, request a private-network policy exception through security review before configuring it.
When it happens
Trigger: Registering or invoking an external MCP capability whose URL resolves to a private address — e.g. http://localhost:8080/mcp, http://10.x.x.x/mcp, http://192.168.x.x/mcp, or a hostname that DNS-resolves to a private IP — triggering the PrivateUrlError check during request setup.
Common situations: Developers pointing the external MCP source at a local dev server; internal-only providers behind VPC addresses; DNS names that resolve to private IPs inside the deployment network; attempts to reach cloud metadata services (accidental or malicious).
Related errors
- the hostname resolves to a private or reserved address (${ad
- Attachment hostname ${hostname} resolved to a private or res
- embedded URL credentials are not allowed
- the address is private or reserved
- unsupported_transport
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/e9b8b707c74d1ba0.
Report an issue: GitHub.