MCP Screenshot Server
This MCP server provides AI assistants with web and system screenshot capture capabilities.
Capture public web pages via headless Chromium, with optional viewport size, full-page capture, CSS selector targeting, and wait conditions.
Capture the local desktop fullscreen, a specific application window by name or ID, or a screen region on macOS, Linux, and Windows.
Control system screenshots with display selection, cursor inclusion, PNG/JPG format, delay, and output path.
Save screenshots to a default or configured output directory, with security protections for URLs, paths, commands, and resource use.
Allows capturing screenshots of websites and local HTML files through Puppeteer with configurable viewport dimensions, full page capture support, and custom output paths.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Screenshot Servertake a screenshot of https://example.com with width 1200 and full page"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Universal Screenshot MCP
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.
Features
Web Page Screenshots — Capture any public URL using a headless Chromium browser
Cross-Platform System Screenshots — Fullscreen, window, or region capture using native OS tools (macOS
screencapture, Linuxmaim/scrot/gnome-screenshot/etc., Windows PowerShell+.NET)Security-First Design — SSRF prevention, path traversal protection, DNS rebinding defense, command injection prevention, and DoS limiting
MCP Native — Integrates directly with Claude Desktop, Cursor, and any MCP-compatible client
Related MCP server: Chrome DevTools MCP
Requirements
Node.js >= 18.0.0
Chromium is downloaded automatically by Puppeteer on first run
Platform-Specific Requirements for take_system_screenshot
Platform | Required Tools | Notes |
macOS |
| No additional installation needed |
Linux | One of: |
|
Windows |
| Uses .NET |
Linux Installation Examples
# 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 grimAfter installing, you can verify your setup with:
npx universal-screenshot-mcp --doctorThis probes the host and prints copy-pasteable install commands for any missing tools, tailored to your detected distro.
Quick Start
Install from npm
npm install -g universal-screenshot-mcpOr run directly with npx:
npx universal-screenshot-mcpInstall from Source
git clone https://github.com/sethbang/mcp-screenshot-server.git
cd mcp-screenshot-server
npm install
npm run buildConfigure Your MCP Client
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 Claude Code, register the server with the claude mcp add command:
# Project scope (current directory only)
claude mcp add screenshot-server -- npx -y universal-screenshot-mcp
# User scope (available across all projects)
claude mcp add --scope user screenshot-server -- npx -y universal-screenshot-mcpOr if installed from source:
claude mcp add screenshot-server -- node /absolute/path/to/mcp-screenshot-server/build/index.jsVerify the server registered with claude mcp list, or check live status from inside a session with /mcp.
For Cursor or other MCP clients, consult their documentation for the equivalent configuration.
Tools
The server exposes two MCP tools:
take_screenshot
Captures a web page (or a specific element) via a headless Puppeteer browser.
Parameter | Type | Required | Description |
| string | ✅ | URL to capture (http/https only) |
| number | — | Viewport width (1–3840) |
| number | — | Viewport height (1–2160) |
| boolean | — | Capture the full scrollable page |
| string | — | CSS selector to capture a specific element |
| string | — | Wait for this selector before capturing |
| number | — | Delay in milliseconds (0–30000) |
| string | — | Output file path (default: |
Example prompt:
Take a screenshot of https://example.com at 1920x1080
take_system_screenshot
Captures the desktop, a specific application window, or a screen region using native OS tools. Works on macOS, Linux, and Windows.
Parameter | Type | Required | Description |
| enum | ✅ |
|
| number | — | Window ID for window mode |
| string | — | App name (e.g. |
| object | — |
|
| number | — | Display number for multi-monitor setups |
| boolean | — | Include the mouse cursor in the capture |
| enum | — |
|
| number | — | Capture delay in seconds (0–10) |
| string | — | Output file path (default: |
Cross-Platform Feature Support
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
Configuration
Environment Variables
Variable | Default | Description |
|
| Default output directory relative to |
|
| Set to |
Output Directories
Screenshots are saved to ~/Documents/screenshots by default (configurable via SCREENSHOT_OUTPUT_DIR). Custom output paths must resolve to one of these allowed directories:
Directory | Description |
| Default output location (configurable) |
| Original default location |
| User downloads folder |
| User documents folder |
| System temp directory |
Security
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 |
SEC-003 | Command injection | All subprocesses use |
SEC-004 | Path traversal | Output paths validated with |
SEC-005 | Denial of service | Concurrent Puppeteer instances limited to 3 via semaphore; 120 s hard deadline per call, after which the browser is killed and the slot freed |
SEC-006 | Popup SSRF bypass | Chromium's popup blocker kept on (Puppeteer disables it by default); any popup that still opens is closed |
For full details, see docs/security.md.
Development
Scripts
Command | Description |
| Compile TypeScript to |
| Recompile on file changes |
| Unit tests (fast, fully mocked) |
| Integration tests (real DNS/filesystem) |
| E2E tests (real Puppeteer/native tools) |
| All test tiers together |
| Linux e2e via Docker (requires Docker) |
| Run tests in watch mode |
| Run tests with coverage report |
| Lint source with ESLint |
| Launch MCP Inspector for debugging |
Project Structure
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)Testing
Tests use Vitest in three tiers:
Unit (
npm test) — Full dependency injection, no real I/O. Fast feedback loop.Integration (
npm run test:integration) — Real DNS resolution, real filesystem with temp directories, real Puppeteer against a local HTTP server.E2E (
npm run test:e2e) — Real native screenshot tools. macOS tests run natively; Linux tests run in Docker vianpm run test:linux; Windows tests run on thewindows-latestCI runner.
npm test # Unit tests (~300ms)
npm run test:linux # Linux provider tests in Docker
npm run test:all # EverythingDebugging with MCP Inspector
npm run inspectorThis launches the MCP Inspector connected to your built server, allowing you to invoke tools interactively.
License
Apache-2.0 — Copyright 2026 Seth Bang
Available Tools
2 toolstake_screenshotB
Capture web page or element via headless browser. Saves to ~/Documents/screenshots by default (configurable via SCREENSHOT_OUTPUT_DIR env var).
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL to capture | |
| width | No | Viewport width | |
| height | No | Viewport height | |
| fullPage | No | Capture full page | |
| selector | No | CSS selector for element | |
| outputPath | No | Absolute path, or relative to home dir | |
| waitForTimeout | No | Delay in ms | |
| waitForSelector | No | Wait for selector |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses the default output directory and the SCREENSHOT_OUTPUT_DIR override, but says nothing about failure modes (unreachable URL, selector timeout), whether the browser is launched locally, or what the tool actually returns (file path vs. image payload).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences: the capability first, then the output-destination detail. Zero filler, nothing buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, annotation-free tool with no output schema, the definition covers placement of the artifact but not the return contract — an agent cannot tell whether it gets a path, a base64 image, or a success flag. The dependency between selector and fullPage is also left unresolved.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and every parameter is self-documented, so baseline is 3. The description adds only one piece of extra meaning — the default output location and env-var override for outputPath — and it does not clarify the interaction between fullPage and selector or how waitForSelector and waitForTimeout combine.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Capture web page or element") plus the mechanism (headless browser), which is enough to separate it from take_system_screenshot. It never names the sibling explicitly, so the differentiation is inferred rather than declared.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"web page or element" hints at the domain, but there is no explicit statement of when to prefer this over take_system_screenshot (which captures the local screen) or any prerequisites/exclusions. The agent must reason about the alternative on its own.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
take_system_screenshotA
Capture desktop, window, or region screenshot. Cross-platform: macOS (screencapture), Linux (maim/scrot/gnome-screenshot/etc.), Windows (PowerShell+.NET). Saves to ~/Documents/screenshots by default (configurable via SCREENSHOT_OUTPUT_DIR env var). For window mode, provide windowName (app name like "Safari") or windowId.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | Yes | fullscreen=entire screen, window=specific app (requires windowName or windowId), region=coordinates | |
| delay | No | Delay seconds | |
| format | No | Image format (png or jpg) | |
| region | No | Region {x,y,width,height} | |
| display | No | Display number | |
| windowId | No | Window ID (for window mode) | |
| outputPath | No | Absolute path, or relative to home dir | |
| windowName | No | App name like "Safari", "Firefox" (for window mode) | |
| includeCursor | No | Include cursor |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does a good job: it names the concrete backend per platform (screencapture, maim/scrot, PowerShell+.NET), states the default save path and the SCREENSHOT_OUTPUT_DIR override. It omits notable behavioral facts such as macOS screen-recording permission requirements and whether the saved file path is returned, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the action, then platform backends, then output location and mode prerequisites. No filler, though the platform backend enumeration is somewhat dense detail an agent rarely needs to act on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter tool with a nested region object, no annotations, and no output schema, the description covers intent and storage location but says nothing about the return value (e.g., whether the file path is returned) or permission prerequisites. The minimum needed to invoke is present; the minimum needed to interpret the result is not.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every parameter is already documented in the schema, including mode, region, windowName and windowId. The description's only added parameter context is the windowName-by-app-name example, which largely duplicates the schema text. Baseline 3 is warranted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Capture desktop, window, or region screenshot') and enumerates the three capture modes, so the agent knows exactly what the tool produces. It does not differentiate itself from the sibling tool take_screenshot, which leaves the naming distinction unresolved.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains mode prerequisites ('For window mode, provide windowName or windowId'), which is useful routing within the tool, and gives the default output location. However, it offers no guidance on when to choose this tool over the sibling take_screenshot, and no exclusions or failure conditions are described.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v1.5.0- Changed
take_screenshot2 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false
- Changed
take_system_screenshot7 fields changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema" - removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / display / maximumAdded value: +9007199254740991 - removed
Input schema / properties / region / additionalPropertiesRemoved value: -false - added
Input schema / properties / region / properties / x / maximumAdded value: +9007199254740991 - added
Input schema / properties / region / properties / y / maximumAdded value: +9007199254740991 - added
Input schema / properties / windowId / maximumAdded value: +9007199254740991
2 tool updates
v1.2.0- Changed
take_screenshot10 fields changed- added
Input schema / $schemaAdded value: +"http://json-schema.org/draft-07/schema#" - added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / fullPage / descriptionPrevious value: -"Capture full scrollable page"New value: +"Capture full page" - changed
Input schema / properties / height / descriptionPrevious value: -"Viewport height in pixels"New value: +"Viewport height" - changed
Input schema / properties / outputPath / descriptionPrevious value: -"Custom output path (optional)"New value: +"Absolute path, or relative to home dir" - added
Input schema / properties / selectorAdded value: +{ + "description": "CSS selector for element", + "type": "string" +} - changed
Input schema / properties / url / descriptionPrevious value: -"URL to capture (can be http://, https://, or file:///)"New value: +"URL to capture" - added
Input schema / properties / waitForSelectorAdded value: +{ + "description": "Wait for selector", + "type": "string" +} - added
Input schema / properties / waitForTimeoutAdded value: +{ + "description": "Delay in ms", + "maximum": 30000, + "minimum": 0, + "type": "number" +} - changed
Input schema / properties / width / descriptionPrevious value: -"Viewport width in pixels"New value: +"Viewport width"
- Added
take_system_screenshot
1 tool update
- First observed
take_screenshot
TDQS
Scored across 2 tools
The two tools split cleanly along rendering source: headless browser page capture vs. OS-level desktop/window/region capture, and descriptions make this explicit. Minor risk remains because the generic name 'take_screenshot' doesn't signal 'web page only', so an agent skimming names could pick it for a desktop capture.
Both follow the same verb_noun convention (take_screenshot, take_system_screenshot) with a consistent qualifier modifier. Predictable and readable as a set.
Two tools are proportionate for a narrow screenshot-capture domain, and each covers a genuinely separate surface. It is on the thin side — a third tool (e.g., listing or re-opening saved captures) would round out the set.
Core capture scenarios are covered: web pages (including elements) and desktop, window, or region captures across all three OSes, with configurable output. Minor gaps around browsing/retrieving saved screenshots or format/full-page options, but agents can work around these via the filesystem.
Maintenance
Related MCP Connectors
Web scraping, browser automation, screenshots and AI data extraction for AI agents via MCP.
Browserless MCP — wraps the Browserless headless-Chromium REST API (browserless.io)
Screenshots of any public web page as PNG, JPEG, WebP, PDF or a scrolling video.
Screenshot any URL/HTML as PNG/JPEG/WebP, or read it as clean Markdown/text for LLMs.
Related MCP Servers
- AlicenseAqualityFmaintenanceCaptures screenshots of web pages using Puppeteer, allowing AI agents to visually verify web applications and see their progress when generating web apps.556MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI coding assistants to control and inspect a live Chrome browser through Chrome DevTools. Provides browser automation, performance analysis, debugging capabilities, and network request monitoring.2,848,483 npm54,622Apache 2.0
- AlicenseCqualityDmaintenanceEnables taking screenshots of web pages with support for multiple devices (desktop, mobile, tablet), custom dimensions, full-page capture, and various image formats. Built with Playwright for reliable web page rendering and screenshot generation.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to capture any public URL as PNG, JPEG, or PDF via REST API or MCP tools, including screenshot capture, page description, and PDF rendering.14 npmMIT