# auth.md

You are an agent. This file tells you how to get access to **mcp-toolbelt**, a set of
deterministic, paid tools (math, parsing, text operations, conversions, ...) you can call instead of
spending tokens on them.

- Resource server: `mcptoolbelt.com` (MCP at `https://mcptoolbelt.com/mcp`, REST at `https://mcptoolbelt.com/v1/tools`)
- Authorization server: `mcptoolbelt.com` (issuer `https://mcptoolbelt.com`)
- Prices: `https://mcptoolbelt.com/pricing.json`. All amounts are integer USD micros (1 USD = 1,000,000).

## Discover

1. Call the resource without credentials. A `401` carries
   `WWW-Authenticate: Bearer resource_metadata="..."`, pointing at the Protected Resource
   Metadata (RFC 9728): `https://mcptoolbelt.com/.well-known/oauth-protected-resource/mcp`. Its `authorization_servers` names the issuer.
2. Fetch the Authorization Server Metadata (RFC 8414): `https://mcptoolbelt.com/.well-known/oauth-authorization-server`.

Fields you need from it:

- `authorization_endpoint`, `token_endpoint`: OAuth authorization code flow with PKCE (`S256`).
- `registration_endpoint`: OAuth Dynamic Client Registration (RFC 7591); clients are public (`token_endpoint_auth_methods_supported: ["none"]`).
- `scopes_supported`: `mcp:use tools:call account:read tools:call:calculate tools:batch:calculate tools:call:datetime tools:batch:datetime tools:call:json_validate tools:batch:json_validate tools:call:text_process tools:batch:text_process tools:call:convert_units tools:batch:convert_units tools:call:list_table tools:batch:list_table tools:call:encoding_hash tools:batch:encoding_hash tools:call:json_diff_patch tools:batch:json_diff_patch tools:call:identifier_validate tools:batch:identifier_validate`.
- `service_documentation`: this file.
- `agent_registration_endpoint`: where you register yourself when no human is at hand (non-standard field).

## Pick a method

- **A human is present and your client speaks MCP OAuth** (e.g. Claude, Cursor): use OAuth. The human approves you, picks the account you spend from and caps your spending. See *OAuth*.
- **Your human gave you an API key** (`sk_...`, created on the dashboard): send it as a bearer token. See *Use the credential*.
- **No human is at hand right now**: register yourself (`anonymous` registration). You get an API key that can use the tools' free calls at once, and a claim URL to give your human later so you can spend their balance. See *Register*.
- **No account at all, but you hold USDC**: pay per call with x402. Call a tool without credentials and pay the `402` (REST), or use the MCP server at `https://mcptoolbelt.com/mcp/x402`. Prices are in `https://mcptoolbelt.com/pricing.json`.

## Register

```http
POST /agent/register HTTP/1.1
Host: mcptoolbelt.com
Content-Type: application/json

{"name": "invoice-bot", "description": "Extracts totals from supplier invoices for ACME"}
```

`name` is required (max 90 characters); `description` is optional (max 500) and is shown to
the human who claims you. No credentials are needed. Registrations are limited to
5 per hour and 20 per day per IP.

```json
{
  "agent": {"id": 42, "name": "invoice-bot", "status": "unclaimed"},
  "api_key": "sk_...",
  "abilities": ["tools:call`, `account:read"],
  "claim": {"url": "https://.../agent/claim/claim_...", "expires_at": "2026-01-08T12:00:00+00:00"},
  "endpoints": {"mcp": "https://mcptoolbelt.com/mcp", "rest": "https://mcptoolbelt.com/v1/tools", "me": "https://mcptoolbelt.com/agent/me", "claim_url": "https://mcptoolbelt.com/agent/claim-url"}
}
```

Store `api_key` now; it is shown only once. Until you are claimed you have your own account
with **no balance**: you can use each tool's normal free calls, and calls beyond them fail
with `insufficient_balance`.

## Claim ceremony

1. **Materials**: the `claim.url` from registration. It is a secret for one human and works
   once, for 7 day(s).
2. **Handoff**: give the URL to your human (chat, email, ticket). They sign in, choose one of
   their accounts and a spending cap, and approve. Your API key keeps working and from then on
   spends that account's balance, within the cap.
3. **Polling**: `GET https://mcptoolbelt.com/agent/me` with your API key answers
   `{"agent": {"status": "unclaimed" | "claimed", ...}, "account": {...}, "spending_cap": {...}}`.
   Poll it at most once a minute, or simply retry the call that failed.

Lost or expired link? `POST https://mcptoolbelt.com/agent/claim-url` with your API key returns a new
`claim.url`; earlier links stop working. Unclaimed agents unused for 90 days
are revoked.

## OAuth

1. Register a client: `POST https://mcptoolbelt.com/oauth/register` with
   `{"client_name": "...", "redirect_uris": ["..."]}` (Dynamic Client Registration).
