# /// script # requires-python = ">=3.12" # dependencies = ["mcp==2.3.0", "httpx2==2.16.0"] # /// """Unattended public MCP signup, persisted identity, authenticated access and reuse. Usage: uv run examples/mcp_agent.py --profile /secure/path/agent.json --username unique_name Existing profiles are reused without signup. No credentials are printed. """ import argparse import asyncio import json import os import secrets from pathlib import Path import httpx2 from mcp import Client from mcp.client.streamable_http import streamable_http_client def save(path, value): path.parent.mkdir(parents=True, exist_ok=True) temporary = path.with_suffix(".new") fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) with os.fdopen(fd, "w") as stream: json.dump(value, stream) stream.flush() os.fsync(stream.fileno()) os.replace(temporary, path) async def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--profile", type=Path, required=True) parser.add_argument("--username", required=True) parser.add_argument("--url", default="https://db.parklab.work") args = parser.parse_args() url = args.url.rstrip("/") if args.profile.exists(): if args.profile.stat().st_mode & 0o077: raise SystemExit("Profile must have mode 0600") profile = json.loads(args.profile.read_text()) if profile["service_url"] != url: raise SystemExit("Service URL differs from saved identity") else: profile = { "service_url": url, "username": args.username, "password": secrets.token_urlsafe(36), } # Save before signup. If an uncertain response interrupts signup, recover by login. save(args.profile, profile) async with httpx2.AsyncClient(timeout=httpx2.Timeout(30, read=90)) as http: async with Client(streamable_http_client(url + "/mcp", http_client=http)) as client: if not profile.get("api_key"): result = await client.call_tool( "account_login", { "login": profile.get("account_id", profile["username"]), "password": profile["password"], }, ) if ( result.is_error and result.structured_content["error"]["code"] == "INVALID_CREDENTIALS" ): if profile.get("account_id"): raise SystemExit("Saved account needs recovery; refusing a new signup") result = await client.call_tool( "account_register", { "username": profile["username"], "password": profile["password"], }, ) if result.is_error: raise SystemExit(result.structured_content["error"]["code"]) data = result.structured_content profile.update( account_id=data["account"]["id"], access_token=data["tokens"]["access_token"] ) if data.get("recovery_codes"): profile["recovery_codes"] = data["recovery_codes"] save(args.profile, profile) http.headers["Authorization"] = "Bearer " + profile["access_token"] result = await client.call_tool("api_key_create", {"name": "python-agent"}) if result.is_error: raise SystemExit(result.structured_content["error"]["code"]) profile.update( api_key=result.structured_content["secret"], credential_id=result.structured_content["credential"]["id"], ) save(args.profile, profile) http.headers["Authorization"] = "Bearer " + profile["api_key"] result = await client.call_tool("account_get", {}) if result.is_error: raise SystemExit(result.structured_content["error"]["code"]) if result.structured_content["id"] != profile["account_id"]: raise SystemExit("Account identity mismatch") print(json.dumps({"ok": True, "account_id": profile["account_id"]})) if __name__ == "__main__": asyncio.run(main())