A small Swift binary that does one thing — take a screenshot of a display, a window, or a region — and exposes it through two interfaces. As a CLI for terminal use, and as a Model Context Protocol server so Claude (Code, Desktop, Cursor) can see your screen and ask follow-up questions about what’s there. Captures come back to the model as inline image content; no temporary files, no path round-trips.
Built on ScreenCaptureKit, the modern macOS capture API. Single Swift package, one external dependency (swift-argument-parser). MIT licensed.
Why this exists
Working with Claude on UI is the obvious case. The model can read the code and predict what should render, but only a screenshot tells you what actually renders. Before Peek, that gap was filled by manually screenshotting, copying into the conversation, describing context. Now the model just calls capture_window and gets the answer.
Beyond UI work, the same primitive is useful for asking the model to read what’s on screen — Obsidian, a Figma frame, a browser tab, a PDF in Preview — without leaving the terminal.
Capabilities
The MCP server advertises five tools:
| Tool | Args | Returns |
|---|---|---|
list_windows | include_offscreen? | JSON list |
list_displays | — | JSON list |
capture_window | window_id or app_name, plus hide_cursor?, force?, format? | inline image |
capture_display | display_id?, hide_cursor?, format? | inline image |
capture_region | x, y, width, height, display_id?, hide_cursor?, format? | inline image |
The CLI mirrors the same surface: peek windows, peek displays, peek window <app>, peek display, peek region. PNG by default; JPEG via --format or environment.
Quality presets
Lossless PNG is the default — sharp UI text, no JPEG artifacts — at the cost of larger responses. For interactive use where speed matters more than fidelity, the PEEK_QUALITY environment variable swaps presets:
fast— JPEG q=0.5, 768 px cap, ~80 KB per capturebalanced— JPEG q=0.7, 1024 px cap, ~150 KBlossless— PNG, 2048 px cap, ~1 MB (default)
Per-call overrides via the format argument supersede the preset.
Install + setup
brew install richardsummerville/tap/peek
peek install # wires Peek into Claude Code and Claude Desktop config
peek install writes the right mcpServers entry into ~/.claude.json and Claude Desktop’s config file. After that, restart the Claude host fully (Cmd-Q + reopen) and grant Screen Recording permission to the host application — not to the Peek binary itself, since ScreenCaptureKit checks the launching process.
peek doctor runs a diagnostic that reports permission status, host configuration, and the active quality preset, with a --open-settings flag that jumps straight to the Privacy panel.
Audit and observability
Every capture (CLI or MCP) is logged as a JSONL entry under the user’s data directory — useful when an agent has been running unattended and you want to see what it actually saw. A menu-bar status item shows the last capture, the five most recent, and a shortcut to the audit log.
peek log tail, peek log tail -n 100, peek log path, peek log clear --yes are the relevant CLI commands.
Implementation notes
- Single Swift package — no Xcode project file.
make installbuilds release and copies to/usr/local/bin. Homebrew formula is the recommended path. - A small deny-list (1Password, Keychain Access, Authy, etc.) blocks window captures of sensitive apps by default;
force: trueoverrides per call. - TCC quirks around Homebrew binaries are handled in
peek doctor— when macOS treats the brewed binary as a distinct TCC subject, the diagnostic prints the exact resolution steps. - The MCP transport is stdio. The same binary serves the CLI and the MCP server; mode is selected by command (
peek servefor MCP).