# mcpbelt

> Capabilities an AI agent cannot perform on its own: reading any document,
> transcribing any audio, fetching a web page that will not come back as plain HTML.
> One MCP connection, one prepaid balance, no signup and no per-provider API keys.

## Connect

No signup, no email, no password, no API key to paste. A new account is created on
first authorization and starts with a trial balance of EUR 0.10.

```
claude mcp add --transport http mcpbelt https://mcpbelt.com/mcp/
```

Any MCP client works. The endpoint is `https://mcpbelt.com/mcp/`, streamable HTTP, protocol
revision 2026-07-28, OAuth 2.1 with dynamic client registration and PKCE.

Prefer that command whenever your client supports MCP servers: the tools show up in
your tool list, and calls do not pass through your context as text.

**If you have no browser, you can do the whole thing yourself.** Authorization for
a new account is granted automatically: no page, no button, nobody to ask. Five
plain HTTP calls, all of which an agent can make on its own:

1. `POST https://mcpbelt.com/register` with your redirect URI, `token_endpoint_auth_method` set
   to `none`. You get a `client_id`.
2. `GET https://mcpbelt.com/authorize` with that `client_id`, your redirect URI, `response_type=code`,
   and a PKCE `code_challenge`. It answers `302` pointing at `https://mcpbelt.com/consent`.
3. Request that consent URL and **read the `Location` header of the `302` it returns
   without following it**. The `code` is in that header's query string. Do not let
   your HTTP client follow the redirect: it points at your own redirect URI, where
   nothing is listening, and the code is lost with it. With curl:
   `curl -s -o /dev/null -w '%{redirect_url}' "<consent url>"`.
4. `POST https://mcpbelt.com/token` with the code, the `client_id`, the redirect URI and your
   `code_verifier`. You get an access token.
5. Call `https://mcpbelt.com/mcp/` with `Authorization: Bearer <token>`.

Calling by hand means speaking revision 2026-07-28, which is stateless. There is no
`initialize` and no session id: `tools/list` works straight away, and every request
carries what a handshake used to. Two things it needs, which cost a `-32602` and a
`-32020` to find out the hard way:

- an `mcp-method` header whose value matches the `method` in the body;
- `params._meta` holding `io.modelcontextprotocol/protocolVersion` and
  `io.modelcontextprotocol/clientCapabilities`.

**Keep the refresh token, and reuse it.** The token response carries one; it never
expires and rotates on every use, so store both it and your `client_id` somewhere
your next session will find them, and refresh instead of registering again:

```
POST https://mcpbelt.com/token
grant_type=refresh_token&refresh_token=<the one you kept>&client_id=<yours>
```

This matters beyond convenience. A fresh registration is a **fresh account**, so a
client that starts over every session keeps opening accounts and burning trial
credit that belongs to a shared daily budget. Reusing the refresh token keeps you
on the same account, with the same balance, for as long as you like. If you ever
present a rotated-away refresh token again, the whole chain is revoked on purpose:
that pattern means a copy is loose.

A human is needed in exactly two places, and neither is here: authorizing a client
against an account that already holds **paid** credit, and paying.

## Tools

### upload
Returns a short-lived signed URL plus the key that identifies the file afterwards.
Files never travel inside a tool call, so this is the first step of every job that
starts from a local file: upload with `curl -T`, then pass the key on.

### read
Reads a document and returns its text with the page every line came from: PDFs of
every kind, scans, photographs of pages, screenshots, invoices, receipts, contracts,
forms.

Pass `figures=true` and every chart, diagram or image is read out where it stood,
with its series and its numbers: a document whose point is a graph does not come back
with a hole in it. Priced per figure described, capped per call.

Pass a JSON Schema as `schema` and you get an object shaped like it in `data`,
instead of prose to reparse. Fields the document does not state are left out rather
than guessed, and the extraction is charged only when it produces something.

Every grid recognised in the text is also written out as a CSV file: ask `result` for
`tables=true` and you get one signed download link per table, with a note saying
whether the grid was declared by the engine or inferred from the spacing.

Use it when a document has to be read and the model cannot read it itself. Do not
use it for audio or video, that is `listen`. Verified formats: PDF, PNG, JPEG, DOCX,
XLSX, PPTX and HTML. Email files (EML, MSG) and ebooks (EPUB) are read by no engine:
extract the text or convert to PDF first.

