Skip to main content
Glama

screen-recorder-mcp

An MCP server that lets an AI assistant record a video of one app window, a part of it, or a whole monitor. Works on Windows and macOS.

Window recordings only contain the chosen app. If another window is dragged over it, the recording keeps showing the app underneath, not the window on top.

You:    record the Chrome window for the demo, just the left half
Claude: [calls list_targets, pick_region, start_recording]
        Recording Chrome. Tell me when to stop.
You:    stop
Claude: Saved ~/Videos/screen-recorder-mcp/rec-20261021-153000.mp4 (42 s)

Desktop app

Features

  • Record a single window (by title, app name or id) or a whole monitor.

  • Windows in front of the recorded app don't show up in the video.

  • Crop: an overlay lets you drag a rectangle over the app to record only that part.

  • Optional audio, off by default: system sound or microphone.

  • Constant frame rate MP4 (H.264), even when the app isn't redrawing.

  • Works without the GPU on Windows: if the GPU can't start a capture session (out of video memory, busy with a render or a game), it falls back to CPU capture on its own. You can also force it.

  • Optional desktop app laid out like the Windows Snipping Tool: selection overlay, recording toolbar with pause, player with trim, GIF export, history and settings. When the app is open, the AI records through it, so you always see the toolbar (with an "AI" badge) and can stop it.

  • Plain stdio MCP server, so any MCP client can use it (Claude Code, Claude Desktop, Cursor, ...).

Related MCP server: screen-mcp-server

Platform support

Windows 10 2004+ / 11

macOS 13 Ventura+

Capture API

Windows Graphics Capture, GDI PrintWindow on CPU

ScreenCaptureKit

Window recording, ignores apps in front

yes

yes

audio="system"

everything the PC plays

only the recorded app (all apps for a monitor)

audio="mic"

default microphone

default microphone

Status

tested

experimental, not yet tested on real hardware

Linux isn't supported yet. The OS-specific code sits behind one interface (src/screen_recorder_mcp/backends/), so adding it is mostly a matter of writing a new backend.

Requirements

  • Python 3.11+ and uv

  • ffmpeg on your PATH

    • Windows: winget install ffmpeg

    • macOS: brew install ffmpeg

  • The region picker uses tkinter. uv's managed Python includes it; Homebrew's Python often doesn't.

Install

git clone https://github.com/gcamara/screen-recorder-mcp.git
cd screen-recorder-mcp
uv sync

macOS permissions

Give Screen Recording permission to the app that launches the server (Terminal, iTerm, the Claude desktop app, ...) in System Settings > Privacy & Security, then restart that app. audio="mic" also needs Microphone.

Desktop app

uv run screen-recorder

It sits in the tray. + New (or Ctrl+Shift+R) opens the selection overlay:

  • Window: hover and click a window. Only that app is recorded, even if something covers it.

  • Rectangle: drag an area of the screen. This is a screen region, so whatever is on top of it is recorded too.

  • Full screen: click a monitor.

Pick a delay (3, 5 or 10 s) in the toolbar if you need time to get ready. While recording:

  • a border frames what is being recorded (it follows the window in Window mode);

  • the recording bar sits at the top of the screen with pause, stop, discard and the mic / system-audio toggles. Drag it anywhere; it remembers the spot. Neither the bar nor the border is ever part of the video.

When you stop, the recording is copied to the clipboard (turn this off in Settings) and opens in the player: trim the start and end, export a GIF, save, open the folder, or copy it again as video, GIF or file path (also on right-click in the history). Recent in the toolbar, and in the tray menu, lists the latest recordings; settings are under the gear.

Selection overlay

Recording toolbar

Trim

Settings

How the app and the MCP server fit together

you ──▶ desktop app (tray, overlay, toolbar, player) ──┐
                                                         ├──▶ recording service (one owner)
AI ───▶ MCP server ──── localhost + token ──────────────┘
         └─ app not running? records on its own, as before

The app writes control.json (port + random token) to your user's app-data folder and only accepts local connections that carry the token. The MCP server checks for it on every call: if the app is running, recordings go through the app (toolbar, history, settings are shared); if not, the MCP server records by itself. Recordings you make by hand show up in list_recordings, so you can tell the AI "make a GIF of my last recording".

Connect it to your AI client

Replace /path/to/screen-recorder-mcp with where you cloned it.

Claude Code

