{"record":{"id":"86dd8bb6dab8b577","repo":"BigPizzaV3/CodexPlusPlus","slug":"json-mcp-config","errorCode":null,"errorMessage":"JSON 里没有可导入的 MCP 服务器","messagePattern":"JSON 里没有可导入的 MCP 服务器","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/codex-plus-core/src/mcp_config.rs","lineNumber":298,"sourceCode":"\n    if servers.is_empty() {\n        anyhow::bail!(\"JSON 里没有找到任何 MCP 服务器\");\n    }\n\n    let mut import = McpJsonImport::default();\n    for (id, config) in servers {\n        let Value::Object(config) = config else {\n            import.warnings.push(format!(\"已跳过 {id}：配置不是对象\"));\n            continue;\n        };\n        match json_server_to_toml(&id, &config, &mut import.warnings) {\n            Ok(toml_body) => import.entries.push(McpJsonEntry { id, toml_body }),\n            Err(error) => import.warnings.push(format!(\"已跳过 {id}：{error}\")),\n        }\n    }\n\n    if import.entries.is_empty() {\n        anyhow::bail!(\"JSON 里没有可导入的 MCP 服务器\");\n    }\n    Ok(import)\n}\n\n/// 只有 command 或 url、且没有嵌套的 server 对象，就当成单个 server。\nfn looks_like_single_server(root: &Map<String, Value>) -> bool {\n    (root.contains_key(\"command\") || root.contains_key(\"url\"))\n        && !root.values().any(|value| {\n            value\n                .as_object()\n                .map(|obj| obj.contains_key(\"command\") || obj.contains_key(\"url\"))\n                .unwrap_or(false)\n        })\n}\n\nfn json_server_to_toml(\n    id: &str,\n    config: &Map<String, Value>,","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/crates/codex-plus-core/src/mcp_config.rs#L280-L316","documentation":"parse_mcp_servers_json converts each server entry to a TOML body via json_server_to_toml; entries that fail conversion are skipped and recorded as warnings. If every entry was skipped (import.entries is empty), the function bails because a no-op import is meaningless. Note the per-entry warnings still explain why each entry failed.","triggerScenarios":"All entries in the JSON failed json_server_to_toml (e.g. each missing command/url, or malformed nested fields), so zero entries survive the loop.","commonSituations":"Importing a config whose servers all use unsupported/invalid fields; every entry has neither command nor url; an exporter produced entries incompatible with this tool's schema.","solutions":["Read the returned warnings via the error chain/warnings to see why each entry was skipped (commonly '缺少 command 或 url').","Add a command (stdio) or url (http) field to each server entry.","Import a subset: fix or remove broken entries so at least one valid server remains.","Validate one entry manually with json_server_to_toml before batch import."],"exampleFix":"// before\n{\"mcpServers\":{\"a\":{\"enabled\":false}}}\n// after\n{\"mcpServers\":{\"a\":{\"command\":\"npx\",\"args\":[\"-y\",\"server\"]}}}","handlingStrategy":"validation","validationCode":"function allEntriesConvertible(root) {\n  const map = root.mcpServers ?? root.servers ?? root;\n  return Object.values(map).every(c => typeof c.command === 'string' || typeof c.url === 'string');\n}","typeGuard":null,"tryCatchPattern":"match parse_mcp_servers_json(&text) {\n    Ok(import) => apply(import),\n    Err(e) if e.to_string().contains(\"没有可导入\") => ui.show_warnings(collected_warnings),\n    Err(e) => return Err(e),\n}","preventionTips":["Validate each entry has command or url before batch import","Import incrementally: one server first, then the rest","Surface per-entry warnings so users see why entries were skipped","Normalize foreign key names (cmd->command, endpoint->url) before import"],"tags":["json","mcp","import","empty"],"backgroundTag":"empty-result-set","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}