fix: preserve Codex tool policies when synchronizing MCP

This commit is contained in:
chenmingxuan committed 2026-10-18 20:56:06 +08:00
1 parent bdc75d0c65
commit 351b2fc905
3 files changed
+97 -12

No files matched your search

+24 -11
View File
@@ -18,6 +18,10 @@ from urllib.parse import urlsplit
ROOT = Path(__file__).resolve().parents[1]
class McpSyncValidationError(ValueError):
"""The synchronizer could not safely update an already parsed configuration."""
def launch_text(english: str, chinese: str) -> str:
return chinese if os.environ.get("ARTEMIS_LAUNCH_LANG") == "zh-CN" else english
@@ -170,11 +174,10 @@ def _updated_entry(config: dict, template: dict, root: Path, names: tuple[str, .
updated["env"] = {**environment, **template["env"]}
if "enabled_tools" in template or "enabled_tools" in config:
updated["enabled_tools"] = list(names)
if "tools" in template or "tools" in config:
current_tools = config.get("tools", {})
if not isinstance(current_tools, dict):
raise ValueError("The existing Artemis MCP tools setting is not an object")
updated["tools"] = {name: {"eager": True, **current_tools.get(name, {})} for name in names}
# Per-tool approval/enablement policies belong to the user. Leave `tools`
# untouched, including entries outside the current exported tool list.
# Rebuilding it both changes policy and sends nested tables to the scalar
# serializer, which produces JSON syntax rather than valid TOML.
for key in ("type", "required", "startup_timeout_sec", "connectionTimeoutMs"):
if key in template and key not in updated:
updated[key] = template[key]
@@ -300,12 +303,17 @@ def refresh_codex(
assignments[env_header] = env_updates
if not top and not env_updates:
return False
result = _replace_toml_tables(raw, assignments)
actual = tomllib.loads(result)["mcp_servers"]["artemis"]
if any(actual.get(key) != value for key, value in top.items()) or any(
actual.get("env", {}).get(key) != value for key, value in env_updates.items()
):
raise ValueError("Could not safely refresh the Artemis MCP table")
try:
result = _replace_toml_tables(raw, assignments)
actual = tomllib.loads(result)["mcp_servers"]["artemis"]
if any(actual.get(key) != value for key, value in top.items()) or any(
actual.get("env", {}).get(key) != value for key, value in env_updates.items()
):
raise ValueError("Updated MCP settings did not match the requested values")
except (ValueError, KeyError, TypeError) as exc:
raise McpSyncValidationError(
"Could not safely generate the MCP configuration update"
) from exc
path.parent.mkdir(parents=True, exist_ok=True)
_atomic_write(path, result)
return result != raw
@@ -339,6 +347,11 @@ def refresh_mcp(root: Path) -> int:
"Cannot read/write the configuration; check file permissions.",
"无法读写配置,请检查文件权限。",
)
elif isinstance(exc, McpSyncValidationError):
reason = launch_text(
"The synchronizer generated an invalid update from a readable configuration. This is an ARTEMIS sync error; do not delete your Codex configuration.",
"原配置可正常解析,但同步程序生成的更新未通过校验。这是 ARTEMIS 同步错误,请勿删除 Codex 配置。",
)
else:
reason = launch_text(
"Invalid TOML or Artemis configuration structure; check the file in Codex.",