makemkv-mcp
# makemkv-mcp
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://modelcontextprotocol.io)
## What is this?
`makemkv-mcp` is a standalone [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that wraps the `makemkvcon` command-line tool, exposing disc ripping capabilities as tools that any MCP-compatible client (Claude Desktop, Hivemind, etc.) can call. It runs on the machine with MakeMKV installed and an optical drive attached. The MCP client connects to it remotely via Streamable HTTP or locally via stdio.
## Features
- Scan optical drives and detect loaded discs
- Scan disc contents — titles, streams, durations, sizes, codecs
- Rip individual titles or all titles as async background jobs
- Full disc backup
- Persistent job queue with real-time progress tracking (SQLite-backed)
- Auto-rip daemon with configurable strategies (`longest`, `all`, `min_duration`)
- Discord webhook and generic webhook notifications
- Agent callback notifications for rip lifecycle events
- Cross-platform support (Linux, macOS, Windows)
- Runs over stdio (local) or Streamable HTTP (remote/network)
## Quick Start
### From source
```bash
git clone https://github.com/hivementality/makemkv-mcp.git
cd makemkv-mcp
pip install .
makemkv-mcp
```
### With pip
```bash
pip install .
# Run locally (stdio)
makemkv-mcp
# Run on the network (HTTP)
makemkv-mcp --transport streamable_http --port 8099
```
### With Docker
```bash
docker-compose up -d
```
## Installation
### Prerequisites
- **Python 3.10+**
- **MakeMKV** with `makemkvcon` in your PATH — [download here](https://www.makemkv.com/)
- An optical drive (Blu-ray, DVD, etc.)
### Linux
```bash
# Install MakeMKV (Ubuntu/Debian example)
sudo apt install makemkv-bin makemkv-oss
# Install makemkv-mcp
git clone https://github.com/hivementality/makemkv-mcp.git
cd makemkv-mcp
./install.sh
```
The installer will offer to set up a systemd service for auto-start.
### macOS
```bash
# Install MakeMKV from https://www.makemkv.com/
git clone https://github.com/hivementality/makemkv-mcp.git
cd makemkv-mcp
./install.sh
```
The installer will offer to set up a launchd service for auto-start.
### Windows
```powershell
# Install MakeMKV from https://www.makemkv.com/
git clone https://github.com/hivementality/makemkv-mcp.git
cd makemkv-mcp
.\install.ps1
```
The installer will offer to create a scheduled task for auto-start at login.
## Configuration
Generate the default config file:
```bash
makemkv-mcp --init-config
```
This writes to the platform-specific default location:
| Platform | Config path |
|----------|-------------|
| Linux | `~/.config/makemkv-mcp/config.yaml` |
| macOS | `~/Library/Application Support/makemkv-mcp/config.yaml` |
| Windows | `%APPDATA%\makemkv-mcp\config.yaml` |
You can also pass `--config /path/to/config.yaml` or set the `MAKEMKV_MCP_CONFIG` environment variable.
### Full config reference
```yaml
server:
host: "0.0.0.0" # Bind address for HTTP transport
port: 8099 # Port for HTTP transport
transport: "stdio" # "stdio" or "streamable_http"
makemkv:
binary: "makemkvcon" # Path or name of makemkvcon binary
default_output: "~/makemkv-output" # Default rip output directory
min_title_length: 120 # Minimum title duration (seconds) for auto-rip filtering
timeout: 7200 # Max seconds for a single rip operation
auto_rip:
enabled: false # Enable auto-rip on disc insertion
poll_interval: 30 # Seconds between drive polls
strategy: "longest" # Title selection: "longest", "all", or "min_duration"
eject_after: true # Eject disc after successful rip
notifications:
agent_notify: true # Send notifications back to MCP agent
discord_webhook: null # Discord webhook URL
webhook_url: null # Generic webhook URL (POST JSON)
```
## Usage
### With Claude Desktop (stdio)
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"makemkv": {
"command": "makemkv-mcp"
}
}
}
```
### With Hivemind / Remote clients (Streamable HTTP)
Start the server on the machine with the optical drive:
```bash
makemkv-mcp --transport streamable_http --host 0.0.0.0 --port 8099
```
Then point your MCP client at it:
```json
{
"mcpServers": {
"makemkv": {
"url": "http://YOUR_IP:8099/mcp"
}
}
}
```
### With Docker
```bash
# Edit docker-compose.yaml to set your output path and drive device
docker-compose up -d
```
The container exposes port `8099` by default and expects the optical drive passed through as a device.
## MCP Tools Reference
| Tool | Type | Description |
|------|------|-------------|
| `makemkv_list_drives` | read-only | List optical drives and disc status |
| `makemkv_scan_disc` | read-only | Scan disc for titles, streams, durations, sizes |
| `makemkv_rip_title` | action | Start ripping a single title (returns job ID immediately) |
| `makemkv_rip_all` | action | Start ripping all titles (returns job ID immediately) |
| `makemkv_backup_disc` | action | Full disc backup (returns job ID immediately) |
| `makemkv_job_status` | read-only | Check job progress, status, and result |
| `makemkv_list_jobs` | read-only | List recent jobs with optional status filter |
| `makemkv_cancel_job` | destructive | Cancel a queued or running job |
| `makemkv_eject` | action | Eject disc from drive |
| `makemkv_monitor` | action | Start, stop, or check status of the auto-rip monitor |
| `makemkv_get_config` | read-only | Get current configuration as YAML |
| `makemkv_set_config` | action | Update a config value at runtime (in-memory only) |
### Tool details
**`makemkv_list_drives`** — Lists all detected optical drives with disc status. Returns a markdown table (or JSON). Shows disc name and device path for each drive.
**`makemkv_scan_disc`** — Scans a disc and returns all titles with their streams (video, audio, subtitle), durations, sizes, chapter counts, and output filenames. Highlights the longest title.
**`makemkv_rip_title`** / **`makemkv_rip_all`** / **`makemkv_backup_disc`** — All rip operations are **async**. They create a background job, return the job ID immediately, and the rip runs in the background. Use `makemkv_job_status` to check progress. The server prevents double-ripping the same drive.
**`makemkv_set_config`** — Takes a dot-separated key like `auto_rip.enabled` and a value. The value is automatically type-coerced to match the existing type. Changes are in-memory only (not persisted to disk), letting agents tweak settings without file writes.
## Auto-Rip Mode
Auto-rip monitors your drives and automatically starts ripping when a disc is inserted.
### Enable auto-rip
In `config.yaml`:
```yaml
auto_rip:
enabled: true
poll_interval: 30
strategy: "longest"
eject_after: true
```
Or at runtime via an agent:
```
Agent: calls makemkv_set_config(key="auto_rip.enabled", value="true")
Agent: calls makemkv_monitor(action="start")
```
### Strategies
| Strategy | Behavior |
|----------|----------|
| `longest` | Rips only the longest title (usually the main movie) |
| `all` | Rips every title on the disc |
| `min_duration` | Rips all titles longer than `makemkv.min_title_length` seconds |
### How it works
1. The monitor polls drives every `poll_interval` seconds
2. When a new disc is detected (via MD5 fingerprint of drive + disc name), it scans the disc
3. Based on the strategy, it creates rip job(s)
4. After a successful rip, the disc is optionally ejected
5. Notifications are sent through all configured channels
## Notifications
### Discord webhooks
1. Create a webhook in your Discord server (Server Settings > Integrations > Webhooks)
2. Add the URL to your config:
```yaml
notifications:
discord_webhook: "https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN"
```
Discord notifications include color-coded embeds:
| Event | Color | Emoji |
|-------|-------|-------|
| Disc detected | Blue | CD |
| Rip started | Orange | Arrows |
| Rip completed | Green | Check |
| Rip failed | Red | X |
| Disc ejected | Purple | Eject |
Embeds include fields for disc name, job ID, status, progress, duration, and errors as applicable.
### Generic webhooks
For custom integrations (Home Assistant, Slack via incoming webhook, etc.):
```yaml
notifications:
webhook_url: "https://your-service.com/hook"
```
The server POSTs JSON with this structure:
```json
{
"event": "rip_completed",
"data": {
"id": "a3f7c2d1",
"job_type": "rip_title",
"disc_name": "INTERSTELLAR",
"status": "completed",
"progress": 100.0,
"duration_seconds": 2700.5,
"output_dir": "/output/INTERSTELLAR",
"result": {
"success": true,
"files": ["/output/INTERSTELLAR/title00.mkv"]
}
}
}
```
## Agent Notifications
When `notifications.agent_notify` is `true` (the default), the server tracks rip lifecycle events internally. MCP agents see updated state the next time they call `makemkv_job_status` or `makemkv_list_jobs` — completed jobs will show their final status, output files, and duration.
Events tracked:
- **disc_detected** — a new disc was inserted
- **rip_started** — a rip job began processing
- **rip_completed** — a rip job finished successfully
- **rip_failed** — a rip job encountered an error
- **disc_ejected** — a disc was ejected after ripping
## Example Conversations
These show what interacting with an agent connected to makemkv-mcp looks like:
### "What drives do I have?"
```
User: What drives do I have?
Agent: Let me check your optical drives.
> calls makemkv_list_drives()
You have 1 optical drive:
Drive 0: BD-RE ASUS BW-16D1HT — Disc loaded: INTERSTELLAR (/dev/sr0)
```
### "What's on the disc?"
```
User: What's on the disc?
Agent: Scanning the disc now...
> calls makemkv_scan_disc(drive_index=0)
Interstellar (INTERSTELLAR):
Title 0: Interstellar — 2:49:00 — 42.1 GB — 33 chapters (longest)
Title 1: Special Features — 0:45:12 — 8.2 GB
Title 2: Trailer — 0:02:30 — 350 MB
The main movie is Title 0 at 2h49m and 42.1 GB.
```
### "Rip the main movie"
```
User: Rip the main movie.
Agent: Starting the rip now.
> calls makemkv_rip_title(drive_index=0, title_index=0)
Rip job started! Job ID: a3f7c2d1
Disc: Interstellar | Title: 0 | Output: ~/makemkv-output/Interstellar/
I'll check on it for you.
> calls makemkv_job_status(job_id="a3f7c2d1")
Job a3f7c2d1: running — 34.2%
[Later]
> calls makemkv_job_status(job_id="a3f7c2d1")
Done! Interstellar has been saved to ~/makemkv-output/Interstellar/title00.mkv
(42.1 GB). The disc has been ejected. Total time: 45 minutes.
```
### "Start auto-ripping"
```
User: Turn on auto-rip so it grabs the main movie whenever I put a disc in.
Agent: I'll enable auto-rip with the "longest" strategy.
> calls makemkv_set_config(key="auto_rip.enabled", value="true")
> calls makemkv_monitor(action="start")
Auto-rip is now active. Whenever you insert a disc, I'll automatically
rip the longest title (usually the main movie) and eject the disc when done.
```
## Development
```bash
# Clone and install in development mode
git clone https://github.com/hivementality/makemkv-mcp.git
cd makemkv-mcp
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=makemkv_mcp
# Lint
ruff check .
```
### Project structure
```
makemkv_mcp/
server.py # MCP server, tools, CLI entry point
makemkv.py # makemkvcon wrapper, output parser, async runner
jobs.py # Persistent job queue (aiosqlite)
notifications.py # Discord, webhook, agent notifications
drive_monitor.py # Auto-rip polling daemon
config.py # Pydantic config models, YAML loader
platform/ # Platform-specific eject/detect
linux.py
darwin.py
windows.py
tests/
test_parser.py # makemkvcon output parsing
test_jobs.py # Job queue operations
test_config.py # Config loading/saving
test_notifications.py # Notification channels
test_server.py # Integration tests (mocked makemkvcon)
```
## API / Protocol
This server implements the [Model Context Protocol](https://modelcontextprotocol.io) (MCP), an open standard for connecting AI assistants to external tools and data sources. MCP provides a structured way for LLM agents to discover and invoke tools over a transport layer.
makemkv-mcp supports two transports:
- **stdio** — the server communicates over stdin/stdout. Best for local usage where the MCP client runs on the same machine (e.g., Claude Desktop).
- **Streamable HTTP** — the server listens on a port and clients connect via HTTP. Best for network/remote usage where the optical drive is on a different machine than the MCP client.
All tool inputs and outputs follow the MCP tool specification with Pydantic-validated schemas.
## License
MIT — see [LICENSE](LICENSE) file.
TDQS
Scored across 12 tools
Each tool has a clearly distinct purpose with no ambiguity: backup, cancel, eject, get config, job status, list drives, list jobs, monitor, rip all, rip title, scan disc, and set config. The actions and targets are well-defined, making it easy for an agent to select the correct tool.
All tool names follow a consistent 'makemkv_' prefix with snake_case and clear verb_noun patterns (e.g., 'makemkv_backup_disc', 'makemkv_list_drives'). This predictability enhances readability and usability for agents.
With 12 tools, the server is well-scoped for optical disc ripping and management. Each tool serves a specific function in the workflow, from disc handling to job control, without being overly sparse or bloated.
The toolset provides complete coverage for the domain, including disc scanning, ripping (both full and title-specific), job management (status, cancel, list), drive operations (list, eject), configuration handling, and monitoring. There are no obvious gaps that would hinder agent workflows.