The MCP server

The same API, spoken over the Model Context Protocol, so an AI client can render a page itself instead of being told how to write the HTTP request. Five tools: one takes a screenshot, one prints a PDF, one reports where the account stands, and two submit and poll a batch. Underneath they are the endpoints the rest of this documentation describes, running the same validation, the same permissions, the same credits and the same cache.

Connecting a client

The server is at https://screenshotbuddy.io/mcp, over streamable HTTP. A client needs two things from you: that URL and an Authorization header carrying an API token, the same header a REST call sends. There is no OAuth step and nothing to install.

Claude Code
terminal
claude mcp add --transport http screenshotbuddy https://screenshotbuddy.io/mcp --header "Authorization: Bearer <your API key>"

Run it in the project you want the server available in. Claude Code keeps the header with the server, so the token travels on every call and never has to be repeated.

Cursor
.cursor/mcp.json
{
    "mcpServers": {
        "screenshotbuddy": {
            "url": "https://screenshotbuddy.io/mcp",
            "headers": {
                "Authorization": "Bearer <your API key>"
            }
        }
    }
}

Cursor reads .cursor/mcp.json in a project and ~/.cursor/mcp.json everywhere. Any other client that can add a remote MCP server takes the same two values under whatever it calls them, so if you can give it a URL and a header you can connect it. The agents page carries the same setup for a few more clients, and the one for a client that reads Agent Skills rather than MCP servers.

Whatever the client, commit the URL and not the token. The file that names the server is a file people share; the token is a credential that spends your credits.

The five tools

take-screenshot and create-pdf take the parameters their REST counterparts take, from the same description of the API, and are checked by the same rules: a combination refused over GET /v1/snap is refused here in the same sentence. There is no pdf switch to set, because the tool is the mode. That is also what lets each tool publish the exact range its own mode allows rather than the wider of the two.

  • Name
    take-screenshot
    Description

    Renders a publicly reachable page and hands the image back in the conversation, so the model can look at what it captured rather than read a description of it. Beside the image comes a line naming the URL, the size and the format, and saying what the render cost. Its parameters are the screenshot options.

  • Name
    create-pdf
    Description

    Prints a page and answers with a link to the rendering rather than with the file, because a PDF is far too large to travel in a tool result. The page is rendered on the call, so a failure surfaces to the agent that can act on it rather than to whoever clicks the link. Its parameters are the PDF options.

  • Name
    check-usage
    Description

    Answers with the document GET /v1/usage serves, built by the same code: credits remaining, the plan, when the period resets and both per-minute limits. It reports zero rather than refusing when the account has nothing left, which is the case it exists for. See the usage endpoint.

  • Name
    submit-render-batch
    Description

    Queues up to 20 renders in one call and answers immediately with the batch and its id, every item still queued. Nothing renders on the call and nothing is billed by it: each item is rendered in the background and billed as it would have been one at a time. An item takes the same parameters as the two rendering tools, plus pdf to make it a PDF, under the batch rules.

  • Name
    check-render-batch
    Description

    Reports where a submitted batch has got to: the document GET /v1/renders/{batch} serves, built by the same code, with a signed URL for every finished item and the machine readable reason for every failure. Polling is free the way check-usage is free, so poll a few seconds apart until the batch reports itself finished.

The link create-pdf answers with is an ordinary signed URL, minted for you rather than by you. It needs no token, so it can be opened or forwarded as it is, and it works for at most 24 hours, less when the cached copy behind it lapses first. It is signed with the signing secret of the token that called the tool, which means it carries that token's permissions and stops working the moment that token is revoked or rotated. Opening it while the copy is still cached is free; a call that turned caching off leaves nothing to serve, so opening that link renders the page again and costs another credit, and the tool says so.

A refusal comes back as the error a REST caller would have received, carrying the same machine readable code from the same published set. A model can therefore tell missing_ability, which no retry fixes, from render_timeout, which one might, without reading the English beside it. Every error code.

The token it authenticates with

The same tokens as the REST API, created in the same place: Settings, API tokens. Copy the value while it is on screen and paste it into the header above. There is deliberately no endpoint that mints a token, so an agent cannot create one for itself, and a token that expires or is rotated stops working here at the same moment it stops working everywhere else.

The two permissions narrow the tools exactly as they narrow the endpoints. A token granted screenshot and not pdf can call take-screenshot and is refused by create-pdf, with the same missing_ability the REST call answers 403 with, and the refusal happens before any credit is spent. Narrowing a token before handing it to an agent is the cheapest way to decide what it may spend your credits on.

A call with no token at all, or with one we do not recognise, never reaches a tool: the endpoint answers 401 and the client reports that it cannot connect.

What it costs

One credit per fresh render, exactly as over HTTP. An identical call repeated is answered from your cache and costs nothing, and both rendering tools say which of the two happened in the line beside their answer, so a model can tell a paid render from a free one and has a reason to reach for the cache. check-usage is free whatever it reports.

The per-minute budgets are counted in the flow both surfaces share, not per surface, so a client gets no second allowance by asking over MCP rather than over HTTP. A fresh render spends the render budget; an answer served from the cache comes out of the separate and far larger cached-answer budget instead. How the two budgets work.

The transport carries a ceiling of its own, set at the sum of those two budgets, and it exists for the calls that never reach a render at all: the protocol handshake, the tool listing, check-usage. Those cost a slot here and nothing anywhere else, which is why asking how much is left never spends a render. A client using the tools as intended meets its render budget long before the ceiling, which is only there to clip a flood.

When the capture is not the page you asked for

A login wall, a 404 page and a rate limit notice all render perfectly, so the image alone gives a model no way to tell them from the page it wanted. Over HTTP that is the X-Target-Status header. Over MCP, take-screenshot says it in words, at the end of the line that describes the capture, and only when the target answered something other than a 2xx: a sentence on every successful capture would be noise a model learns to skip, and the point of this one is that it is unusual.

Nothing about billing moves. The page the server actually served was loaded and rendered, so it costs the credit any render costs. create-pdf reports no such status, here as over HTTP, so the document itself is the only thing that says what was captured.

Batches go over the REST endpoint

The tools render one page at a time, which is what a conversation wants. A set of captures, or a page slow enough to outlast a tool call, is submitted as a batch over the REST endpoint instead: POST /v1/renders with the same bearer token. There is no batch tool on this server, so that submission is an HTTP request rather than a tool call. Batch and async renders.