{"record":{"id":"6a7d1d95671816f1","repo":"nanocoai/nanoclaw","slug":"url-must-use-https-plain-http-is-allowed-only-for","errorCode":null,"errorMessage":"url must use HTTPS (plain HTTP is allowed only for localhost and host.docker.internal)","messagePattern":"url must use HTTPS \\(plain HTTP is allowed only for localhost and host\\.docker\\.internal\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/container-config.ts","lineNumber":159,"sourceCode":"  const instructions = input.instructions;\n  if (instructions !== undefined && typeof instructions !== 'string') {\n    throw new Error('MCP instructions must be a string');\n  }\n\n  if (url !== undefined) {\n    if (command !== undefined) throw new Error('Provide exactly one of command or url');\n    if (input.args !== undefined || input.env !== undefined || input.cwd !== undefined) {\n      throw new Error('args, env, and cwd are only valid with command');\n    }\n    let parsed: URL;\n    try {\n      parsed = new URL(url);\n    } catch (err) {\n      throw new Error('url must be a valid HTTP(S) URL', { cause: err });\n    }\n    const loopback = ['localhost', '127.0.0.1', '[::1]', 'host.docker.internal'].includes(parsed.hostname);\n    if (parsed.protocol !== 'https:' && !(parsed.protocol === 'http:' && loopback)) {\n      throw new Error('url must use HTTPS (plain HTTP is allowed only for localhost and host.docker.internal)');\n    }\n    if (parsed.username || parsed.password || parsed.hash) {\n      throw new Error('url must not contain credentials or fragments; use OneCLI for authentication');\n    }\n    for (const key of parsed.searchParams.keys()) {\n      if (SECRET_QUERY_KEY_RE.test(key.replace(CAMEL_SPLIT_RE, '$1_$2'))) {\n        throw new Error(`url query parameter \"${key}\" looks like a credential; use OneCLI for authentication`);\n      }\n    }\n    const headers = parseStringRecord(input.headers, 'headers');\n    return {\n      type: 'http',\n      url,\n      ...(headers === undefined ? {} : { headers }),\n      ...(instructions === undefined ? {} : { instructions }),\n    };\n  }\n  if (command === undefined) throw new Error('Provide exactly one of command or url');","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/container-config.ts#L141-L177","documentation":"The MCP server url parsed successfully but its protocol is not https:. Plain http is permitted only for loopback hosts (localhost, 127.0.0.1, [::1], host.docker.internal) because container-to-host traffic is the exception; everything else must be TLS-encrypted.","triggerScenarios":"An http:// url with a non-loopback hostname, e.g. http://mcp.internal.example.com:8080/mcp; also http:// with a LAN IP like 192.168.1.5.","commonSituations":"Pointing at an internal HTTP-only server on the network; dev setup moved from localhost to a LAN host; port-forwarded service without TLS.","solutions":["Use an https:// url (put the server behind TLS or a reverse proxy)","If the server runs on the Docker host, switch the hostname to host.docker.internal so plain http is allowed","For other LAN hosts, add TLS via a local proxy (e.g. caddy/nginx) and use https"],"exampleFix":"// before\n{\"url\":\"http://192.168.1.5:8080/mcp\"}\n// after\n{\"url\":\"http://host.docker.internal:8080/mcp\"}","handlingStrategy":"validation","validationCode":"const u = new URL(entry.url); const loopback = ['localhost','127.0.0.1','[::1]','host.docker.internal'].includes(u.hostname); if (u.protocol !== 'https:' && !(u.protocol === 'http:' && loopback)) throw new UserError('use https or a loopback host');","typeGuard":"function isAllowedMcpUrl(s: string): boolean { const u = new URL(s); const lo = ['localhost','127.0.0.1','[::1]','host.docker.internal'].includes(u.hostname); return u.protocol === 'https:' || (u.protocol === 'http:' && lo); }","tryCatchPattern":"catch (err) { if (err.message.includes('must use HTTPS')) suggestTlsOrLoopback(); else throw err; }","preventionTips":["Default to https for any remote MCP endpoint","Use host.docker.internal for host-local servers"],"tags":["mcp","https","security-policy","url-validation"],"backgroundTag":"insecure-protocol-rejected","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}