Reliable clipboard image paste for Claude Code in iTerm2
Quick Start • How It Works • Tools • Config • Troubleshooting
An MCP server that gives Claude Code reliable access to clipboard images and screenshots. A background Swift daemon watches the clipboard in real time, so screenshots from any app — including clipboard-only tools like Shottr — are captured automatically and available instantly.
Built to fix the broken Ctrl+V image paste in iTerm2 and Terminal.app when using Claude Code. Should also work with any MCP-compatible client (Cursor, Claude Desktop, etc.).
Warning
Pasting images into Claude Code via Ctrl+V in iTerm2 is unreliable and often fails completely.
These are real, open issues:
| Issue | What happens |
|---|---|
| claude-code#29776 | Ctrl+V image paste fails silently — "No image found in clipboard" |
| claude-code#17042 | sandbox-exec blocks clipboard access via com.apple.hiservices-xpcservice |
| claude-code#29365 | Ctrl+V image paste in iTerm2 intermittently fails (still reproducible) |
| claude-code#1361 | "Can't paste image from clipboard" (various causes) |
Similar problems exist in other terminal AI tools: Codex CLI, Gemini CLI. The root cause is that terminals have no reliable protocol for transferring binary image data from the macOS clipboard.
|
A lightweight Swift daemon polls |
Parallel search across clipboard watcher dir, native macOS screenshots dir, and Spotlight. Three sources — the newest image wins. |
|
MCP servers run outside |
Auto-resize to optimal AI vision dimensions (1568px). Saves tokens without losing detail. PNG or JPEG output. |
git clone https://github.com/zelentsov-dev/clipsnap-mcp.git ~/.clipsnap-mcp
cd ~/.clipsnap-mcp
npm install
npm run build # TypeScript + Swift clipboard watcher
npm install -g . # install globally (symlinks to this directory)Important:
npm install -g .creates a symlink to the cloned directory — do not delete it.npm install -g git+https://...does not work because the package requires a build step.
claude mcp add --scope user --transport stdio clipsnap -- clipsnap-mcpThis registers ClipSnap globally across all your projects. Verify with:
claude mcp listThen restart Claude Code. Now when you say "look at my screenshot" or "check what I just captured", Claude Code will use ClipSnap to find your images.
cd ~/.clipsnap-mcp
git pull
npm install # if dependencies changed
npm run buildThe global clipsnap-mcp binary is a symlink to ~/.clipsnap-mcp, so it picks up changes automatically. Restart Claude Code after updating.
claude mcp remove clipsnap --scope user
npm uninstall -g clipsnap-mcp
rm -rf ~/.clipsnap-mcp1. Claude Code starts
└── MCP server starts
└── Swift clipboard watcher spawns as background daemon
2. User takes screenshot (any app: native, Shottr, CleanShot X, browser, etc.)
└── Clipboard gets image
└── Watcher detects NSPasteboard change within ~500ms
└── Saves PNG to ~/.clipsnap/clipboard-captures/
3. User: "look at my screenshot"
└── Claude Code calls paste_recent tool
└── Parallel search:
├── Watcher captures dir (clipboard images, instant)
├── Native screenshots dir (file-saved screenshots, instant)
└── Spotlight mdfind (broad coverage, all apps)
└── Merge, dedup, sort by time → return newest N as base64 images
4. Claude Code exits
└── SIGTERM → watcher stops → session files cleaned up
Architecture Diagram
graph TD
A["Claude Code"] -->|MCP stdio| B["ClipSnap MCP Server<br/>(Node.js)"]
B -->|spawns on start| C["Swift Clipboard Watcher"]
C -->|polls NSPasteboard<br/>every 500ms| D["~/.clipsnap/clipboard-captures/"]
B -->|scans| D
B -->|scans| E["Native Screenshots Dir"]
B -->|queries| F["Spotlight mdfind"]
D & E & F -->|merge + dedup<br/>sort by time| G["Return newest N images"]
A -->|SIGTERM on exit| C
Returns the most recent N screenshot images. Combines clipboard watcher captures, native macOS screenshots directory, and Spotlight. Sorted by time, newest first.
| Parameter | Type | Default | Description |
|---|---|---|---|
count |
number (1–10) |
3 |
Number of images to return |
folder |
string |
— | Scan a specific folder instead |
max_dimension |
number |
1568 |
Max long edge in pixels |
Example prompts: "Look at my screenshot", "Compare the last 4 screenshots", "Check what I just captured"
Deletes temporary ClipSnap session images. Auto-cleanup runs on TTL/size limits, so this is rarely needed.
| Parameter | Type | Default | Description |
|---|---|---|---|
all |
boolean |
false |
Delete ALL sessions, not just current |
older_than_minutes |
number |
— | Delete files older than N minutes |
All settings via environment variables:
| Variable | Default | Description |
|---|---|---|
CLIPSNAP_MAX_DIMENSION |
1568 |
Max image long edge (px) |
CLIPSNAP_IMAGE_FORMAT |
png |
Output format (png or jpeg) |
CLIPSNAP_JPEG_QUALITY |
80 |
JPEG quality (1–100) |
CLIPSNAP_SCREENSHOTS_DIR |
auto | Native screenshots dir (auto-detected via defaults read com.apple.screencapture) |
CLIPSNAP_MAX_FILES |
50 |
Max files per session |
CLIPSNAP_TTL_MINUTES |
60 |
File time-to-live |
CLIPSNAP_MAX_SIZE_MB |
200 |
Max total session size |
CLIPSNAP_CHECK_CONCEALED |
true |
Detect passwords before reading clipboard |
CLIPSNAP_CLEANUP_ON_EXIT |
true |
Delete session files on exit |
Claude calculates image tokens as (width x height) / 750:
| Image Size | Tokens | Cost (Sonnet, $3/1M input) |
|---|---|---|
| 1568x882 (16:9) | ~1,841 | $0.006 |
| 1568x1024 | ~2,141 | $0.006 |
| 800x600 (snippet) | ~640 | $0.002 |
- Password detection — checks
ConcealedType/TransientTypebefore reading (1Password, Bitwarden, macOS Keychain) - Symlink protection —
lstatprevents following symlinks to sensitive files - File permissions —
0600files,0700directories - Session isolation — UUID-based subdirs per process (
$TMPDIR/clipsnap-<uuid>/) - No content logging — clipboard data is never logged
- No network calls — fully offline, zero telemetry
Built and tested with Claude Code on iTerm2 on macOS.
Since ClipSnap is a standard MCP server (stdio transport), it should work with any MCP-compatible client — Cursor, Claude Desktop, Windsurf, etc. — but these haven't been tested yet. If you try it, let us know.
Requirements:
- macOS 15+ (Sequoia or later)
- Node.js 20+
- Swift 6.2+ (for building the clipboard watcher; optional)
Watcher not capturing clipboard images
The Swift watcher binary must be built:
npm run build # or: cd watcher && swift build -c releaseIf the binary is missing, ClipSnap still works via Spotlight and native dir scanning — just without real-time clipboard capture.
"No recent images found"
Take a screenshot or copy an image first:
Cmd+Shift+4(region) orCmd+Shift+3(full screen)Cmd+Con an image in Preview, Figma, browser- Shottr, CleanShot X, or any screenshot tool
"Clipboard contains concealed data"
Your clipboard contains a password (1Password, Bitwarden, etc.). ClipSnap refuses to read it for security. Copy a screenshot instead.
Screenshots directory not found
ClipSnap auto-detects from defaults read com.apple.screencapture location, falling back to ~/Screenshots or ~/Desktop. Override with CLIPSNAP_SCREENSHOTS_DIR.
Contributions welcome! Please open an issue before starting work on large changes.
Built by Aleksei Zelentsov