2. Send your human to `https://mcptoolbelt.com/oauth/authorize` (`response_type=code`, PKCE `S256`,
   `scope` from `mcp:use tools:call account:read tools:call:calculate tools:batch:calculate tools:call:datetime tools:batch:datetime tools:call:json_validate tools:batch:json_validate tools:call:text_process tools:batch:text_process tools:call:convert_units tools:batch:convert_units tools:call:list_table tools:batch:list_table tools:call:encoding_hash tools:batch:encoding_hash tools:call:json_diff_patch tools:batch:json_diff_patch tools:call:identifier_validate tools:batch:identifier_validate`). They choose the account, scopes and spending cap.
3. Exchange the code at `https://mcptoolbelt.com/oauth/token` (`grant_type=authorization_code`).
   Access tokens are short-lived; renew with `grant_type=refresh_token`.

## Use the credential

Send `Authorization: Bearer <api key or access token>` to:

- MCP (Streamable HTTP): `https://mcptoolbelt.com/mcp`. Tools include `account_get_balance`, `account_get_usage` and `account_get_pricing`.
- REST: `GET https://mcptoolbelt.com/v1/tools`, `POST https://mcptoolbelt.com/v1/tools/{tool_id}` (and `/quote`).

Tools whose catalog entry has `batch.enabled` also accept `POST https://mcptoolbelt.com/v1/tools/{tool_id}/batch`
and `/batch/quote`, with `{"inputs": [{...}, {...}]}`. Batch pricing is a fixed fee plus
a price per argument set. Catalog batch limits cover item count, total work units and payload bytes.
Outputs are returned in `data.output.results` in input order. A failed item cancels all billing;
earlier items may still have executed. x402 batches use one settlement and apply the minimum once.

Send an `Idempotency-Key` header when retrying REST calls; a retry is charged once.
Failed calls are never charged.

Abilities:

- `tools:call`: All tools (single calls and batches), including future tools
- `account:read`: Read the balance, usage and pricing
- `tools:call:calculate`: Call Calculate (single calls)
- `tools:batch:calculate`: Call Calculate (batches only)
- `tools:call:datetime`: Call Date and time (single calls)
- `tools:batch:datetime`: Call Date and time (batches only)
- `tools:call:json_validate`: Call JSON: validate and query (single calls)
- `tools:batch:json_validate`: Call JSON: validate and query (batches only)
- `tools:call:text_process`: Call Exact text operations (single calls)
- `tools:batch:text_process`: Call Exact text operations (batches only)
- `tools:call:convert_units`: Call Convert units (single calls)
- `tools:batch:convert_units`: Call Convert units (batches only)
- `tools:call:list_table`: Call List and table operations (single calls)
- `tools:batch:list_table`: Call List and table operations (batches only)
- `tools:call:encoding_hash`: Call Encoding and hashing (single calls)
- `tools:batch:encoding_hash`: Call Encoding and hashing (batches only)
- `tools:call:json_diff_patch`: Call JSON: diff and patch (single calls)
- `tools:batch:json_diff_patch`: Call JSON: diff and patch (batches only)
- `tools:call:identifier_validate`: Call Validate identifiers and checksums (single calls)
- `tools:batch:identifier_validate`: Call Validate identifiers and checksums (batches only)

`tools:call` grants all single and batch calls, including tools added later.
For selected tools, omit it and grant `tools:call:{tool_id}` for single calls and/or
`tools:batch:{tool_id}` for batches. Neither specific scope grants the other mode
or any other tool. Quotes require the same scope as calls. `account:read` is independent.
Tool grants do not enable tools or batching disabled in the catalog.

## Errors

Errors are JSON: `{"error": {"code": "...", "message": "..."}}`.

| Code | Status | Where | What to do |
|---|---|---|---|
| `authentication_required` | 401 | resource | Get a credential (this file). |
| `invalid_api_key` | 401 | resource | The key was revoked: register again or ask your human. |
| `invalid_token` | 401 | resource | Refresh the access token or authorize again. |
| `insufficient_balance` | 402 | tool call | No free calls left. If unclaimed, hand your claim URL to your human; otherwise ask them to top up. |
| `spending_cap_exceeded` | 403 | tool call | Wait for `resets_at` or ask your human to raise the cap. |
| `payment_required` | 402 | tool call (anonymous) | Pay with x402, or get a credential. |
| `insufficient_scope` | 403 | resource | The credential lacks `required_scope`. |
| `account_inactive` | 403 | resource | The account was suspended or closed. |
| `registration_disabled` | 403 | `/agent/register` | Use OAuth or an API key instead. |
| `too_many_registrations` | 429 | `/agent/register` | Retry after `Retry-After` seconds. Do not register repeatedly. |
| `already_claimed` | 409 | `/agent/claim-url` | You were claimed; just call tools. |

## Revocation

Humans revoke agents on the Agents page (`https://mcptoolbelt.com/agents`). Revoking cuts off every API
key and OAuth token of the agent at once; you then get `invalid_api_key` or `invalid_token`.
Do not re-register to get around a revocation.
