openmedia-mcp
# openmedia-mcp
Context-efficient MCP server suite for extracting, analyzing and manipulating
media — **images, PDFs, video, audio** — designed for AI agents.
Works with any MCP-compatible harness (opencode, Claude Code/Desktop, Cursor,
Windsurf, Cline, LM Studio, ...) over stdio, streamable HTTP, or SSE.
## Why
Multimodal models can *see*, but most harnesses give them no clean way to look
at a video, a scanned PDF, or a 20 MB photo without either failing or burning
enormous context. openmedia-mcp fixes that with hard rules:
- **Every visual output is downscaled + recompressed** before it reaches the
model (configurable max dimension / JPEG quality).
- **Every text output is capped** with an explicit truncation marker telling
the model how to fetch more.
- **Frame/page caps per call** (12 frames, 8 pages) prevent accidental
context floods.
- **URLs are first-class**: video page URLs (YouTube + 1000+ sites via
yt-dlp) are fetched once at ≤720p and cached; direct file URLs are cached
with a size cap.
## Requirements
Python ≥ 3.10 plus system binaries (all resolved at call time with actionable
error messages — only the tools you actually call need their binary):
| Binary | Needed for | Arch package |
|---|---|---|
| `ffmpeg`/`ffprobe` | video, audio | `ffmpeg` |
| `yt-dlp` | video URLs, downloads | `yt-dlp` |
| `pdftotext`/`pdftoppm`/`pdfinfo`/`pdfimages` | pdf | `poppler` |
| `tesseract` | image_ocr, pdf_ocr | `tesseract` + language data |
Optional: `pip install 'openmedia-mcp[whisper]'` enables local speech-to-text
(`audio_transcribe`) via faster-whisper.
## Install & run
```bash
# From a local checkout
uv run --project /path/to/openmedia-mcp openmedia-mcp
# Or install as a tool
uv tool install git+https://github.com/Builderstar/openmedia-mcp.git
openmedia-mcp --tools pdf,image
```
### opencode
```json
{
"mcp": {
"openmedia": {
"type": "local",
"command": ["uv", "run", "--project", "/home/you/projects/openmedia-mcp", "openmedia-mcp"]
}
}
}
```
### Claude Desktop / generic MCP config
```json
{
"mcpServers": {
"openmedia": {
"command": "uv",
"args": ["run", "--project", "/home/you/projects/openmedia-mcp", "openmedia-mcp"]
}
}
}
```
### HTTP transport
```bash
openmedia-mcp --transport streamable-http --host 127.0.0.1 --port 8756
```
## Toolsets
Mount only what a given harness needs with `--tools image,pdf,video,audio`
(default: all). `media_probe` is always available.
### image
| Tool | Purpose |
|---|---|
| `image_view` | See an image (auto-downscaled); `region` param zooms into details |
| `image_info` | Format, dimensions, EXIF summary — no pixels spent |
| `image_ocr` | Tesseract text extraction |
| `image_transform` | crop / resize / rotate / flip / grayscale / format convert |
| `image_compare` | Two images side-by-side in one composite |
### pdf
| Tool | Purpose |
|---|---|
| `pdf_info` | Metadata + detects whether a text layer exists |
| `pdf_read` | Text-layer extraction (page ranges, layout mode) |
| `pdf_view` | Render pages as images for the model (scans, figures, layout) |
| `pdf_ocr` | Tesseract OCR for scanned PDFs |
| `pdf_extract_images` | Pull embedded figures/photos to disk |
### video
| Tool | Purpose |
|---|---|
| `video_info` | ffprobe for files; yt-dlp metadata for URLs (no download) |
| `video_frames` | See the video: uniform sampling or exact timestamps |
| `video_transcript` | Captions via yt-dlp (URLs) or embedded subs (files) |
| `video_download` | yt-dlp download with resolution control |
| `video_clip` | Cut sections (stream-copy or re-encode) |
| `video_extract_audio` | Audio track to mp3/m4a/wav/flac/opus |
### audio
| Tool | Purpose |
|---|---|
| `audio_info` | Codec, duration, tags |
| `audio_convert` | Format/bitrate/sample-rate/mono conversion |
| `audio_trim` | Lossless section cut |
| `audio_waveform` | See the waveform as an image |
| `audio_transcribe` | Local Whisper STT (optional `[whisper]` extra) |
## Configuration (env vars)
| Variable | Default | Meaning |
|---|---|---|
| `OPENMEDIA_CACHE_DIR` | `~/.cache/openmedia-mcp` | URL/video download cache |
| `OPENMEDIA_OUTPUT_DIR` | `~/Downloads/openmedia` | Default output location |
| `OPENMEDIA_TEXT_CAP` | `20000` | Default max chars for text outputs |
| `OPENMEDIA_MAX_IMAGE_DIM` | `1024` | Default longest edge for returned images |
| `OPENMEDIA_JPEG_QUALITY` | `80` | Default JPEG quality |
| `OPENMEDIA_MAX_DOWNLOAD_BYTES` | `209715200` | Direct-URL download cap |
## Security and privacy
This server acts with the permissions of the user who starts it. Its tools can
read local media, fetch URLs, run media-processing binaries, and write to
caller-selected output paths. Tool responses may include absolute paths and
media metadata. Only connect trusted MCP clients.
The HTTP transports do not provide authentication. They bind to loopback by
default; do not expose them to another host or an untrusted network without a
separate authenticated proxy and network policy. URL fetching can reach
addresses visible from the host, including private-network services.
The optional Whisper tool downloads and caches the `base` faster-whisper model
on first use. Prepare that model cache in advance for offline operation.
## Development
```bash
uv sync # install deps
uv run python tests/smoke_test.py [sample-video.mp4] # exercises every tool
```
The smoke test generates its own test image and PDF; pass any local video file
to also cover the video/audio toolsets.
## License
MIT
TDQS
Scored across 22 tools
Each tool targets a distinct media type and action, with clear boundaries (e.g., pdf_read vs pdf_ocr vs pdf_view explicitly address text layer vs scanned). The media_probe helper reduces ambiguity by routing to the correct tools. No two tools appear to do the same thing.
All tools follow a strict pattern: media type prefix (image_, pdf_, video_, audio_) followed by a descriptive verb (view, info, transform, read, convert, clip). All snake_case, no mixed conventions, and the pattern makes tool purposes predictable.
22 tools is on the heavy side, but the server covers four distinct media domains (image, PDF, video, audio) each with a logical set of operations. Every tool earns its place given the broad scope, though it slightly exceeds the typical comfortable range.
The surface covers the full lifecycle for each media type: inspection (info/probe), viewing/reading, transformation/conversion, extraction (OCR, transcript, frames, audio), and editing (clip, trim). No obvious dead ends or critical missing operations for the stated purpose.