MCP server for web page and cross-platform system screenshots (macOS, Linux, Windows)
An MCP (Model Context Protocol) server that provides AI assistants with screenshot capabilities — both web page capture via Puppeteer and cross-platform system screenshots using native OS tools.
screencapture, Linux maim/scrot/gnome-screenshot/etc., Windows PowerShell+.NET)take_system_screenshot| Platform | Required Tools | Notes |
|---|---|---|
| macOS | screencapture (built-in) | No additional installation needed |
| Linux | One of: maim, scrot, gnome-screenshot, spectacle, grim, or import (ImageMagick) | maim or scrot recommended for full feature support. For window-by-name capture, also install xdotool. |
| Windows | powershell (built-in) | Uses .NET System.Drawing — no additional installation needed |
# Ubuntu/Debian (recommended)
sudo apt install maim xdotool
# Fedora
sudo dnf install maim xdotool
# Arch Linux
sudo pacman -S maim xdotool
# Wayland (Sway, etc.)
sudo apt install grim
npm install -g universal-screenshot-mcp
Or run directly with npx:
npx universal-screenshot-mcp
git clone https://github.com/sethbang/mcp-screenshot-server.git
cd mcp-screenshot-server
npm install
npm run build
Add the server to your MCP client configuration. For Claude Desktop, edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"screenshot-server": {
"command": "npx",
"args": ["-y", "universal-screenshot-mcp"]
}
}
}
Or if installed from source:
{
"mcpServers": {
"screenshot-server": {
"command": "node",
"args": ["/absolute/path/to/mcp-screenshot-server/build/index.js"]
}
}
}
For Cursor or other MCP clients, consult their documentation for the equivalent configuration.
The server exposes two MCP tools:
take_screenshotCaptures a web page (or a specific element) via a headless Puppeteer browser.
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | ✅ | URL to capture (http/https only) |
width | number | — | Viewport width (1–3840) |
height | number | — | Viewport height (1–2160) |
fullPage | boolean | — | Capture the full scrollable page |
selector | string | — | CSS selector to capture a specific element |
waitForSelector | string | — | Wait for this selector before capturing |
waitForTimeout | number | — | Delay in milliseconds (0–30000) |
outputPath | string | — | Output file path (default: ~/Desktop/Screenshots) |
Example prompt:
Take a screenshot of https://example.com at 1920x1080
take_system_screenshotCaptures the desktop, a specific application window, or a screen region using native OS tools. Works on macOS, Linux, and Windows.
| Parameter | Type | Required | Description |
|---|---|---|---|
mode | enum | ✅ | fullscreen, window, or region |
windowId | number | — | Window ID for window mode |
windowName | string | — | App name (e.g. "Safari", "Firefox") for window mode |
region | object | — | { x, y, width, height } for region mode |
display | number | — | Display number for multi-monitor setups |
includeCursor | boolean | — | Include the mouse cursor in the capture |
format | enum | — | png (default) or jpg |
delay | number | — | Capture delay in seconds (0–10) |
outputPath | string | — | Output file path (default: ~/Desktop/Screenshots) |
| Feature | macOS | Linux | Windows |
|---|---|---|---|
| Fullscreen | ✅ | ✅ | ✅ |
| Region | ✅ | ✅ (maim, scrot, grim, import) | ✅ |
| Window by name | ✅ | ⚠️ X11 + xdotool | ⚠️ best-effort |
| Window by ID | ✅ | ✅ X11 only | ⚠️ HWND |
| Multi-display | ✅ | ⚠️ tool-dependent | ✅ |
| Include cursor | ✅ | ⚠️ tool-dependent | ⚠️ |
| Delay | ✅ | ✅ | ✅ |
Example prompt:
Take a system screenshot of the Safari window
Screenshots are saved to ~/Desktop/Screenshots by default. Custom output paths must resolve to one of these allowed directories:
| Directory | Description |
|---|---|
~/Desktop/Screenshots | Default output location |
~/Downloads | User downloads folder |
~/Documents | User documents folder |
/tmp | System temp directory |
This server implements multiple layers of security hardening:
| ID | Threat | Mitigation |
|---|---|---|
| SEC-001 | SSRF / DNS rebinding | URLs validated against blocked IP ranges; DNS resolved pre-request with IP pinning via --host-resolver-rules; navigation redirects re-validated |
| SEC-003 | Command injection | All subprocesses use execFile (no shell); app names validated against SAFE_APP_NAME_PATTERN |
| SEC-004 | Path traversal | Output paths validated with fs.realpath() symlink resolution; restricted to allowed directories |
| SEC-005 | Denial of service | Concurrent Puppeteer instances limited to 3 via semaphore |
For full details, see docs/security.md.
| Command | Description |
|---|---|
npm run build | Compile TypeScript to build/ |
npm run watch | Recompile on file changes |
npm test | Run tests with Vitest |
npm run test:watch | Run tests in watch mode |
npm run test:coverage | Run tests with coverage report |
npm run lint | Lint source with ESLint |
npm run inspector | Launch MCP Inspector for debugging |
src/
├── index.ts # Entry point — stdio transport
├── server.ts # MCP server factory
├── config/
│ ├── index.ts # Static constants (limits, allowed dirs)
│ └── runtime.ts # Singleton semaphore, default directory
├── tools/
│ ├── take-screenshot.ts # Web page capture tool
│ └── take-system-screenshot.ts # macOS system capture tool
├── types/
│ └── index.ts # Shared TypeScript interfaces
├── utils/
│ ├── helpers.ts # Response builders, file utilities
│ ├── screenshot-provider.ts # Cross-platform provider interface + factory
│ ├── macos-provider.ts # macOS: screencapture wrapper
│ ├── linux-provider.ts # Linux: maim/scrot/gnome-screenshot/etc.
│ ├── windows-provider.ts # Windows: PowerShell + .NET System.Drawing
│ ├── macos.ts # Window ID lookup via CoreGraphics
│ └── semaphore.ts # Async concurrency limiter
└── validators/
├── path.ts # Output path validation (SEC-004)
└── url.ts # URL/SSRF validation (SEC-001)
Tests use Vitest with full dependency injection — no real network calls, filesystem access, or subprocess execution in tests.
npm test
npm run inspector
This launches the MCP Inspector connected to your built server, allowing you to invoke tools interactively.
Apache-2.0 — Copyright 2026 Seth Bang
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y universal-screenshot-mcpMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-sethbang-screenshot-server": {
"command": "npx",
"args": [
"-y",
"universal-screenshot-mcp"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceuniversal-screenshot-mcpnpmUniversal Screenshot MCP works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.