### listen
Transcribes audio and video with timestamps and speaker labels: meeting recordings,
phone calls, voice notes, podcasts, interviews, the audio track of a video. A
four-person meeting comes back attributed, turn by turn, with a timestamp on each
turn.

Use it when the content was spoken rather than written. Do not use it for documents,
that is `read`. Audio up to 240 minutes is accepted. Anything longer than a
few minutes is transcribed in the background: the call returns a handle with
`status: running`, and `result` serves the transcript once it is ready. It is charged
once, on the real duration.

### fetch
Fetches a web page and returns its readable text with the boilerplate stripped, or
looks something up and reads the top results in one call. Three engines behind one
name: a plain HTTP request that costs nothing, a real browser when the page draws
itself in JavaScript, and a commercial renderer with residential addresses when the
browser gets a bot challenge.

Use it when your own page fetching returns an empty shell or a challenge page. Do not
use it for a file you already have, that is `upload` and `read`, and do not use it for
anything behind a login: it carries no credentials of yours. Only public http and
https addresses are followed.

### look
Looks at an image and answers about it, or compares two and reports what changed:
a screenshot, a photograph, a chart, a diagram, a UI. Pass `schema` and the answer
comes back as fields instead of prose.

Use it to compare two images, which no model does on its own: a visual regression
between two builds, a before and after, two revisions of the same page. Do not use
it for a document, a scan or an invoice, that is `read`, which keeps the pages and
costs less. If you can already see the image yourself, look at it there: this costs
credit and your own eyes are free.

### result
Searches and extracts from a result `read` or `listen` already produced, and reports
on one still being produced: find a term and get it back with its page or its
timestamp, pull pages 12 to 14, replay minute 9:30 to 11:00, or list who spoke when.
Free, because the work was already paid for.

Long results come back as a preview, a map and a handle rather than as the whole
text. An hour-long meeting would otherwise fill the context window and degrade every
answer given afterwards, including the ones about something else.

### cancel
Stops a background job that has not started yet and gives the reserved credit back.
Only works while the job is still waiting: once an engine has started, the cost has
already left and the job runs to the end. Free.

### account
Returns the remaining balance and the unit price of an operation. Free, never
charged.

## Is it working right now

`GET https://mcpbelt.com/status.json` answers with the engines configured for each capability,
how often each one has failed in the last day, and how long jobs are waiting to be
picked up. It needs no token and costs nothing. Read it when a call fails and you
have to decide whether to retry or to tell the person you work for.

## Prices

| Tool | Price |
|---|---|
| upload | free |
| read | from EUR 0.007 per page, EUR 0.016 in exact mode |
| read with `schema` | EUR 0.002 per page on top, and only when it returns data |
| read with `figures` | EUR 0.003 per figure described on top, capped per call |
| listen | from EUR 0.005 per minute of audio, EUR 0.008 in exact mode |
| fetch | EUR 0.007 per page fetched, EUR 0.008 in exact mode |
| look | EUR 0.005 per image looked at, so a comparison counts as two |
| result | free |
| cancel | free |
| account | free |

A digital PDF that already carries its own text is extracted locally and costs
nothing at all. A search costs nothing beyond the pages it brings back.

Prepaid credit only. There is no subscription and no per-request billing: you top up
a balance and calls draw it down. When the balance runs out the tool returns an error
that contains the exact message to relay to the person who is paying, plus a top-up
link. It does not fail silently and it does not degrade the result to fit the budget.

## Example

```
upload(filename="invoice.pdf")          -> { key, upload_url }
curl -T invoice.pdf "<upload_url>"
read(key="<key>", mode="balanced")       -> { handle, text or preview }
read(key="<key>", schema={...})          -> { handle, data }
result(handle="<handle>", tables=true)   -> one CSV link per table

upload(filename="meeting.mp3")          -> { key, upload_url }
curl -T meeting.mp3 "<upload_url>"
listen(key="<key>")                      -> { handle, preview }
fetch(url="https://example.com/docs")    -> { handle, text or preview }
fetch(search="how X works", max_pages=3) -> { handle, preview }
result(handle="<handle>", outline=true)  -> who spoke when
result(handle="<handle>", time="9:30-11:00")
```

Every result declares which engine produced it, including when a fallback engine
answered. The price does not change when the fallback runs.

## Not for you if

You need the document to stay on your machine: the file is fetched from the URL you
pass and processed on our infrastructure. You need a signed data processing agreement:
during the trial there is none.
