npm package: @misterhuydo/eyeshot-mcp
Description: MCP server that gives Claude Code visual awareness and Chrome profile control — desktop screenshot + Chrome profile launcher.
Latest version: 2.0.0

# eyeshot

A lightweight [MCP](https://modelcontextprotocol.io) server that gives Claude Code visual awareness and Chrome profile control.

eyeshot works **alongside** other browser automation tools (chrome-devtools MCP, Browser MCP, Playwright MCP) rather than replacing them. It fills the gaps those tools can't: desktop screenshots, scrolling native windows, and launching isolated Chrome test profiles.

---

## Tools

| Tool | Description |
|------|-------------|
| `screenshot` | Capture the desktop or a specific window by title |
| `scroll` | Scroll a window by title and return a screenshot of the new position |
| `list_profiles` | List all eyeshot-managed test Chrome profiles |
| `create_test_profile` | Create a named, isolated Chrome test profile |
| `launch_profile` | Launch Chrome with a test profile on port 9222 |
| `clear_test_profile` | Wipe browsing data from a test profile |
| `delete_test_profile` | Permanently delete a test profile |

---

## Installation

**Requirements:** Node.js 18+

```bash
npm install -g @misterhuydo/eyeshot-mcp
eyeshot install
```

That's it. `eyeshot install` registers the MCP server in `~/.claude.json`.

Restart Claude Code once after running this — required for the MCP server to load.

**Upgrade:**

```bash
npm install -g @misterhuydo/eyeshot-mcp
```

No need to re-run `eyeshot install` — the config carries over between versions.

---

## Tool reference

### `screenshot(title?)`

Takes a screenshot and returns it as an image to Claude.

- **`title`** _(optional)_ — partial window title to capture (e.g. `"slack"`, `"chrome"`). Case-insensitive. If omitted, captures the full desktop.

Platform notes:
- **Windows** — uses `PrintWindow` (Win32 API), captures the window even if it's behind other windows
- **macOS** — uses `screencapture -l <window-id>` via Quartz
- **Linux X11** — uses `import` (ImageMagick) or `xwd`
- **Linux Wayland** — always falls back to full desktop screenshot

---

### `scroll(title, direction?, amount?)`

Scrolls a window by title, then returns a screenshot of the new position. Useful for reading long Slack threads, terminals, or any content that runs off-screen.

- **`title`** _(required)_ — partial window title (e.g. `"slack"`, `"terminal"`)
- **`direction`** _(optional)_ — `"down"` (default) or `"up"`
- **`amount`** _(optional)_ — scroll steps, 1–20 (default `3`)

Platform notes:

| Platform | Mechanism | Requirements |
|----------|-----------|--------------|
| Windows | `WM_MOUSEWHEEL` via PostMessage | None — no focus needed |
| macOS | Quartz `CGEventCreateScrollWheelEvent` | `python3` with Quartz; [Accessibility permission](#macos-accessibility-permission) |
| Linux X11 | `xdotool click` (buttons 4/5) | `xdotool` installed |
| Linux Wayland | Not supported | — |

> **Electron/Chrome app caveat:** OS-level scroll events may not reach Electron's rendering layer (Slack, VS Code, Chrome). For browser content, use `chrome-devtools` MCP's `evaluate_script` with `window.scrollBy()` instead.

#### macOS Accessibility permission

The first time `scroll` runs on macOS, you'll need to grant Accessibility access to the terminal or app running Claude Code:

**System Settings → Privacy & Security → Accessibility** → add your terminal.

---

### `list_profiles`

Lists all eyeshot-managed test Chrome profiles. Real user profiles are never shown or touched.

---

### `create_test_profile(name)`

Creates a named, isolated Chrome profile stored under a dedicated eyeshot user data directory — completely separate from your real Chrome profiles.

- **`name`** — alphanumeric name, hyphens and underscores allowed (e.g. `"payments-ui"`, `"staging"`)

---

### `launch_profile(profile)`

Launches Chrome with a test profile on `--remote-debugging-port=9222` so the chrome-devtools MCP can connect.

- **`profile`** — test profile name (e.g. `"payments-ui"`) or full directory (e.g. `"eyeshot-payments-ui"`)
- Only kills the process already bound to port 9222, never all Chrome instances

---

### `clear_test_profile(name)`

Wipes all browsing data (cookies, cache, history, storage) from a test profile while keeping the profile shell. Pass `"all"` to clear every test profile.

---

### `delete_test_profile(name)`

Permanently deletes a test profile directory. Pass `"all"` to delete every test profile.

---

## Architecture

```
eyeshot MCP
  ├── screenshot / scroll    → OS-level window capture & input
  ├── list/create_test_profile → isolated Chrome profile management
  └── launch_profile         → spawns Chrome with --remote-debugging-port=9222

chrome-devtools MCP (separate)
  └── connects to Chrome on port 9222 (whatever profile eyeshot launched)
```

---

## Tech stack

- **Runtime:** Node.js (ESM)
- **MCP SDK:** `@modelcontextprotocol/sdk`
- **Schema:** `zod`
- **Windows screenshot/scroll:** PowerShell + Win32 API (no extra deps)
- **macOS screenshot/scroll:** `screencapture` + Python Quartz framework
- **Linux screenshot/scroll:** ImageMagick / `xwd` + `xdotool`