# Thai Data Cloud (TDC) — for AI agents TDC is a Thai cloud provider: servers, managed PostgreSQL (pgvector), Kubernetes, hosting, domains, SSL, and a Sovereign AI Inference API (Thai models) — data stays in Thailand (PDPA / Thai AI Act ready). ## Act on behalf of a customer - MCP (streamable HTTP): https://mcp.thaidata.cloud/mcp — Authorization: Bearer - OpenAPI (REST): https://mcp.thaidata.cloud/openapi.json - Agent card: https://mcp.thaidata.cloud/.well-known/tdc-agent.json - Get a token (customer issues it with spending limits): https://thaidata.cloud/agent - Sandbox: tokens starting with tdc_sbx_ never charge real money ## Auth (OAuth 2.1 resource server) This service verifies tokens; it does not issue OAuth tokens — the authorization server lives in the TDC customer portal. Both credential shapes go in the same header, `Authorization: Bearer `: - an opaque TDC mandate token (tdc_sbx_… / tdc_live_…), the fast path, issued at https://mcp.thaidata.cloud/ - an OAuth 2.1 JWT access token from the portal, once that authorization server is announced Protected-resource metadata (RFC 9728): https://mcp.thaidata.cloud/.well-known/oauth-protected-resource (REST) and https://mcp.thaidata.cloud/.well-known/oauth-protected-resource/mcp (the MCP endpoint — its own resource, so a token minted for /mcp cannot be replayed against the REST twin). A missing or bad credential returns 401 with `WWW-Authenticate: Bearer realm="tdc", error="invalid_token", …, resource_metadata="…"`; a valid credential without the scope an operation needs returns 403 with `error="insufficient_scope"` and a `scope="…"` parameter naming exactly what to ask for. Scope names are the six below, and a `tdc:` prefix is accepted as an alias: catalog:read, account:read, orders:write, payments:charge, services:manage, services:delete. Mandate tokens expire and can be revoked (DELETE https://mcp.thaidata.cloud/mandates/me). ## Rate limits Every tool carries a risk tier in its `_meta.tdc` block (`risk`, `scopes`, `reversible`) and each tier has its own budget per token, shared by all replicas: R0 60/min, R1 20/min, R2 10/min, R3 3/min plus 20/day, and 120/min across everything the token does. Over REST you get `429` with `Retry-After` and the `RateLimit-*` headers; over MCP you get a normal tool result `{"error": "rate_limited", "retry_after_s": N}` — wait that many seconds, do not retry in a loop. ## Audit trail EVERY call is recorded — reads too, and every refusal: 401, 403 (with the scope that was missing), 404, 422 and 429. The customer reads their own trail at `GET https://mcp.thaidata.cloud/audit` (cursor paginated, oldest first; filters: kind=call|event, action, outcome=allowed|denied|rate_limited|error, transport, since, until). There is no customer_id parameter — the tenant comes from your token, so you can only ever read the customer you are acting for. `agent_history` is the same trail filtered to business events. Arguments are redacted before they are stored: values under `env`, `*token*`, `*secret*`, `*password*` keys are dropped (the key NAMES are kept), Thai national IDs, +66 numbers, card numbers, PEM keys and `sk-`/`ghp_`/`AKIA`/JWT strings are masked, and credentials in a git URL are stripped. Assume anything you send is written down in that form — and that an operation which cannot be recorded (money, deletion) is refused with `503` rather than performed silently. ## Flow recommend_setup → create_quote → place_order → pay_order → deploy_app → set_dns_record → enable_ssl → get_service ## Rules - Payments above the mandate's auto-pay limit return approval_url — the human pays; never retry. - delete_service always needs human confirmation. - Everything the agent does is logged for the customer (agent_history, GET /audit).