Files
wyndham-ARR/arr_mcp/launch.py
2026-07-29 16:38:05 +08:00

109 lines
3.2 KiB
Python

"""Local secure launcher that loads routes and Keychain-backed MCP secrets."""
from __future__ import annotations
import argparse
import os
import stat
import subprocess
from pathlib import Path
from typing import Dict, Optional, Sequence
from arr_mcp.run import main as run_mcp
KEYCHAIN_ACCOUNT = "arr-web"
KEYCHAIN_SERVICES = {
"OSS_ACCESS_KEY_ID": "com.chillishark.arr.oss-access-key-id",
"OSS_ACCESS_KEY_SECRET": "com.chillishark.arr.oss-access-key-secret",
"ARR_MCP_BEARER_TOKEN": "com.chillishark.arr.mcp-bearer",
}
ROUTE_KEYS = frozenset(
{
"ARR_OSS_REGION",
"ARR_OSS_ENDPOINT",
"ARR_OSS_BUCKET",
"ARR_OBJECT_PREFIX",
}
)
def _private_route_values(path: Path) -> Dict[str, str]:
candidate = path.expanduser()
if candidate.is_symlink():
raise ValueError("ARR MCP route configuration is invalid")
resolved = candidate.resolve(strict=True)
metadata = resolved.stat()
if (
not stat.S_ISREG(metadata.st_mode)
or metadata.st_uid != os.getuid()
or stat.S_IMODE(metadata.st_mode) != 0o600
):
raise ValueError("ARR MCP route configuration is invalid")
values: Dict[str, str] = {}
for raw in resolved.read_text(encoding="utf-8").splitlines():
line = raw.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
key = key.strip()
if key in ROUTE_KEYS:
if key in values:
raise ValueError("ARR MCP route configuration is invalid")
values[key] = value.strip().strip('"').strip("'")
if any(not values.get(key) for key in ("ARR_OSS_REGION", "ARR_OSS_BUCKET")):
raise ValueError("ARR MCP route configuration is incomplete")
return values
def _keychain_secret(service: str) -> str:
try:
completed = subprocess.run(
[
"security",
"find-generic-password",
"-s",
service,
"-a",
KEYCHAIN_ACCOUNT,
"-w",
],
check=True,
capture_output=True,
text=True,
timeout=10,
)
except (OSError, subprocess.SubprocessError):
raise ValueError("required ARR MCP Keychain item is unavailable") from None
value = completed.stdout.strip()
if not value:
raise ValueError("required ARR MCP Keychain item is unavailable")
return value
def load_runtime_environment(route_config: Path) -> None:
for key, value in _private_route_values(route_config).items():
os.environ[key] = value
for environment_name, service in KEYCHAIN_SERVICES.items():
os.environ[environment_name] = _keychain_secret(service)
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
"--route-config",
type=Path,
default=Path("~/.config/arr/agent-writeback.env"),
)
return parser
def main(argv: Optional[Sequence[str]] = None) -> int:
args, remaining = _parser().parse_known_args(argv)
load_runtime_environment(args.route_config)
return run_mcp(remaining)
if __name__ == "__main__":
raise SystemExit(main())