diff --git a/src-tauri/src/mcp.rs b/src-tauri/src/mcp.rs index 83329577..2b05c183 100644 --- a/src-tauri/src/mcp.rs +++ b/src-tauri/src/mcp.rs @@ -1105,7 +1105,8 @@ fn json_value_to_toml_item(value: &Value, field_name: &str) -> Option Result { @@ -1113,7 +1114,11 @@ fn json_server_to_toml_table(spec: &Value) -> Result let mut t = Table::new(); let typ = spec.get("type").and_then(|v| v.as_str()).unwrap_or("stdio"); - t["type"] = toml_edit::value(typ); + // Codex 的 `[mcp_servers.]` 不认识 `type` 字段:普通模式下会告警 + // "is ignored",`--strict-config` 下直接校验失败。传输方式由 Codex 根据 + // `command`(stdio)或 `url`(streamable HTTP)自行推断,导入侧 + // (`import_from_codex`)在缺少 `type` 时也按同样规则推断,因此这里不写出 + // `type`,只用它来决定写哪些核心字段。 // 定义核心字段(已在下方处理,跳过通用转换) let core_fields = match typ { @@ -1813,6 +1818,38 @@ mod codex_mcp_tests { assert_eq!(doc.to_string(), "mcp_servers = 42\n"); } + #[test] + fn codex_toml_omits_unsupported_type_field() { + // Codex rejects `mcp_servers..type` under `--strict-config` and warns + // about it otherwise; the transport is inferred from `command` / `url`. + for (spec, expect_command, expect_url) in [ + ( + json!({ "type": "stdio", "command": "npx", "args": ["-y", "x"] }), + true, + false, + ), + (json!({ "command": "npx" }), true, false), + ( + json!({ "type": "http", "url": "https://mcp.example.com/mcp" }), + false, + true, + ), + ( + json!({ "type": "sse", "url": "https://mcp.example.com/sse" }), + false, + true, + ), + ] { + let table = json_server_to_toml_table(&spec).expect("server table"); + assert!( + table.get("type").is_none(), + "`type` must not be written to Codex TOML for {spec}" + ); + assert_eq!(table.contains_key("command"), expect_command, "{spec}"); + assert_eq!(table.contains_key("url"), expect_url, "{spec}"); + } + } + #[test] fn http_headers_are_only_written_to_codex_http_headers() { let table = json_server_to_toml_table(&json!({