A Docker-based MCP (Model Context Protocol) server that enables Claude Code to fetch and view screenshots from your Desktop using a simple #snip notation.
SnipMCP solves the friction of sharing screenshots with Claude Code. Instead of manually copying paths or dragging files, simply:
- Take a screenshot with macOS (
Cmd+Shift+4orCmd+Shift+3) - Reference it in your prompt with
#snip - Claude sees the image instantly
You: "Look at #snip - why is this CSS not centering?"
Claude: [views your screenshot] "The issue is..."
- Simple notation:
#snipfor latest,#snip0/#snip1/#snip2for multiple - Native image support: Returns images Claude can view directly (not base64 text)
- Docker-based: Isolated, reproducible, auto-restarts on boot
- Fallback support: Works even if MCP server is down (via direct file read)
- Health monitoring: Hook warns you if the server isn't running
cd ~/Documents/Github/SnipMCP
docker compose up -dclaude mcp add --transport sse snip http://localhost:3001/sse --scope userAdd to ~/.claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "#snip",
"hooks": [
{
"type": "command",
"command": "bash ~/Documents/Github/SnipMCP/hooks/snip-check.sh"
}
]
}
]
}
}Add to ~/.claude/CLAUDE.md for automatic recognition:
## Screenshot Reference System (#snip)
When you see `#snip` or `#snipN` in a prompt, use the SnipMCP server's
`screenshot` tool to fetch the referenced screenshot(s) from the Desktop.
- `#snip` = most recent screenshot
- `#snip0`, `#snip1`, `#snip2` = multiple screenshots (0=oldest, N=newest)tell me about #snip
| Notation | Meaning |
|---|---|
#snip |
The most recent screenshot on Desktop |
When you reference multiple screenshots in one prompt, they're numbered by age within that set:
| Notation | Meaning |
|---|---|
#snip0 |
Oldest of the referenced screenshots |
#snip1 |
Second oldest |
#snip2 |
Third oldest (most recent if 3 total) |
Example: If you take 3 screenshots and say:
"Compare #snip0 with #snip2"
#snip0= first screenshot you took#snip2= last screenshot you took
Fetch screenshot(s) from the Desktop.
Parameters:
index(string, default:"latest"):"latest"- most recent screenshot"0"- single indexed screenshot"0,1,2"- multiple screenshots
Returns: Image content that Claude can view directly.
Examples:
screenshot(index="latest") # Most recent
screenshot(index="0") # Oldest of set
screenshot(index="0,1,2") # Three screenshots
List available screenshots on the Desktop.
Parameters:
limit(int, default:10): Maximum screenshots to list
Returns: Text listing of available screenshots with indices.
Check server health and screenshot availability.
Returns: Health status string.
┌──────────────────────────────────────────────────────────────┐
│ macOS Host │
│ │
│ ~/Desktop/ │
│ ├── Screenshot 2025-12-20 at 10.02.15 PM.png │
│ ├── Screenshot 2025-12-20 at 10.02.22 PM.png │
│ └── Screenshot 2025-12-20 at 10.02.31 PM.png │
│ │ │
│ │ (read-only volume mount) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Docker: snip-mcp │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ Python MCP Server (FastMCP) │ │ │
│ │ │ - screenshot() tool │ │ │
│ │ │ - list_screenshots() tool │ │ │
│ │ │ - health() tool │ │ │
│ │ │ - SSE transport on 0.0.0.0:8000 │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ │ :8000 │ │
│ └──────────────┼──────────────────────────────────────┘ │
│ │ │
│ │ :3001 (port mapping) │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Claude Code │ │
│ │ - MCP client connects via SSE │ │
│ │ - Receives native Image content │ │
│ │ - Falls back to Read tool if MCP unavailable │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
The hook configuration warns you if the MCP server isn't running:
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "#snip",
"hooks": [
{
"type": "command",
"command": "bash ~/Documents/Github/SnipMCP/hooks/snip-check.sh"
}
]
}
]
}
}Added automatically by claude mcp add:
{
"mcpServers": {
"snip": {
"type": "sse",
"url": "http://localhost:3001/sse"
}
}
}Teaches Claude to recognize #snip notation:
## Screenshot Reference System (#snip)
When the user mentions `#snip` or `#snipN` in their prompt,
use the SnipMCP server's `screenshot` tool.
- `#snip` = screenshot(index="latest")
- `#snip0`, `#snip1`, `#snip2` = screenshot(index="0,1,2")- Open Docker Desktop
- Go to Settings → General
- Enable "Start Docker Desktop when you sign in"
The docker-compose.yml includes restart: always, so the container starts automatically when Docker starts.
~/Documents/Github/SnipMCP/
├── Dockerfile # Python 3.12 slim image
├── docker-compose.yml # Container config with volume mount
├── server.py # FastMCP server implementation
├── requirements.txt # Python dependencies
├── hooks/
│ └── snip-check.sh # Availability warning hook
├── README.md # This file
└── .gitignore
-
Screenshot Detection: macOS saves screenshots to Desktop as
Screenshot YYYY-MM-DD at H.MM.SS AM/PM.png -
Volume Mount: Docker mounts
~/Desktopread-only to/desktopinside the container -
File Discovery: Server uses
globto findScreenshot*.pngfiles, sorted by modification time -
Image Return: Uses FastMCP's
Image(data=bytes, format="png")to return native image content -
Claude Viewing: Claude Code receives the image and can analyze it directly (like the Read tool with images)
# Check if container is running
docker compose ps
# Check container logs
docker logs snip-mcp
# Restart the container
docker compose restartThe server might not be bound to the right interface:
# Check the logs show 0.0.0.0:8000
docker logs snip-mcp | grep "Uvicorn running"
# Should show: Uvicorn running on http://0.0.0.0:8000# Check if Desktop is mounted
docker compose exec snip-mcp ls /desktop
# Check screenshot pattern
docker compose exec snip-mcp ls /desktop/Screenshot*.png# Find what's using the port
lsof -i :3001
# Change the port in docker-compose.yml
ports:
- "3002:8000" # Use a different host port
# Update MCP registration
claude mcp remove snip
claude mcp add --transport sse snip http://localhost:3002/sse --scope userThis was fixed in v1.0. If you're seeing base64 JSON instead of images:
# Pull latest and rebuild
git pull
docker compose down
docker compose build --no-cache
docker compose up -d# Create virtual environment
python -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
# Set desktop path
export DESKTOP_PATH=~/Desktop
# Run server
python server.py- Edit
server.py - Rebuild:
docker compose build - Restart:
docker compose up -d
Modify SCREENSHOT_PATTERN in server.py to match different file patterns:
# Include multiple patterns
SCREENSHOT_PATTERNS = ["Screenshot*.png", "CleanShot*.png", "Snagit*.png"]- macOS (for screenshot integration)
- Docker Desktop
- Claude Code CLI
MIT
Built with:
- FastMCP - Fast MCP server framework
- MCP - Model Context Protocol
- Claude Code - Anthropic's CLI for Claude