{"record":{"id":"e16fba33b590ab70","repo":"nanocoai/nanoclaw","slug":"type-http-requires-url","errorCode":null,"errorMessage":"type \"http\" requires url","messagePattern":"type \"http\" requires url","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/container-config.ts","lineNumber":139,"sourceCode":" * Parse one CLI or approval payload into the persisted MCP config shape.\n * Duplicated in container/agent-runner/src/mcp-tools/self-mod.ts\n * (parseMcpServerInput) — no shared modules across the host/container\n * boundary; keep the two in sync.\n */\nexport function parseMcpServerConfig(input: Record<string, unknown>): McpServerConfig {\n  const command = typeof input.command === 'string' && input.command.trim() ? input.command : undefined;\n  const url = typeof input.url === 'string' && input.url.trim() ? input.url.trim() : undefined;\n\n  // A declared transport is honored; absence keeps the legacy CLI inference\n  // (url → http, command → stdio). \"streamable-http\" is the Agent Plugins\n  // spelling of the internal \"http\".\n  const type = input.type === 'streamable-http' ? 'http' : input.type;\n  if (type === 'sse') throw new Error('unsupported transport \"sse\"');\n  if (type !== undefined && type !== 'stdio' && type !== 'http') {\n    throw new Error('type must be \"stdio\", \"http\", or \"streamable-http\"');\n  }\n  if (type === 'stdio' && !command) throw new Error('type \"stdio\" requires command');\n  if (type === 'http' && !url) throw new Error('type \"http\" requires url');\n\n  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);","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/container-config.ts#L121-L157","documentation":"Thrown by parseMcpServerConfig when type is \"http\" (or \"streamable-http\") but no `url` is provided. HTTP-transport MCP servers are addressed by endpoint URL, so it is required and validated eagerly.","triggerScenarios":"Configuring an MCP server entry with type http/streamable-http and only a command, or with neither command nor url; applies to ncl add-mcp-server, the self-mod tool, and direct parseMcpServerConfig calls.","commonSituations":"Converting a stdio entry to http but leaving `command` in place; typo like \"uri\" instead of \"url\"; expecting the SDK to derive the URL from a name.","solutions":["Add the `url` field, e.g. {\"type\":\"http\",\"url\":\"https://mcp.example.com/mcp\"}","If the server is local, use command-based stdio transport instead","Check for misspellings of the url key in the JSON payload"],"exampleFix":"// before\n{\"type\":\"http\",\"headers\":{\"x\":\"y\"}}\n// after\n{\"type\":\"http\",\"url\":\"https://mcp.example.com/mcp\"}","handlingStrategy":"validation","validationCode":"if ((srv.type === 'http' || srv.type === 'streamable-http') && !srv.url) throw new UserError('http MCP entry needs url');","typeGuard":"function isValidHttpEntry(e: any): e is {type:'http'; url:string} {\n  return (e?.type === 'http' || e?.type === 'streamable-http') && typeof e.url === 'string';\n}","tryCatchPattern":"catch (err) { if (err.message.includes('requires url')) promptForUrl(); else throw err; }","preventionTips":["Prefer type 'http' plus explicit url; treat streamable-http as an alias","Template new entries from a working example"],"tags":["mcp","config-validation","container-config"],"backgroundTag":"required-field-missing","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}