Skip to main content
Glama
LukeLamb

claude-linux-mcp

screenshot

Read-only

Capture a screenshot of the full screen or active window. Saves a PNG image and returns the file path.

Instructions

Capture a screenshot of the full screen (or the active window if active_window=true). Saves a PNG under /tmp/claude-linux-mcp/shots/ and returns the path.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathNoOptional target path. Defaults to /tmp/claude-linux-mcp/shots/shot-<ts>.png.
active_windowNoIf true, capture only the currently-focused window instead of the full screen.

Implementation Reference

  • The main screenshot handler function. Captures a screenshot using maim, scrot, or gnome-screenshot (in preference order) with fallback. Supports full-screen and active_window capture. Saves PNG to /tmp/claude-linux-mcp/shots/ and returns the path.
    async function screenshot(args) {
      if (!haveScreenshotTool()) {
        return errorResult('No screenshot tool found. Install one: sudo apt install maim (preferred), or scrot, or gnome-screenshot.');
      }
      fs.mkdirSync(SHOTS_ROOT, { recursive: true });
      const out = args.path || path.join(SHOTS_ROOT, `shot-${Date.now()}.png`);
      const active = args.active_window === true;
      const env = cleanEnv();
    
      // Try each installed tool in order; fall through on runtime failure.
      const attempts = [];
    
      async function tryMaim() {
        if (!BIN.maim) return null;
        const args2 = active && BIN.xdotool
          ? ['-i', (await run(BIN.xdotool, ['getactivewindow'], { env })).stdout.trim(), out]
          : [out];
        return { tool: 'maim', ...(await run(BIN.maim, args2, { env })) };
      }
      async function tryScrot() {
        if (!BIN.scrot) return null;
        return { tool: 'scrot', ...(await run(BIN.scrot, active ? ['-u', out] : [out], { env })) };
      }
      async function tryGnome() {
        if (!BIN.gnomeShot) return null;
        return { tool: 'gnome-screenshot', ...(await run(BIN.gnomeShot, active ? ['-w', '-f', out] : ['-f', out], { env })) };
      }
    
      for (const attempt of [tryMaim, tryScrot, tryGnome]) {
        // Clear any stale file before each attempt so size=0 check is meaningful.
        try { if (fs.existsSync(out)) fs.unlinkSync(out); } catch (_) {}
        const r = await attempt();
        if (!r) continue;
        const size = fs.existsSync(out) ? fs.statSync(out).size : 0;
        attempts.push({ tool: r.tool, code: r.code, size, stderr: (r.stderr || '').slice(0, 200) });
        if (r.code === 0 && size > 0) {
          return textResult({ path: out, size_bytes: size, active_window: active, tool: r.tool });
        }
      }
    
      return errorResult(
        `screenshot failed. Tried: ${attempts.map(a => `${a.tool}(code=${a.code}, size=${a.size})`).join('; ') || '<none installed>'}. ` +
        `DISPLAY=${process.env.DISPLAY || 'unset'}, XDG_SESSION_TYPE=${process.env.XDG_SESSION_TYPE || 'unset'}. ` +
        `If XDG_SESSION_TYPE is "wayland", log out and pick an X11 session; this extension does not support Wayland in v0.1. ` +
        `If you only have gnome-screenshot installed and it's failing, try: sudo apt install maim`
      );
    }
  • Tool registration entry for 'screenshot' including its description, annotations (readOnlyHint: true), and inputSchema (path string, active_window boolean).
    const TOOLS = [
      {
        name: 'screenshot',
        description: 'Capture a screenshot of the full screen (or the active window if active_window=true). Saves a PNG under /tmp/claude-linux-mcp/shots/ and returns the path.',
        annotations: { title: 'Take screenshot', readOnlyHint: true },
        inputSchema: {
          type: 'object',
          properties: {
            path: { type: 'string', description: 'Optional target path. Defaults to /tmp/claude-linux-mcp/shots/shot-<ts>.png.' },
            active_window: { type: 'boolean', description: 'If true, capture only the currently-focused window instead of the full screen.' },
          },
        },
      },
  • server.js:553-554 (registration)
    HANDLERS object mapping 'screenshot' to the 'screenshot' function, used by the tools/call dispatch at line 587-598.
    const HANDLERS = {
      screenshot,
  • haveScreenshotTool() checks whether at least one of maim, scrot, or gnome-screenshot is available on the system.
    function haveScreenshotTool() {
      return BIN.gnomeShot || BIN.scrot || BIN.maim;
    }
  • cleanEnv() strips Snap-confinement environment variables to prevent GNOME/maim/scrot tools from breaking due to Snap env pollution. Used by the screenshot handler.
    function cleanEnv() {
      const e = {};
      for (const [k, v] of Object.entries(process.env)) {
        if (k.startsWith('SNAP_') || k === 'SNAP' || k === 'GTK_PATH' || k === 'GIO_MODULE_DIR' || k === 'LD_LIBRARY_PATH' || k === 'LD_PRELOAD') continue;
        e[k] = v;
      }
      return e;
    }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses file format (PNG), save location (/tmp/claude-linux-mcp/shots/), and return value (path). Annotations include readOnlyHint=true, which is not contradicted; the tool is a read operation with minimal side effects.

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 concise sentences front-load the main action and optional behavior. No unnecessary words or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with full parameter coverage and annotations, the description covers purpose, parameters, output, and side effects. No gaps exist given the lack of an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description adds the default path and clarifies the behavior of 'active_window', providing value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'capture' and the resource 'screenshot', and distinguishes between full screen and active window. It contrasts with the sibling tool 'screenshot_text' which extracts text.

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 implies usage for visual capture but does not explicitly state when to use versus alternatives like 'screenshot_text' or specify when not to use. No exclusions or context is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/LukeLamb/claude-linux-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server