How to add a screenshot tool to Claude Code
Claude Code can't see a web page until a tool hands it an image. One command adds Shotkiln's remote MCP server, and the agent can capture any public URL, full page or phone-sized, then look at the result. Here's the setup we tested, prompts to try, and the errors you might hit.
Setup in one command
Run claude mcp add with --transport http, a name and https://shotkiln.com/mcp. Claude Code then has three tools: take_screenshot, render_pdf and generate_og_image. It works without a key on small anonymous limits. Add an x-api-key header to use your plan, then check the connection with claude mcp list.
# No key: anonymous limits, watermarked
claude mcp add --transport http shotkiln https://shotkiln.com/mcp
# With your key
claude mcp add --transport http shotkiln https://shotkiln.com/mcp --header "x-api-key: $SHOTKILN_KEY"Checking MCP server health…
shotkiln: https://shotkiln.com/mcp (HTTP) - ✔ ConnectedYour shell fills in $SHOTKILN_KEY when you run the command, and Claude Code stores the value in ~/.claude.json. Restart a running session to pick up the new tools.
This project, every project, or your team
claude mcp add takes a --scope. The default, local, adds the server for you in the current project only.
| Scope | Who gets it | Stored in |
|---|---|---|
local (default) | You, in this project | ~/.claude.json |
user | You, in every project | ~/.claude.json |
project | Everyone who clones the repo | .mcp.json in the repo |
For a team, commit an .mcp.json that reads the key from each person's environment, so no key lands in git:
{
"mcpServers": {
"shotkiln": {
"type": "http",
"url": "https://shotkiln.com/mcp",
"headers": { "x-api-key": "${SHOTKILN_KEY}" }
}
}
}Claude Code asks each person to approve a project server the first time; until then claude mcp list shows it as pending. If the variable isn't set, Claude Code warns Missing environment variables: SHOTKILN_KEY.
Prompts to try
You don't name the tool. Ask for what you want and Claude Code picks the tool and the arguments:
| You ask | Tool call |
|---|---|
| Take a full-page screenshot of example.com at phone width and tell me what's above the fold. | take_screenshot with width: 390, height: 844, full_page: true |
| Screenshot our pricing page in dark mode at 2x and check the table is readable. | take_screenshot with dark_mode: true, device_scale_factor: 2 |
| Compare the hero of these three competitor sites and list what each one promises. | three take_screenshot calls |
| Save this docs page as an A4 PDF. | render_pdf with format: "A4" |
| Make a social card titled "Release 2.4" for acme.dev. | generate_og_image |
Each screenshot comes back as an image plus one line of status. A phone-width capture of example.com returned a 78 KB PNG and this text:
screenshot rendered (77751 bytes, cache HIT, quota remaining 60, free-plan watermark).The model reads the picture, not the page's HTML. Instructions hidden in the page text don't reach it as text, which matters when the agent visits sites you don't control.
Tool arguments
These come from the server's own tools/list response. All three tools are marked read-only.
| Tool | Arguments and defaults |
|---|---|
take_screenshot | url (required), width 320 to 3,840 (1280), height 200 to 3,840 (800), full_page (false), scroll (true, full page only), format png, jpeg or webp (png), delay up to 10,000 ms, device_scale_factor 1 to 3, dark_mode |
render_pdf | url or html (up to 1 MB), format A3 to Tabloid (A4), landscape, margin (10mm), print_background (true) |
generate_og_image | title (required), subtitle, template default, split or gradient, theme light or dark, accent, site |
Full pages stop at 16,384 px. Before a full-page capture the server scrolls through the page so lazy images load, and the scroll argument turns that off. The Puppeteer guide explains why it's needed.
Remote screenshot server or a local browser
Local browser servers such as Microsoft's Playwright MCP drive a browser on your machine. They can open localhost, use your logins, click and read page text. The price is a browser to install and keep running, and an agent that can reach anything your machine can.
Shotkiln runs remotely, so there's nothing to install and nothing on your network it can reach: private, loopback and cloud metadata addresses are refused on every request and redirect. That also means it can't capture your dev server on localhost:3000. Use a local browser server for that, and Shotkiln for public pages, deploy previews on public URLs, PDFs and OG cards. Many setups use both.
When it doesn't connect
| You see | What it means | Fix |
|---|---|---|
✘ Failed to connect — Dynamic Client Registration rejected (HTTP 405) | The server turned down the key with a 401, so Claude Code tried an OAuth sign-in instead. Shotkiln uses API keys, not OAuth. | Check the key in the header, then remove the server and add it again. Without the header it connects on the anonymous limits. |
⏸ Pending approval | A project server from .mcp.json nobody has approved on this machine yet | Start claude in the repo and approve it |
Missing environment variables: SHOTKILN_KEY | .mcp.json refers to a variable your shell doesn't have | Export it in the shell that starts Claude Code |
| A rate-limit error from the tool | Anonymous use allows 3 captures a minute and 10 a day per network | Add a free key |
We hit the first one in testing by passing a placeholder instead of a real key. With the real key, and with no header at all, claude mcp list showed ✔ Connected.