{"record":{"id":"ae6b52a0e15a1a55","repo":"farion1231/cc-switch","slug":"stdio-mcp-command","errorCode":null,"errorMessage":"stdio 类型的 MCP 服务器必须包含 command 字段","messagePattern":"stdio 类型的 MCP 服务器必须包含 command 字段","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/utils/tomlUtils.ts","lineNumber":113,"sourceCode":"};\n\n/**\n * 规范化服务器配置对象为 McpServer 格式\n * 保留所有字段（包括扩展字段如 timeout_ms）\n */\nfunction normalizeServerConfig(config: any): McpServerSpec {\n  if (!config || typeof config !== \"object\") {\n    throw new Error(\"服务器配置必须是对象\");\n  }\n\n  const type = (config.type as string) || \"stdio\";\n\n  // 已知字段列表（用于后续排除）\n  const knownFields = new Set<string>();\n\n  if (type === \"stdio\") {\n    if (!config.command || typeof config.command !== \"string\") {\n      throw new Error(\"stdio 类型的 MCP 服务器必须包含 command 字段\");\n    }\n\n    const server: McpServerSpec = {\n      type: \"stdio\",\n      command: config.command,\n    };\n    knownFields.add(\"type\");\n    knownFields.add(\"command\");\n\n    // 可选字段\n    if (config.args && Array.isArray(config.args)) {\n      server.args = config.args.map((arg: any) => String(arg));\n      knownFields.add(\"args\");\n    }\n    if (config.env && typeof config.env === \"object\") {\n      const env: Record<string, string> = {};\n      for (const [k, v] of Object.entries(config.env)) {\n        env[k] = String(v);","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/farion1231/cc-switch/blob/0b5da510168914b251481654a568c3ffacd62cf4/src/utils/tomlUtils.ts#L95-L131","documentation":"For type stdio — which is also the default when the type key is omitted — normalizeServerConfig requires a command field that is a non-empty string ('stdio 类型的 MCP 服务器必须包含 command 字段'). stdio servers launch a local process, so without command there is nothing to execute. The check runs before args/env and unknown-field copying.","triggerScenarios":"Pasting a block like 'type = \"stdio\"' with only args/env, or where command is missing, empty, or a non-string (number/table).","commonSituations":"A remote-style (url-based) config pasted while type still says stdio; the executable landed in args when the command line was split wrongly; key typos like cmd or Command.","solutions":["Add command = \"<executable>\" to the stdio server block","If the server is actually remote, set type = \"http\" or \"sse\" and provide url instead","Check spelling and case — the parser only accepts a lowercase command key"],"exampleFix":"# before\n[mcp_servers.fetch]\ntype = \"stdio\"\nargs = [\"mcp-server-fetch\"]\n\n# after\n[mcp_servers.fetch]\ntype = \"stdio\"\ncommand = \"uvx\"\nargs = [\"mcp-server-fetch\"]","handlingStrategy":"validation","validationCode":"const parsed = parseToml(normalizeTomlText(tomlText));\nconst first = firstServerOf(parsed);\nconst type = (first?.type as string) || 'stdio';\nif (type === 'stdio' && (typeof first?.command !== 'string' || !first.command)) {\n  // show \"stdio server needs a command\" before importing\n}","typeGuard":null,"tryCatchPattern":"try {\n  const server = tomlToMcpServer(tomlText);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('必须包含 command 字段')) {\n    // highlight the command field guidance\n  } else {\n    throw error;\n  }\n}","preventionTips":["For stdio servers always write command = '<executable>' first","Switch type to http/sse with a url for remote servers","Use exactly the lowercase key 'command'"],"tags":["toml","mcp","stdio","required-field"],"backgroundTag":"missing-required-argument","analyzedSha":"0b5da510168914b251481654a568c3ffacd62cf4","analyzedAt":"2026-08-20T14:29:00.113Z","contentChangedAt":"2026-08-20T14:29:00.113Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}