claude mcp add screen-recorder --scope user -- uv --directory /path/to/screen-recorder-mcp run --no-sync screen-recorder-mcp

Claude Desktop, Cursor and other clients (mcpServers section of the client's config):

{
  "mcpServers": {
    "screen-recorder": {
      "command": "uv",
      "args": ["--directory", "/path/to/screen-recorder-mcp", "run", "--no-sync", "screen-recorder-mcp"]
    }
  }
}

Restart the client and the tools below show up.

--no-sync matters on Windows: plain uv run re-installs the package when dependencies change, and that fails while another client session has the server's .exe open. After pulling a new version, close your AI clients and run uv sync once.

Usage

Just ask in plain language:

  • "Record the Notepad window for 30 seconds."

  • "Record my second monitor with the microphone on."

  • "Record the YouTube tab." The site is matched against the browser window's title, so that tab has to be the active one.

  • "Start recording." The assistant lists your windows and asks which one, then asks whether you want to crop.

The server tells the assistant to:

  1. use the screen, app or site you named, or ask you which one when you didn't;

  2. ask whether you want to record only part of it, and if so open the crop overlay;

  3. leave audio off unless you asked for it.

Crop overlay: drag a rectangle, then press Enter or double-click to confirm. Esc or right-click records the whole window.

Tools

Tool

What it does

list_targets()

Visible windows (front-most first) and monitors (monitor:1, monitor:2, ...)

pick_region(target)

Opens the crop overlay over the target and returns the rectangle you drew (or null)

start_recording(target, region?, fps=30, audio="none", capture_cursor=true, output_dir?, capture="auto")

Starts recording

recording_status()

Elapsed time, frames written, whether the target window was closed

pause_recording() / resume_recording()

Pause and resume; the paused time is cut out

stop_recording()

Finishes the file and returns its path and size

cancel_recording()

Stops and deletes the partial file

list_recordings(limit?)

Past recordings, newest first (made by you or by the AI)

trim_recording(recording_id, start_seconds, end_seconds)

Saves a trimmed copy

export_gif(recording_id, high_quality)

Exports a GIF next to the video

target accepts a window title or part of it, an app name (chrome, notepad.exe, Safari), a window_id from list_targets, or monitor:N.

capture picks how frames are read: "auto" (GPU, falling back to CPU), "gpu", or "cpu" (Windows only). Ask for it in plain words, e.g. "record Chrome, use the CPU, my GPU is busy". CPU capture doesn't draw the mouse cursor and costs more CPU per frame.

Files are saved to ~/Videos/screen-recorder-mcp/ on Windows and ~/Movies/screen-recorder-mcp/ on macOS, unless you pass output_dir.

Limitations

  • A minimized window produces no frames. start_recording fails with a message saying so.

  • On Windows, audio="system" records every app's sound, not only the recorded one.

  • Recording a whole monitor captures whatever is on it, including windows on top.

  • Some apps block capture of their windows (DRM video, some password managers). Those come out black.

  • One recording at a time (shared between the app and the AI).

  • The app's global shortcut is Windows-only for now; on macOS open the app from the tray.

How it works

OS capture API ──frames on change──▶ latest-frame slot ──▶ pacer (fixed fps) ──▶ ffmpeg ──▶ MP4
 (WGC / SCK)                                                  crop + size lock
optional audio ──▶ WAV (silence-padded) ─────────────────────────────── mux ──▶ final MP4
  • Per-window capture. Windows Graphics Capture and ScreenCaptureKit both read the window's own surface from the compositor, not the pixels on screen. That's why windows on top don't appear. The CPU path on Windows asks the window to paint itself into a bitmap (PrintWindow), which keeps the same guarantee, and stretches windows that aren't DPI-aware the way the desktop shows them.

  • Constant frame rate. Both APIs only send a frame when the window changes, so a static window would produce a 10-second video only a fraction of a second long. A pacer thread re-sends the latest frame on a fixed clock.

  • Size lock. The output size is fixed from the first frame. If the window is resized later, frames are padded or trimmed to that size, because ffmpeg's raw input needs a constant size.

  • Audio gaps. System/app audio sends no packets while nothing is playing. The WAV writer fills those gaps with silence so the audio stays in sync with the video.

  • stdout stays clean. In a stdio MCP server stdout carries the protocol. ffmpeg's output goes to a log file, and the crop overlay runs in its own process.

Development

uv run pytest -q                                      # unit tests, no desktop needed
uv run python scripts/verify_recording.py notepad     # real recording on this machine
uv run python scripts/verify_recording.py notepad --capture=cpu

verify_recording.py records a window while a red window covers it, then checks the result with ffprobe: duration, even dimensions, no red in the frames, and an audio stream when audio is on. On macOS use TextEdit as the window. If you have a Mac, running it there and reporting the output is the most useful contribution right now.

Layout:

src/screen_recorder_mcp/
  server.py            MCP tools
  recorder.py          one recording session (capture → pacer → encoder, audio, mux)
  frame_pacer.py       constant-fps pacing
  region_picker.py     crop overlay (runs as a subprocess)
  frame_sources.py     polling source + GPU→CPU fallback
  backends/windows/    Win32 window list, WGC capture, GDI CPU capture, WASAPI audio
  backends/macos/      Quartz window list, ScreenCaptureKit capture and app audio

License

MIT

Available Tools

11 tools
cancel_recordingA

Stop the running recording and delete the partial file.

Inputs: no named parameters. Returns: object

export_gifC

Convert a recording to an animated GIF and return its path.

Inputs: recording_id (required), output, high_quality. Returns: object

list_recordingsB

Recording history, newest first, including recordings the user made by hand.

Inputs: limit. Returns: object

list_targetsA

List recordable windows (front-most first) and monitors (monitor:N).

Inputs: no named parameters. Returns: object

pause_recordingA

Pause the running recording; paused time is not recorded.

Inputs: no named parameters. Returns: object

pick_regionA

Show a drag-to-crop overlay over the target so the USER selects the area.

    target: window title / process name / window_id, or `monitor:N`.
    Returns `region` relative to the target (null = user pressed Esc, record all).
    The OS may refuse to bring the app to the front; tell the user to keep the
    app visible before calling this, since the overlay is semi-transparent.
    

Inputs: target (required). Returns: object

recording_statusA

Report the running recording (state, elapsed time, countdown, whether the target closed).

Inputs: no named parameters. Returns: object

resume_recordingB

Resume a paused recording.

Inputs: no named parameters. Returns: object

start_recordingA

Start recording a window or monitor to MP4 (H.264).

    target: window title / process name / window_id, or `monitor:N` (see list_targets).
    region: optional {x, y, width, height} relative to the target, usually from pick_region.
    audio: "none" (default), "system" or "mic" — only when the user asked for audio.
    capture: "auto" (default: GPU capture, CPU if the GPU can't start), "gpu", or "cpu"
             (Windows only; no GPU use at all, no cursor in the video).
    delay_seconds: countdown before capture starts (0 default; the user sees it on screen).
    The user sees the recording toolbar of the desktop app, if it is running.
    

Inputs: target (required), fps, audio, region, +4 more. Returns: object

stop_recordingA

Stop the running recording and return the final MP4 path (output).

Inputs: no named parameters. Returns: object

trim_recordingB

Cut a recording to [start_seconds, end_seconds]; saves a new file, the original is kept.

Inputs: end_seconds (required), recording_id (required), start_seconds (required). Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 11 tools

    Disambiguation5/5

    Each tool targets a distinct lifecycle step or resource: discovery (list_targets, list_recordings), setup (pick_region), capture control (start/pause/resume/stop/cancel), and post-processing (trim_recording, export_gif). The only near-pair is stop_recording vs cancel_recording, and their descriptions make the keep-vs-delete difference explicit. An agent can select the right tool reliably.

    Naming Consistency4/5

    Names are uniformly snake_case with clear verb-led phrasing (list_targets, start_recording, pause_recording, trim_recording, export_gif). The lone deviation is recording_status, which is noun-first rather than verb_noun, though it is still readable and unambiguous. Overall predictable.

    Tool Count5/5

    11 tools is well within the sweet spot and each one maps to a concrete step of the recording workflow. There are no filler or redundant tools; pause/resume/cancel each earn their place as separate operations. The set is nicely scoped to the domain.

    Completeness4/5

    The surface covers the full capture lifecycle: target discovery, region selection, start, status, pause/resume, stop, cancel, history, trim, and GIF export. Minor gaps exist — there is no tool to delete a saved recording or inspect its duration/metadata, and no still-frame capture — but agents can work around these. Core workflows are fully supported.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers