Start
Your computer · Local MCP
Run ShotOps on your own machine with npx shotops-mcp: local screenshot paths, local rendering, and nothing but what you choose leaving the computer.
The same server, the same tool contract and the same render engine as ShotOps Cloud — running as a process on your machine, over stdio. Your screenshots are read off your disk, the renders happen on your CPU, and an ordinary render or export uploads nothing.
#Connect Claude Code
The preferred path is one command. Claude Code saves the Local MCP entry, starts the server when it
is needed, and lets npx fetch the package the first time:
claude mcp add shotops -- npx -y shotops-mcp
Then ask the agent for something and it connects on demand. To check the package is reachable before you wire a client to it:
npx -y shotops-mcp help
That prints the subcommands and exits. A bare npx shotops-mcp with no subcommand starts the MCP
server and speaks JSON-RPC on stdout — useful to a client, unreadable to you.
Node 20.12 or newer is required.
#Connect Cursor or another client
Any client that can start a subprocess can run this server. The three things a client needs are the command, the arguments, and nothing else — no URL, no header, no token.
For Cursor or any client with a JSON config, use the standard stdio entry:
{
"mcpServers": {
"shotops": {
"command": "npx",
"args": ["-y", "shotops-mcp"]
}
}
}
ChatGPT cannot use this door. Its connectors speak HTTP to a URL and have no way to start a local process. Use ShotOps Cloud instead.
#Chromium
The renderer draws the device mockups in a real browser, so it needs Playwright's Chromium — about 150 MB, which is why it is not inside the npm package.
Whether it arrives on its own depends on your package manager: Playwright's install script fetches it, and some setups block install scripts by default. Install it explicitly and the question goes away:
npx playwright install chromium
Chromium boots lazily, on the first render_strip or
emit_bundle call rather than at startup, so the server connects instantly and the
first render is the slow one.
#Point at screenshots on disk
This is the reason to run locally. A screenshot entry can be a path, and the server reads the file directly:
{
"screenshots": [
{ "path": "/Users/you/screens/01_today.png" },
{ "path": "/Users/you/screens/02_forecast.png" }
]
}
No upload, no ref, no round trip. { "path": … } works on render_strip,
emit_bundle and import_screenshot, and
emit_bundle takes already-rendered panels the same way, so you can render in one
call and package in another with nothing leaving the machine.
The path form is local only. ShotOps Cloud refuses it outright and says so: reading a
caller-supplied filesystem path on a shared host would be a local-file-inclusion hole. The mirror is
also true — { "url": … } and ChatGPT attachments are refused here, because there is no account
storage to import them into. Pass a URL straight to render_strip instead and it
fetches at render time. Screenshots and assets covers each input
form.
#Sign in (optional)
Previewing needs no account at all. Signing in connects this machine to a ShotOps account so the account-shaped tools work — saved looks, existing projects, project reads and re-renders — and so store-ready output has an entitlement to check. Rendering still runs here and still spends no cloud credits.
npx shotops-mcp login # opens ShotOps in your browser, saves the token it gets back
npx shotops-mcp whoami # which account is connected, and its plan
npx shotops-mcp logout # revokes that token and removes it from this machine
The token lands in ~/.shotops/credentials.json, readable only by you, and every later
npx shotops-mcp picks it up — there is nothing to paste into a client config. It is an ordinary
ShotOps API token; revoke it any time from the account menu in Studio.
For CI, or to point one client at a different account, pass the token explicitly:
SHOTOPS_TOKEN=shotops_… claude mcp add shotops -- npx -y shotops-mcp
--token wins over SHOTOPS_TOKEN, which wins over a saved browser login — so a token in the
environment is never quietly shadowed by whoever last signed in on this machine.
Without any token, save_project still has a route: a new project made from local
paths uploads that project's record and its source PNGs as a private pending claim and returns an
openUrl instead of a project id. One browser sign-in through that link and the project is yours,
screenshots included. An unclaimed link expires after seven days. Updating an existing project
needs the token that owns it.
#What leaves your machine
Ordinary renders and exports upload nothing. render_strip and
emit_bundle read your PNGs, run Chromium here, and write the panels and the zip
back — no screenshot bytes go anywhere.
Four things do reach the network, and each is something you asked for:
| What | When |
|---|---|
| The npm package and Chromium | Install time, from the registry and from Playwright's CDN |
| Your account token | npx shotops-mcp login, once, in your browser |
| A project record and its source PNGs | Only on save_project — a deliberate save, so the project can reopen in a browser on another device |
| The image at a URL you passed | Only when you hand a render an https:// screenshot instead of a path |
refine_project is the one further exception: it runs the agent turn here and
renders here, but asks ShotOps' servers to run each AI pass, so it spends AI cloud credits on your
account.
Share links need the hosted connection. What ShotOps stores when it does store something, and for how long, is in Privacy and Terms.
Next: Your first strip runs the whole path end to end, or Plans and output explains what separates a preview from something you can ship.