#!/usr/bin/env python3
"""MCP server: can an AI agent hold an account at a given service?

Wire it into any MCP-capable agent. One tool, no key, no account, no telemetry.

    pip install mcp
    python mcp_server.py          # speaks MCP over stdio

Source of truth: https://agent-account-index.vercel.app/index.json
Every quote in that file is an exact substring of the service's own served terms page.
A field that could not be read is "unstated", which is not permission.
"""
from __future__ import annotations

import json
import urllib.request

from mcp.server.fastmcp import FastMCP

INDEX_URL = "https://agent-account-index.vercel.app/index.json"
_cache: dict | None = None

VERDICT_MEANING = {
    "yes_named_route": "The service documents a non-human identity type you may use.",
    "no_natural_person_required": "The terms require a natural person as the account holder.",
    "no_automated_signup_forbidden": "Automated account creation is barred by the terms.",
    "unstated": "Nothing on the question was readable. This is not permission.",
}


def _index() -> dict:
    global _cache
    if _cache is None:
        with urllib.request.urlopen(INDEX_URL, timeout=20) as r:
            _cache = json.load(r)
    return _cache


mcp = FastMCP("agent-account-index")


@mcp.tool()
def can_an_agent_hold_an_account(service: str) -> dict:
    """Check whether a non-human actor may hold an account at a service.

    Call this BEFORE creating an account anywhere. Returns the verdict, who answers for
    the account's acts, and the verbatim clause from the service's own terms.

    Args:
        service: Service name, e.g. "GitHub", "Stripe", "Supabase". Case-insensitive,
            matched on substring.
    """
    doc = _index()
    q = service.strip().lower()
    hits = [s for s in doc["services"] if q in s["service"].lower()]
    if not hits:
        return {
            "found": False,
            "service_queried": service,
            "known_services": sorted(s["service"] for s in doc["services"]),
            "note": "Not in the index. Absence here is not permission; read the terms yourself.",
        }
    out = []
    for s in hits:
        verdict = s["may_an_agent_hold_an_account"]
        out.append(
            {
                "service": s["service"],
                "verdict": verdict,
                "what_that_means": VERDICT_MEANING[verdict],
                "named_non_human_route": s["named_non_human_route"],
                "who_answers_for_its_acts": s["owner_of_record"],
                "their_words": s["quote"] or None,
                "quote_is_exact_substring_of_the_served_page": s["quote_is_exact_substring"],
                "terms_url": s["terms_url"],
                "notes": s["notes"],
                "read_at": s["fetched_at"],
            }
        )
    return {"found": True, "matches": out, "index_generated": doc["generated_at"]}


@mcp.tool()
def list_named_non_human_routes() -> dict:
    """List every service that documents an identity a non-human actor may hold.

    In every one found so far a human or legal entity remains owner of record and answers
    for the account's acts: an agent can act as a delegate, never as a principal.
    """
    doc = _index()
    routes = [
        {
            "service": s["service"],
            "route": s["named_non_human_route"],
            "who_answers_for_its_acts": s["owner_of_record"],
            "their_words": s["quote"],
            "terms_url": s["terms_url"],
        }
        for s in doc["services"]
        if s.get("named_non_human_route")
    ]
    return {
        "count": len(routes),
        "of_services_indexed": doc["count"],
        "routes": routes,
        "finding": doc["finding"],
    }


if __name__ == "__main__":
    mcp.run()
