Skip to main content
Glama
sethbang

MCP Screenshot Server

by sethbang

Universal Screenshot MCP

npm version MCP Registry License

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, Linux maim/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

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

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 grim

After installing, you can verify your setup with:

npx universal-screenshot-mcp --doctor

This 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-mcp

Or run directly with npx:

npx universal-screenshot-mcp

Install from Source

git clone https://github.com/sethbang/mcp-screenshot-server.git
cd mcp-screenshot-server
npm install
npm run build

Configure 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-mcp

Or if installed from source:

claude mcp add screenshot-server -- node /absolute/path/to/mcp-screenshot-server/build/index.js

Verify 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

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: ~/Documents/screenshots)

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

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: ~/Documents/screenshots)

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

SCREENSHOT_OUTPUT_DIR

Documents/screenshots

Default output directory relative to ~

ALLOW_LOCAL

false

Set to true to allow screenshotting localhost/127.x.x.x/[::1] (useful for local dev servers)

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

~/Documents/screenshots

Default output location (configurable)

~/Desktop/Screenshots

Original default location

~/Downloads

User downloads folder

~/Documents

User documents folder

/tmp

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 --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; 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

npm run build

Compile TypeScript to build/

npm run watch

Recompile on file changes

npm test

Unit tests (fast, fully mocked)

npm run test:integration

Integration tests (real DNS/filesystem)

npm run test:e2e

E2E tests (real Puppeteer/native tools)

npm run test:all

All test tiers together

npm run test:linux

Linux e2e via Docker (requires Docker)

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

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 via npm run test:linux; Windows tests run on the windows-latest CI runner.

npm test                 # Unit tests (~300ms)
npm run test:linux       # Linux provider tests in Docker
npm run test:all         # Everything

Debugging with MCP Inspector

npm run inspector

This 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 tools
take_screenshotB

Capture web page or element via headless browser. Saves to ~/Documents/screenshots by default (configurable via SCREENSHOT_OUTPUT_DIR env var).

NameRequiredDescriptionDefault
urlYesURL to capture
widthNoViewport width
heightNoViewport height
fullPageNoCapture full page
selectorNoCSS selector for element
outputPathNoAbsolute path, or relative to home dir
waitForTimeoutNoDelay in ms
waitForSelectorNoWait for selector

TDQS

B3.3/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

NameRequiredDescriptionDefault
modeYesfullscreen=entire screen, window=specific app (requires windowName or windowId), region=coordinates
delayNoDelay seconds
formatNoImage format (png or jpg)
regionNoRegion {x,y,width,height}
displayNoDisplay number
windowIdNoWindow ID (for window mode)
outputPathNoAbsolute path, or relative to home dir
windowNameNoApp name like "Safari", "Firefox" (for window mode)
includeCursorNoInclude cursor

TDQS

A3.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

  1. 2 tool updatesv1.5.0
    • Changedtake_screenshot2 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / additionalProperties
        Removed value: -false
    • Changedtake_system_screenshot7 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / display / maximum
        Added value: +9007199254740991
      • removedInput schema / properties / region / additionalProperties
        Removed value: -false
      • addedInput schema / properties / region / properties / x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / region / properties / y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / windowId / maximum
        Added value: +9007199254740991
  2. 2 tool updatesv1.2.0
    • Changedtake_screenshot10 fields changed
      • addedInput schema / $schema
        Added value: +"http://json-schema.org/draft-07/schema#"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / fullPage / description
        Previous value: -"Capture full scrollable page"New value: +"Capture full page"
      • changedInput schema / properties / height / description
        Previous value: -"Viewport height in pixels"New value: +"Viewport height"
      • changedInput schema / properties / outputPath / description
        Previous value: -"Custom output path (optional)"New value: +"Absolute path, or relative to home dir"
      • addedInput schema / properties / selector
        Added value: +{
        +  "description": "CSS selector for element",
        +  "type": "string"
        +}
      • changedInput schema / properties / url / description
        Previous value: -"URL to capture (can be http://, https://, or file:///)"New value: +"URL to capture"
      • addedInput schema / properties / waitForSelector
        Added value: +{
        +  "description": "Wait for selector",
        +  "type": "string"
        +}
      • addedInput schema / properties / waitForTimeout
        Added value: +{
        +  "description": "Delay in ms",
        +  "maximum": 30000,
        +  "minimum": 0,
        +  "type": "number"
        +}
      • changedInput schema / properties / width / description
        Previous value: -"Viewport width in pixels"New value: +"Viewport width"
    • Addedtake_system_screenshot
  3. 1 tool update
    • First observedtake_screenshot

TDQS

A3.7/5.0

Scored across 2 tools

Disambiguation4/5

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.

Naming Consistency5/5

Both follow the same verb_noun convention (take_screenshot, take_system_screenshot) with a consistent qualifier modifier. Predictable and readable as a set.

Tool Count4/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    D
    maintenance
    Enables 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.
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables 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 npm
    MIT