---
title: "Your computer · Local MCP"
description: "Run ShotOps on your own machine with npx shotops-mcp: local screenshot paths, local rendering, and nothing but what you choose leaving the computer."
canonical: "https://shotops.dev/docs/mcp/your-computer"
last_updated: "2026-09-07"
shotops_mcp_version: "0.9.6"
result_contract_version: "2.0.0"
---
# 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](https://shotops.dev/docs/mcp/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](https://shotops.dev/docs/mcp/shotops-cloud#connect-chatgpt) 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`](https://shotops.dev/docs/mcp/reference/render_strip) or [`emit_bundle`](https://shotops.dev/docs/mcp/reference/emit_bundle) call rather than at startup, so the server connects instantly and the first render is the slow one.

> A missing browser is not a plan problem If Chromium is absent, the render fails with Playwright's own message naming the executable it could not find and telling you to run `npx playwright install`. That is a local environment failure — nothing to do with your account, your plan or your cloud credits, and it reads nothing like the store-ready refusal. [Chromium is missing](https://shotops.dev/docs/mcp/troubleshooting#chromium-is-missing) has the rest.

## 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`](https://shotops.dev/docs/mcp/reference/render_strip), [`emit_bundle`](https://shotops.dev/docs/mcp/reference/emit_bundle) and [`import_screenshot`](https://shotops.dev/docs/mcp/reference/import_screenshot), and [`emit_bundle`](https://shotops.dev/docs/mcp/reference/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`](https://shotops.dev/docs/mcp/reference/render_strip) instead and it fetches at render time. [Screenshots and assets](https://shotops.dev/docs/mcp/concepts/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`](https://shotops.dev/docs/mcp/reference/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`](https://shotops.dev/docs/mcp/reference/render_strip) and [`emit_bundle`](https://shotops.dev/docs/mcp/reference/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`](https://shotops.dev/docs/mcp/reference/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](https://shotops.dev/privacy) and [Terms](https://shotops.dev/terms).

> Zero custody, on every door ShotOps never holds an Apple or Google Play credential, here or anywhere. The bundle lands on your disk and you upload it with your own `fastlane`.

Next: [Your first strip](https://shotops.dev/docs/mcp/workflows/first-strip) runs the whole path end to end, or [Plans and output](https://shotops.dev/docs/mcp/plans-and-output) explains what separates a preview from something you can ship.
