This commit is contained in:
2026-08-24 08:11:59 -07:00
commit 53df0eed10
275 changed files with 133056 additions and 0 deletions
+524
View File
@@ -0,0 +1,524 @@
#!/usr/bin/env python3
"""Operator-owned tool MCP registry, validation, and Codex rendering.
Tool MCP servers expose third-party tools to Codex. They are deliberately
separate from the MMO Agent MCP server (``mmo_mesh``), which launches and
supervises profile participants.
"""
from __future__ import annotations
import math
import os
import re
import shutil
from collections.abc import Mapping
from pathlib import Path
from typing import Any
from urllib.parse import urlsplit
from mmo_util import (
config_root,
parse_env_file,
read_toml,
valid_absolute_uri,
valid_http_header_value,
validate_id,
)
from mmo_version import MMO_SCHEMA_VERSION
TOOL_MCP_RESERVED_IDS = {"mmo_mesh"}
TOOL_MCP_TRANSPORTS = {"stdio", "streamable_http"}
TOOL_MCP_APPROVAL_MODES = {"auto", "prompt", "writes", "approve"}
_DOCUMENT_FIELDS = {"schema_version", "tool_mcp_servers"}
_COMMON_SERVER_FIELDS = {
"transport",
"enabled_tools",
"default_tools_approval_mode",
"startup_timeout_sec",
"tool_timeout_sec",
"supports_parallel_tool_calls",
"tools",
}
_STDIO_FIELDS = {"command", "args", "env", "env_vars", "cwd"}
_HTTP_FIELDS = {
"url",
"bearer_token_env_var",
"http_headers",
"env_http_headers",
}
_OAUTH_FIELDS = {"auth", "scopes", "oauth", "oauth_resource", "environment_id"}
_REGISTRY_OWNED_POLICY_FIELDS = {"enabled", "required", "disabled_tools"}
_TOOL_FIELDS = {"approval_mode"}
_ENVIRONMENT_NAME = re.compile(r"[A-Za-z_][A-Za-z0-9_]*")
_HEADER_NAME = re.compile(r"[!#$%&'*+.^_`|~0-9A-Za-z-]+")
_SENSITIVE_ENVIRONMENT_NAME = re.compile(
r"(?:^|_)(?:API_?KEY|KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|COOKIE|AUTH|PRIVATE)(?:_|$)",
re.IGNORECASE,
)
_SENSITIVE_HEADER_NAME = re.compile(
r"(?:^|-)(?:authorization|cookie|api-?key|key|token|secret|password|passwd|"
r"credential|auth|private)(?:-|$)",
re.IGNORECASE,
)
def tool_mcp_registry_root() -> Path:
"""Return the operator-owned directory containing registry fragments."""
return config_root() / "tool-mcp.d"
def _reject_unknown_fields(value: Mapping[str, Any], allowed: set[str], label: str) -> None:
unknown = sorted(set(value) - allowed)
if unknown:
raise ValueError(f"{label} has unknown fields: {', '.join(unknown)}")
def _nonempty_string(value: Any, label: str) -> str:
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{label} must be a non-empty string")
if any(ord(character) < 0x20 or ord(character) == 0x7F for character in value):
raise ValueError(f"{label} cannot contain control characters")
return value
def _string_list(value: Any, label: str, *, allow_empty: bool) -> list[str]:
if not isinstance(value, list) or not all(isinstance(item, str) for item in value):
raise ValueError(f"{label} must be an array of strings")
if not allow_empty and not value:
raise ValueError(f"{label} cannot be empty")
if any(not item.strip() for item in value):
raise ValueError(f"{label} cannot contain empty strings")
if len(value) != len(set(value)):
raise ValueError(f"{label} cannot contain duplicates")
return list(value)
def _environment_name(value: Any, label: str) -> str:
if not isinstance(value, str) or not _ENVIRONMENT_NAME.fullmatch(value):
raise ValueError(f"{label} must be a valid environment variable name")
return value
def _positive_seconds(value: Any, label: str) -> float:
if (
not isinstance(value, (int, float))
or isinstance(value, bool)
or not math.isfinite(float(value))
or not 0 < float(value) <= 172_800
):
raise ValueError(f"{label} must be a finite number between 0 and 172800")
return float(value)
def _string_map(value: Any, label: str) -> dict[str, str]:
if not isinstance(value, Mapping):
raise ValueError(f"{label} must be a table of strings")
result: dict[str, str] = {}
for raw_key, raw_value in value.items():
if not isinstance(raw_key, str) or not isinstance(raw_value, str):
raise ValueError(f"{label} must be a table of strings")
result[raw_key] = raw_value
return result
def _validate_stdio_environment(value: Any, label: str) -> dict[str, str]:
environment = _string_map(value, label)
result: dict[str, str] = {}
for name, raw_value in environment.items():
_environment_name(name, f"{label} key")
if _SENSITIVE_ENVIRONMENT_NAME.search(name):
raise ValueError(
f"{label}.{name} looks credential-bearing; use env_vars and credentials.env"
)
if "\x00" in raw_value:
raise ValueError(f"{label}.{name} cannot contain NUL")
result[name] = raw_value
return dict(sorted(result.items()))
def _validate_headers(value: Any, label: str, *, environment_backed: bool) -> dict[str, str]:
headers = _string_map(value, label)
result: dict[str, str] = {}
seen: set[str] = set()
for raw_name, raw_value in headers.items():
if not _HEADER_NAME.fullmatch(raw_name):
raise ValueError(f"{label} contains an invalid HTTP header name: {raw_name!r}")
normalized = raw_name.lower()
if normalized in seen:
raise ValueError(f"{label} contains duplicate case-insensitive header {raw_name!r}")
seen.add(normalized)
if environment_backed:
_environment_name(raw_value, f"{label}.{raw_name}")
else:
if _SENSITIVE_HEADER_NAME.search(raw_name):
raise ValueError(
f"{label}.{raw_name} is credential-bearing; use bearer_token_env_var "
"or env_http_headers"
)
if not valid_http_header_value(raw_value):
raise ValueError(f"{label}.{raw_name} contains an invalid HTTP header value")
result[raw_name] = raw_value
return dict(sorted(result.items(), key=lambda item: item[0].lower()))
def _validate_http_url(value: Any, label: str) -> str:
url = _nonempty_string(value, label)
if not valid_absolute_uri(url):
raise ValueError(f"{label} must be a valid HTTP(S) URL")
try:
parsed = urlsplit(url)
_ = parsed.port
except ValueError as exc:
raise ValueError(f"{label} must be a valid HTTP(S) URL") from exc
if parsed.scheme.lower() not in {"http", "https"} or not parsed.hostname:
raise ValueError(f"{label} must be a valid HTTP(S) URL")
if parsed.username is not None or parsed.password is not None:
raise ValueError(f"{label} cannot contain embedded credentials")
if parsed.fragment:
raise ValueError(f"{label} cannot contain a URL fragment")
return url
def _validate_stdio_command(value: Any, label: str) -> str:
command = _nonempty_string(value, label)
if "/" not in command and not command.startswith("~"):
return command
try:
path = Path(command).expanduser()
except RuntimeError as exc:
raise ValueError(f"{label} has an unknown home-directory user") from exc
if not path.is_absolute():
raise ValueError(f"{label} must be a PATH executable name or an absolute path")
return str(path.resolve())
def _validate_tool_policy(
value: Any,
*,
label: str,
enabled_tools: set[str],
) -> dict[str, dict[str, str]]:
if value is None:
return {}
if not isinstance(value, Mapping):
raise ValueError(f"{label} must be a table")
result: dict[str, dict[str, str]] = {}
for raw_name, raw_policy in value.items():
tool_name = _nonempty_string(raw_name, f"{label} tool name")
if tool_name not in enabled_tools:
raise ValueError(f"{label}.{tool_name} is not present in enabled_tools")
if not isinstance(raw_policy, Mapping):
raise ValueError(f"{label}.{tool_name} must be a table")
_reject_unknown_fields(raw_policy, _TOOL_FIELDS, f"{label}.{tool_name}")
approval = raw_policy.get("approval_mode")
if not isinstance(approval, str) or approval not in TOOL_MCP_APPROVAL_MODES:
raise ValueError(
f"{label}.{tool_name}.approval_mode must be one of "
f"{sorted(TOOL_MCP_APPROVAL_MODES)}"
)
result[tool_name] = {"approval_mode": approval}
return dict(sorted(result.items()))
def validate_tool_mcp_server(server_id: str, value: Any, *, label: str) -> dict[str, Any]:
"""Validate and normalize one operator-defined tool MCP server."""
server_id = validate_id(server_id, "tool MCP server id")
if server_id in TOOL_MCP_RESERVED_IDS:
raise ValueError(f"tool MCP server id {server_id!r} is reserved for Agent MCP")
if not isinstance(value, Mapping):
raise ValueError(f"{label} must be a table")
if "bearer_token" in value:
raise ValueError(f"{label}.bearer_token is forbidden; use bearer_token_env_var")
oauth_fields = sorted(set(value) & _OAUTH_FIELDS)
if oauth_fields:
raise ValueError(
f"{label} uses unsupported OAuth fields: {', '.join(oauth_fields)}; "
"the Tool MCP registry supports environment-backed authentication only"
)
policy_fields = sorted(set(value) & _REGISTRY_OWNED_POLICY_FIELDS)
if policy_fields:
raise ValueError(f"{label} cannot set agent-owned fields: {', '.join(policy_fields)}")
transport = value.get("transport")
if not isinstance(transport, str) or transport not in TOOL_MCP_TRANSPORTS:
raise ValueError(f"{label}.transport must be one of {sorted(TOOL_MCP_TRANSPORTS)}")
allowed = _COMMON_SERVER_FIELDS | (_STDIO_FIELDS if transport == "stdio" else _HTTP_FIELDS)
_reject_unknown_fields(value, allowed, label)
enabled_tools = _string_list(
value.get("enabled_tools"), f"{label}.enabled_tools", allow_empty=False
)
approval = value.get("default_tools_approval_mode")
if not isinstance(approval, str) or approval not in TOOL_MCP_APPROVAL_MODES:
raise ValueError(
f"{label}.default_tools_approval_mode must be one of {sorted(TOOL_MCP_APPROVAL_MODES)}"
)
normalized: dict[str, Any] = {
"transport": transport,
"enabled_tools": enabled_tools,
"default_tools_approval_mode": approval,
"supports_parallel_tool_calls": False,
}
if "supports_parallel_tool_calls" in value:
if not isinstance(value["supports_parallel_tool_calls"], bool):
raise ValueError(f"{label}.supports_parallel_tool_calls must be boolean")
normalized["supports_parallel_tool_calls"] = value["supports_parallel_tool_calls"]
for timeout_field in ("startup_timeout_sec", "tool_timeout_sec"):
if timeout_field in value:
normalized[timeout_field] = _positive_seconds(
value[timeout_field], f"{label}.{timeout_field}"
)
normalized["tools"] = _validate_tool_policy(
value.get("tools"),
label=f"{label}.tools",
enabled_tools=set(enabled_tools),
)
if transport == "stdio":
normalized["command"] = _validate_stdio_command(value.get("command"), f"{label}.command")
normalized["args"] = _string_list(value.get("args", []), f"{label}.args", allow_empty=True)
if any("\x00" in argument for argument in normalized["args"]):
raise ValueError(f"{label}.args cannot contain NUL")
normalized["env"] = _validate_stdio_environment(value.get("env", {}), f"{label}.env")
env_vars = _string_list(value.get("env_vars", []), f"{label}.env_vars", allow_empty=True)
for name in env_vars:
_environment_name(name, f"{label}.env_vars")
overlap = sorted(set(normalized["env"]) & set(env_vars))
if overlap:
raise ValueError(
f"{label} defines the same variables in env and env_vars: {', '.join(overlap)}"
)
normalized["env_vars"] = env_vars
if "cwd" in value:
raw_cwd = _nonempty_string(value["cwd"], f"{label}.cwd")
try:
cwd = Path(raw_cwd).expanduser()
except RuntimeError as exc:
raise ValueError(f"{label}.cwd has an unknown home-directory user") from exc
if not cwd.is_absolute():
raise ValueError(f"{label}.cwd must expand to an absolute path")
normalized["cwd"] = str(cwd.resolve())
else:
normalized["url"] = _validate_http_url(value.get("url"), f"{label}.url")
if "bearer_token_env_var" in value:
normalized["bearer_token_env_var"] = _environment_name(
value["bearer_token_env_var"], f"{label}.bearer_token_env_var"
)
normalized["http_headers"] = _validate_headers(
value.get("http_headers", {}),
f"{label}.http_headers",
environment_backed=False,
)
normalized["env_http_headers"] = _validate_headers(
value.get("env_http_headers", {}),
f"{label}.env_http_headers",
environment_backed=True,
)
static_names = {name.lower() for name in normalized["http_headers"]}
environment_names = {name.lower() for name in normalized["env_http_headers"]}
overlap = sorted(static_names & environment_names)
if overlap:
raise ValueError(
f"{label} defines headers in both http_headers and env_http_headers: "
+ ", ".join(overlap)
)
return normalized
def _load_tool_mcp_fragment(path: Path) -> dict[str, dict[str, Any]]:
data = read_toml(path)
_reject_unknown_fields(data, _DOCUMENT_FIELDS, f"tool MCP registry {path}")
schema = data.get("schema_version")
if not isinstance(schema, int) or isinstance(schema, bool) or schema != MMO_SCHEMA_VERSION:
raise ValueError(f"unsupported tool MCP registry schema_version in {path}")
raw_servers = data.get("tool_mcp_servers", {})
if not isinstance(raw_servers, Mapping):
raise ValueError(f"tool_mcp_servers must be a table in {path}")
return {
server_id: validate_tool_mcp_server(
server_id,
server,
label=f"tool MCP server {server_id} in {path}",
)
for server_id, server in raw_servers.items()
}
def load_tool_mcp_registry_with_sources() -> tuple[dict[str, dict[str, Any]], dict[str, str]]:
"""Load deterministic operator fragments, replacing duplicate entries whole."""
registry: dict[str, dict[str, Any]] = {}
sources: dict[str, str] = {}
root = tool_mcp_registry_root()
if root.is_dir():
for path in sorted(root.glob("*.toml")):
for server_id, server in _load_tool_mcp_fragment(path).items():
registry[server_id] = server
sources[server_id] = str(path)
return dict(sorted(registry.items())), dict(sorted(sources.items()))
def load_tool_mcp_registry() -> dict[str, dict[str, Any]]:
return load_tool_mcp_registry_with_sources()[0]
def validate_tool_mcp_grants(
value: Any,
registry: Mapping[str, Mapping[str, Any]],
*,
label: str,
) -> dict[str, dict[str, Any]]:
"""Validate an agent's required/optional grants against operator maxima."""
if value is None:
return {}
if not isinstance(value, Mapping):
raise ValueError(f"{label} must be a table")
result: dict[str, dict[str, Any]] = {}
for raw_server_id, raw_grant in value.items():
server_id = validate_id(raw_server_id, "tool MCP server id")
if server_id not in registry:
raise ValueError(
f"{label}.{server_id} references an undefined operator tool MCP server; "
f"define it under {tool_mcp_registry_root()}"
)
if not isinstance(raw_grant, Mapping):
raise ValueError(f"{label}.{server_id} must be a table")
_reject_unknown_fields(
raw_grant,
{"required", "enabled_tools"},
f"{label}.{server_id}",
)
required = raw_grant.get("required", True)
if not isinstance(required, bool):
raise ValueError(f"{label}.{server_id}.required must be boolean")
maximum = list(registry[server_id]["enabled_tools"])
selected = (
maximum
if "enabled_tools" not in raw_grant
else _string_list(
raw_grant["enabled_tools"],
f"{label}.{server_id}.enabled_tools",
allow_empty=False,
)
)
outside_maximum = sorted(set(selected) - set(maximum))
if outside_maximum:
raise ValueError(
f"{label}.{server_id}.enabled_tools exceeds the operator allowlist: "
+ ", ".join(outside_maximum)
)
result[server_id] = {"required": required, "enabled_tools": selected}
return dict(sorted(result.items()))
def tool_mcp_environment_names(server: Mapping[str, Any]) -> list[str]:
"""Return process environment names referenced by a normalized definition."""
names: set[str] = set()
if server["transport"] == "stdio":
names.update(str(name) for name in server.get("env_vars", []))
else:
names.update(tool_mcp_http_environment_names(server))
return sorted(names)
def tool_mcp_http_environment_names(server: Mapping[str, Any]) -> list[str]:
"""Return environment names whose values become HTTP header material."""
if server["transport"] != "streamable_http":
return []
names = {str(name) for name in server.get("env_http_headers", {}).values()}
bearer = server.get("bearer_token_env_var")
if bearer:
names.add(str(bearer))
return sorted(names)
def codex_tool_mcp_server_config(
server: Mapping[str, Any],
grant: Mapping[str, Any] | None,
) -> dict[str, Any]:
"""Compile one normalized definition/grant to Codex's mcp_servers shape."""
transport = str(server["transport"])
fields = _STDIO_FIELDS if transport == "stdio" else _HTTP_FIELDS
result = {
key: server[key] for key in sorted(fields) if key in server and server[key] not in ({}, [])
}
maximum = list(server["enabled_tools"])
selected = set(grant["enabled_tools"] if grant is not None else ())
result.update(
{
"enabled": grant is not None,
"required": bool(grant["required"]) if grant is not None else False,
"supports_parallel_tool_calls": bool(server["supports_parallel_tool_calls"]),
"enabled_tools": maximum,
# Always emit this array so a native role can clear a narrower
# deny-list inherited from its parent config layer.
"disabled_tools": [tool for tool in maximum if tool not in selected],
"default_tools_approval_mode": server["default_tools_approval_mode"],
}
)
for timeout_field in ("startup_timeout_sec", "tool_timeout_sec"):
if timeout_field in server:
result[timeout_field] = server[timeout_field]
if server.get("tools"):
result["tools"] = server["tools"]
return result
def tool_mcp_readiness(
server_id: str,
server: Mapping[str, Any],
*,
sources: Mapping[str, str] | None = None,
) -> dict[str, Any]:
"""Return non-launching command, cwd, and environment readiness."""
values = parse_env_file(config_root() / "credentials.env")
values.update({key: value for key, value in os.environ.items() if value})
http_environment = set(tool_mcp_http_environment_names(server))
environment: dict[str, bool] = {}
invalid_environment: list[str] = []
for name in tool_mcp_environment_names(server):
value = values.get(name)
valid = bool(value) and "\x00" not in str(value)
if valid and name in http_environment:
valid = valid_http_header_value(str(value))
environment[name] = valid
if value and not valid:
invalid_environment.append(name)
result: dict[str, Any] = {
"id": server_id,
"source": (sources or {}).get(server_id),
"transport": server["transport"],
"enabled_tools": list(server["enabled_tools"]),
"default_tools_approval_mode": server["default_tools_approval_mode"],
"environment": environment,
"invalid_environment": invalid_environment,
}
if server["transport"] == "stdio":
command = str(server["command"])
command_path = Path(command).expanduser()
resolved = (
str(command_path.resolve())
if "/" in command and command_path.is_file() and os.access(command_path, os.X_OK)
else shutil.which(command)
)
result["command"] = command
result["resolved_command"] = resolved
cwd = server.get("cwd")
result["cwd"] = cwd
result["cwd_ready"] = cwd is None or Path(str(cwd)).is_dir()
result["transport_ready"] = bool(resolved) and bool(result["cwd_ready"])
else:
result["url"] = server["url"]
result["transport_ready"] = True
result["environment_ready"] = all(environment.values())
result["ready"] = bool(result["transport_ready"]) and bool(result["environment_ready"])
return result