{"record":{"id":"6291e31479837165","repo":"different-ai/openwork","slug":"protocol-url-protocol-is-not-allowed","errorCode":null,"errorMessage":"protocol \"${url.protocol}\" is not allowed","messagePattern":"protocol \"(.+?)\" is not allowed","errorType":"exception","errorClass":"LocalManagedMcpPrivateUrlError","httpStatus":null,"severity":"error","filePath":"apps/server/src/local-managed-mcp-url-guard.ts","lineNumber":109,"sourceCode":"  return first === 0x2002 && isPrivateIpv4(embeddedIpv4(words, 1));\n}\n\nexport function isLocalManagedMcpPrivateAddress(address: string): boolean {\n  const version = isIP(address);\n  if (version === 4) return isPrivateIpv4(address);\n  if (version === 6) return isPrivateIpv6(address);\n  return true;\n}\n\nfunction parseHttpUrl(rawUrl: string): URL {\n  let url: URL;\n  try {\n    url = new URL(rawUrl);\n  } catch {\n    throw new LocalManagedMcpPrivateUrlError(rawUrl, \"not a valid URL\");\n  }\n  if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n    throw new LocalManagedMcpPrivateUrlError(rawUrl, `protocol \"${url.protocol}\" is not allowed`);\n  }\n  if (url.username || url.password) {\n    throw new LocalManagedMcpPrivateUrlError(rawUrl, \"embedded URL credentials are not allowed\");\n  }\n  return url;\n}\n\nfunction allowPrivateUrls(): boolean {\n  return process.env.OPENWORK_DEV_MODE === \"1\" || process.env.OPENWORK_ALLOW_PRIVATE_MCP_URLS === \"1\";\n}\n\ntype ResolveAddresses = (hostname: string, options: LookupAllOptions) => Promise<LookupAddress[]>;\n\nconst resolveAddresses: ResolveAddresses = (hostname, options) => lookup(hostname, options);\n\nfunction validateResolvedAddresses(hostname: string, addresses: LookupAddress[]): void {\n  if (addresses.length === 0) {\n    throw new LocalManagedMcpPrivateUrlError(`https://${hostname}/`, \"the hostname does not resolve\");","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/local-managed-mcp-url-guard.ts#L91-L127","documentation":"LocalManagedMcpPrivateUrlError thrown by parseHttpUrl when a configured local managed MCP server URL uses a scheme other than http: or https:. The guard only permits HTTP(S) because it must fetch and validate the URL; schemes like file:, ws:, or ftp: are rejected before any network work.","triggerScenarios":"Registering/starting a local managed MCP server whose url field is e.g. \"file:///path\", \"ws://host\", \"localhost:8080\" (URL parses protocol as \"localhost:\"), or a URL with trailing junk that yields an odd protocol.","commonSituations":"Typo like \"localhost:3000\" without the http:// scheme (URL() parses \"localhost:\" as the protocol); copying a WebSocket URL into an HTTP config; using file:// paths where an HTTP server URL is expected.","solutions":["Prefix the URL with the scheme: \"http://localhost:3000\" instead of \"localhost:3000\"","Use https:// for remote servers over the public internet","Replace ws:// with its HTTP(S) equivalent endpoint if the server exposes one","Print/inspect the raw url in the error to spot the missing or wrong scheme"],"exampleFix":"// before\n{ \"mcpServers\": { \"tools\": { \"url\": \"localhost:8080\" } } }\n// after\n{ \"mcpServers\": { \"tools\": { \"url\": \"http://localhost:8080\" } } }","handlingStrategy":"validation","validationCode":"function assertHttpUrl(raw: string): URL {\n  const u = new URL(raw);\n  if (u.protocol !== \"http:\" && u.protocol !== \"https:\") throw new Error(`MCP url must start with http:// or https:// — got \"${u.protocol}\"`);\n  return u;\n}","typeGuard":"function isHttpUrl(raw: string): boolean {\n  try { const u = new URL(raw); return u.protocol === \"http:\" || u.protocol === \"https:\"; } catch { return false; }\n}","tryCatchPattern":"try {\n  await mcp.addServer({ url: rawUrl });\n} catch (e) {\n  if (e instanceof LocalManagedMcpPrivateUrlError && e.message.includes(\"not allowed\")) {\n    throw new Error(`fix scheme: use http://${rawUrl} or https://... (got: ${rawUrl})`);\n  } else throw e;\n}","preventionTips":["Always include the scheme: \"http://localhost:3000\", never \"localhost:3000\"","Validate configured URLs with new URL() + protocol check at config-load time","Don't paste ws:// or file:// URLs into HTTP server URL fields"],"tags":["url","validation","mcp","config"],"backgroundTag":"unsupported-url-protocol","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}