Skip to main content
Glama
README.md
# quick-media-mcp

MCP server and Chrome extensions for screen recording and screenshots, designed for [Claude Code](https://claude.com/claude-code).

## Architecture

```
Claude Code
    ↓ MCP protocol (stdio)
quick-media-mcp server (Node.js)
    ↓ WebSocket (localhost:9876)
Chrome Extensions (Quick Video / Quick Screenshot)
    ↓ getDisplayMedia / captureVisibleTab
Browser
```

The MCP server is the bridge between Claude Code and the Chrome extensions. Claude calls MCP tools (`video_start`, `screenshot_capture`, etc.), the server forwards them to the extensions via WebSocket, and the extensions use Chrome APIs to capture media.

## Packages

| Package | Description | npm |
|---------|-------------|-----|
| [`packages/server`](packages/server/) | MCP server — bridge between Claude Code and extensions | `quick-media-mcp` |
| [`packages/chrome-video`](packages/chrome-video/) | Chrome extension — screen/tab recording (WebM, MP4, GIF) | - |
| [`packages/chrome-screenshot`](packages/chrome-screenshot/) | Chrome extension — screenshots (PNG, JPEG, WebP, GIF) | - |

## Prerequisites

- **Node.js** >= 18
- **Google Chrome** (or Chromium)
- **Claude Code** (for MCP integration)
- **ffmpeg** (optional, for hardware-accelerated encoding detection)

## Installation

### 1. Clone and build

```bash
git clone https://github.com/Fowerld/quick-media-mcp.git
cd quick-media-mcp
npm install
npm run build
```

This builds all three packages:
- `packages/server/dist/` — compiled MCP server
- `packages/chrome-video/dist/` — video extension ready to load
- `packages/chrome-screenshot/dist/` — screenshot extension ready to load

### 2. Load extensions in Chrome

1. Open `chrome://extensions`
2. Enable **Developer mode** (toggle in the top right corner)
3. Click **Load unpacked** → navigate to `packages/chrome-video/dist/` → select the folder
4. Click **Load unpacked** → navigate to `packages/chrome-screenshot/dist/` → select the folder

Both extensions should appear in the extensions list. Pin them to the toolbar for easy access.

### 3. Configure the MCP server for Claude Code

**Option A — Local path (recommended for development):**

Add to `~/.claude/settings.json`:

```json
{
  "mcpServers": {
    "quick-media": {
      "command": "node",
      "args": ["/absolute/path/to/quick-media-mcp/packages/server/dist/cli.js"]
    }
  }
}
```

**Option B — Global install:**

```bash
cd packages/server
npm install -g .
quick-media-mcp --install
```

This registers the server in `~/.claude/settings.json` automatically. You can verify with `quick-media-mcp --help`.

**Option C — Auto-install script:**

```bash
quick-media-mcp --install    # adds to Claude Code config
quick-media-mcp --uninstall  # removes from Claude Code config
```

### 4. Connect the extensions

1. Open a Chrome tab
2. Click the **Quick Video** (or **Quick Screenshot**) extension icon
3. Enable the **MCP** toggle in the popup
4. The extension badge turns **blue** when connected to the server

> The extensions auto-reconnect every 5 seconds if the server is not running. You can enable MCP mode once and it persists across browser restarts.

### 5. Verify

In Claude Code, check the connection:

```
Use the video_status tool to check if the video extension is connected.
```

Claude should report that the extension is connected and ready.

## Usage

### MCP tools (via Claude Code)

| Tool | Description | Parameters |
|------|-------------|------------|
| `video_start` | Start screen recording | `resolution` (auto/4k/.../240p), `format` (mp4/webm/gif) |
| `video_stop` | Stop recording and save | — |
| `video_status` | Check extension connection | — |
| `screenshot_capture` | Take a screenshot | `format` (png/jpeg/webp/gif), `quality` (1-100), `resolution` (auto/720p/1080p/4k) |
| `screenshot_status` | Check extension connection | — |
| `system_info` | Display GPU/encoder capabilities | — |

All parameters are optional and have sensible defaults.

### Keyboard shortcuts

| Shortcut | Action |
|----------|--------|
| `Alt+Shift+V` | Start/stop video recording |
| `Ctrl+Shift+S` | Take a screenshot (toggle preview) |

### Standalone usage (without MCP)

Both extensions work without the MCP server for manual capture:

- **Quick Video**: click the extension icon → configure format/resolution/FPS → hit record
- **Quick Screenshot**: press `Ctrl+Shift+S` or click the extension icon

Without the MCP server, audio capture is limited to microphone only (no system audio on Linux).

## Important notes

### First recording requires a user gesture

Chrome requires a **user gesture** to authorize screen capture (`getDisplayMedia`). On the first recording of a browser session:

1. Claude (or you) triggers `video_start`
2. Chrome shows a picker dialog — **you must click** to select the tab/window/screen to share
3. Subsequent recordings reuse the permission until the service worker resets

This is a Chrome security requirement and cannot be bypassed.

### Screen capture permissions (Linux)

On Wayland, you may need to grant screen capture permissions through your compositor. With PipeWire-based compositors (GNOME, KDE), Chrome typically handles this via the portal API.

### System audio (Linux)

Chrome's `getDisplayMedia` does **not** expose system audio on Linux (unlike Windows/macOS where tab audio is available). The MCP server bridges this gap using PipeWire:

- Requires `pw-record` and `ffmpeg` (native) on the host
- The server captures system audio with `pw-record --target=0`
- After recording, the server merges video + audio with `ffmpeg`
- The extension popup shows a "System Audio (PipeWire)" option when the server detects PipeWire

This feature is under active development on the `feat/pipewire-audio` branch.

### File output

Recordings and screenshots are saved to Chrome's **Downloads** folder. The file path is returned to Claude via the MCP response, so Claude knows exactly where the file is.

## GPU and encoder detection

The MCP server auto-detects your GPU at startup and selects the best encoder:

| GPU | Encoder | Max capability |
|-----|---------|---------------|
| NVIDIA | `h264_nvenc` | 4K @ 60fps |
| Intel | `h264_qsv` / `h264_vaapi` | Depends on model |
| AMD | `h264_vaapi` | Radeon RX: 4K, others: 1080p |
| None / fallback | `libx264` (software) | 720p @ 30fps |

Use `system_info` in Claude Code to see what was detected on your system.

## Development

```bash
npm run build              # build everything
npm run build:server       # build MCP server only
npm run build:video        # build video extension only
npm run build:screenshot   # build screenshot extension only
```

For watch mode during development:

```bash
# In separate terminals:
cd packages/server && npm run dev          # tsc --watch
cd packages/chrome-video && npm run watch  # esbuild --watch
```

After rebuilding an extension, go to `chrome://extensions` and click the **reload** button on the extension card (or press `Ctrl+R` on the card).

### Project structure

```
quick-media-mcp/
├── packages/
│   ├── server/                 # MCP server (published to npm)
│   │   ├── src/
│   │   │   ├── server.ts       # MCP tools + WebSocket bridge
│   │   │   ├── cli.ts          # CLI entry point (start/install/uninstall)
│   │   │   ├── capabilities.ts # GPU detection + resolution presets
│   │   │   └── install.ts      # Claude Code settings management
│   │   └── package.json
│   ├── chrome-video/           # Quick Video extension
│   │   ├── src/
│   │   │   ├── background.ts   # Service worker, state, MCP WebSocket
│   │   │   ├── offscreen.ts    # MediaRecorder (offscreen document)
│   │   │   ├── converter.ts    # FFmpeg WASM (WebM → MP4/GIF)
│   │   │   ├── popup.ts/html   # Extension popup UI
│   │   │   └── manifest.json
│   │   └── package.json
│   └── chrome-screenshot/      # Quick Screenshot extension
│       ├── src/
│       │   ├── background.ts   # Service worker, capture logic, MCP WebSocket
│       │   ├── content.ts      # Overlay UI, area selection
│       │   ├── popup.ts/html   # Extension popup UI
│       │   └── manifest.json
│       └── package.json
├── docker/                     # Docker setup for headless recording
├── package.json                # Workspace root
└── README.md
```

## Troubleshooting

### Extension badge doesn't turn blue
- Is the MCP server running? Check with `quick-media-mcp --help`
- Is MCP mode enabled in the extension popup?
- Check Chrome DevTools console (right-click extension icon → Inspect popup → Console) for WebSocket errors
- Verify port 9876 is not in use: `lsof -i :9876`

### "Permission denied" on first recording
- This is normal — Chrome requires you to click the capture picker dialog at least once per session
- Make sure the browser window is focused when the dialog appears

### Build fails with "Missing dependencies"
- Run `npm install` from the repo root (not from a package subfolder)
- npm workspaces hoists dependencies to the root `node_modules/`

### screenshot_capture returns an error
- Make sure a Chrome tab is active and focused
- The `<all_urls>` host permission must be granted (check `chrome://extensions`)

## License

MIT