{"record":{"id":"c9f55d57bbefd4d3","repo":"nanocoai/nanoclaw","slug":"type-must-be-stdio-http-or-streamable-http","errorCode":null,"errorMessage":"type must be \"stdio\", \"http\", or \"streamable-http\"","messagePattern":"type must be \"stdio\", \"http\", or \"streamable-http\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/container-config.ts","lineNumber":136,"sourceCode":"const CWD_FORM_RE = /^(?:\\.\\/|\\$\\{PLUGIN_ROOT\\}(?:\\/|$)|\\$\\{PLUGIN_DATA\\}(?:\\/|$))/;\n\n/**\n * 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) {","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/container-config.ts#L118-L154","documentation":"parseMcpServerConfig requires a declared transport type to be one of stdio, http, or streamable-http; anything else (e.g. 'websocket', 'ws', typo'd 'http2') throws. Absence of type is allowed (inferred from url/command presence).","triggerScenarios":"An MCP server entry with \"type\": \"websocket\" or any string other than stdio|http|streamable-http in container config or add-mcp-server input.","commonSituations":"Speculative transport values copied from other tooling, or typos like 'strdio'.","solutions":["Set type to \"stdio\" (with command) or \"http\"/\"streamable-http\" (with url)","Or omit type entirely and provide either url or command for inference"],"exampleFix":"// before\n{\"type\": \"websocket\", \"url\": \"https://mcp.example.com\"}\n// after\n{\"type\": \"http\", \"url\": \"https://mcp.example.com/mcp\"}","handlingStrategy":"type-guard","validationCode":"const SUPPORTED = new Set(['stdio','http','streamable-http']);\nif (entry.type !== undefined && !SUPPORTED.has(entry.type)) throw new Error('unsupported type');","typeGuard":"function isMcpTransport(t: unknown): t is 'stdio' | 'http' | 'streamable-http' {\n  return t === undefined || t === 'stdio' || t === 'http' || t === 'streamable-http';\n}","tryCatchPattern":null,"preventionTips":["Omit type and rely on url/command inference when unsure","Copy transport spellings exactly from `ncl groups config add-mcp-server` docs"],"tags":["mcp","transport","validation","container-config"],"backgroundTag":"unsupported-transport","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}