An MCP server that fetches a web page with a real, stealth browser (a fingerprint-patched Firefox that gets through bot walls — even Google — with a real-Chrome engine as an option) and returns:
Same code as mcp-fetch-ux, fronted by a Rust edge that handles auth, queueing, and per-second billing. No LLM in the loop. No credit multipliers. JavaScript is always rendered. Stealth is always on.
pithy_live_…. No credit
card. The key is stored in your browser’s localStorage.X-Compute-Seconds, X-Charge-USD, X-Balance-USD)
inline. Cheapest way to see exactly what your agent will see.{
"mcpServers": {
"pithy": {
"type": "http",
"url": "https://pithy.bot/mcp/",
"headers": { "Authorization": "Bearer pithy_live_..." }
}
}
}
Then ask your model to fetch a page. It will call the fetch tool over MCP
and you’ll get the receipt in response headers.
When you’re ready for more than the trial, top up in $5 packs via Stripe Checkout (coming online shortly). Credits don’t expire; refundable while unused.
Want full control and zero dollars? Self-host
mcp-fetch-ux (MIT). Clone, make
server, you’ve got the same Patchright + clipboard extraction running on
localhost:5006 in five minutes. You own the box; you ship the page.
Want to ship the agent instead of the infra? Use pithy.bot. Paste the block above, mint a key, you’re fetching in seconds. Same fetch code, we run it; you ship the agent.
Both make you the one who built it. Pick the one that gets you to building faster.
https://pithy.bot/ (dev.pithy.bot points at the
same backend for staging). Signup, magic-link login, metering, queue, SSRF guard,
MCP proxy — all live. Stripe top-ups come next.
One thing: an Authorization header carrying a bearer token.
Authorization: Bearer pithy_live_<32 hex chars>
Keys are scoped to a single bowl (your balance). A request with no key returns 401. A request with an unknown key returns 401. A request whose key has less than $0.003 in its bowl returns 402 — we won’t start a fetch we might not be paid for, since the per-fetch cap is $0.003.
One tool: fetch. Same shape over MCP and over the direct HTTP API.
| name | type | default | description |
|---|---|---|---|
| url | string | required | http or https URL to fetch. |
| actions | array | none | Actions to perform after the page loads. See Actions. |
| max_length | int | 50000 | Maximum characters to return. |
| start_index | int | 0 | Resume from this character index (pagination). |
| raw | bool | false | Return raw HTML instead of clipboard text. |
curl -X POST https://pithy.bot/fetch \
-H "Authorization: Bearer pithy_live_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://en.wikipedia.org/wiki/Octopus"}'
{
"content": "Contents of https://en.wikipedia.org/wiki/Octopus:\nTitle: Octopus - Wikipedia\n\nAn octopus (pl.: octopuses or octopodes...\n\n---\nAvailable actions on this page:\n - click: \"a:has-text('Edit')\"\n - fill: \"input[name='search']\"\n ..."
}
The first call returns the page text and the list of available buttons / inputs
on it. Your agent picks one and calls back with an actions array:
{
"url": "https://www.roche.com/solutions/pipeline",
"actions": [
{"action": "click", "selector": "button:has-text('Download current view as CSV')"}
]
}
| action | params | example |
|---|---|---|
| click | selector | {"action":"click","selector":"text=Download CSV"} |
| fill | selector, value | {"action":"fill","selector":"input[name=q]","value":"octopus"} |
| wait | selector or timeout (ms) | {"action":"wait","selector":".results"} |
| select | selector, value | {"action":"select","selector":"select#lang","value":"en"} |
| scroll | direction | {"action":"scroll","direction":"bottom"} |
Actions run sequentially. If a click triggers a file download (CSV, PDF, etc.), the file
contents come back in content instead of the page text. PDFs are converted to
text via pdftotext; other binaries return a curl command your agent can use to
save the file locally.
Selectors are Playwright locators. CSS
by default; selectors starting with / are treated as XPath.
The body is always JSON with a single content string. The receipt lives in
response headers:
| header | meaning |
|---|---|
| X-Queue-Wait-Ms | How long the request sat in the queue before a Chromium opened up. Not billed. |
| X-Compute-Seconds | Actual Chromium work time. Billed. Capped at 30.000. |
| X-Charge-USD | What you paid for this fetch, six decimal places. |
| X-Balance-USD | What’s left in your bowl after this fetch. |
| X-Gruel-Served-USD | Same as X-Charge-USD. We had to. |
Per second of Chromium time:
$0.000092 / second (Daytona medium-equivalent × 2) capped at $0.003 per fetch (the 30-second timeout) rounded up to next microdollar
| fetch shape | elapsed | charge |
|---|---|---|
| simple (Wikipedia, blog) | ~5s | $0.000460 |
| JS-heavy (SPAs, Shadow DOM) | ~10s | $0.000920 |
| with actions (click + download) | ~15s | $0.001380 |
| worst case (30s cap) | 30s | $0.002760 |
Queue time isn’t billed. Only the seconds Chromium actually spent on your page. Failed fetches aren’t billed either — if the worker returns an error, your bowl is not touched.
Top-ups via Stripe Checkout in $5 / $20 / $50 packs. Credits don’t expire. Refundable while unused.
JSON errors carry a please_sir field. The status code tells your tooling
what to do; the body tells you the why.
| status | body | why |
|---|---|---|
| 401 | {"please_sir": "no key — buy gruel at pithy.bot"} | No Authorization header. |
| 401 | {"please_sir": "unknown key — sign up at pithy.bot"} | Key not recognised. |
| 402 | {"please_sir": "may I have some more? balance ..."} | Balance below the $0.003 per-fetch cap. Top up. |
| 429 | {"please_sir": "you have too many in flight already; ..."} | Per-key cap hit (max 2 in flight / queued per key). |
| 429 | {"please_sir": "the workhouse is full; ..."} | Global queue full after 30s wait. Retry shortly. |
| 502 | {"please_sir": "the kitchen is unwell; ..."} | Worker error. You are not charged. |
| 404 | {"please_sir": "that page doesn’t exist."} | Wrong route. |
claude mcp add pithy --transport http https://pithy.bot/mcp/ \ --header "Authorization: Bearer pithy_live_..."
Or edit ~/.claude.json directly with the JSON block above.
Add to your project’s .cursor/mcp.json (or User Settings → MCP):
{
"mcpServers": {
"pithy": {
"type": "http",
"url": "https://pithy.bot/mcp/",
"headers": { "Authorization": "Bearer pithy_live_..." }
}
}
}
Same JSON. Streamable HTTP transport, Authorization header for auth. If
your client only supports stdio, run mcp-fetch-ux locally instead and skip the
hosted service.
Pithy means concise and forcefully expressive. The clipboard capture strips the page to its visible text. The metering returns the bill in the response headers. The pricing fits on one line. The name fits.
Every new signup gets a $0.10 trial — about 100 typical fetches, no credit card. Beyond that, top up in $5 packs ($0.000092/sec, ~$0.001 per typical 10 s fetch, $5 covers ~5,400 fetches). No monthly minimum, no subscription. Credits don’t expire.
Max 3 Chromiums concurrently (hard limit). Max 2 in-flight + queued per key. Past that,
you get a 429 with Retry-After. No request waits more than ~30 seconds in the
queue.
The host portion of each URL is logged in your usage table for billing
receipts (e.g. en.wikipedia.org). Path, query, response body, and rendered
content are not stored. We don’t train on, sell, or share your
traffic.
No. The service runs from a residential ISP in Darien, CT. Patchright handles bot detection on the page-script side; we don’t rotate IPs. Sites that geofence away from the US East coast will see a US East coast residential IP.
Two pieces, dual-source.
The open-source MCP library is mcp-fetch-ux (MIT) —
same Patchright + clipboard extraction the hosted service runs, but you can clone it,
make server, and have it on localhost:5006 in five minutes. Free, no signup.
pithy.bot is the managed version: auth, queueing, billing, hosting — that wrapper is closed source.