video-understanding-mcp
video-understanding-mcp
Local stdio MCP server for extracting bounded, reproducible evidence from video.
Early development: Milestones 1 and 2 provide safe video inspection and offline transcription. Timestamped frame extraction is planned next.
The server provides:
video_probe, backed byffprobevideo_transcribe, backed by FFmpeg and whisper.cpptimestamped transcript JSON and Markdown written to caller-selected roots
absolute-path and allowed-root enforcement
symlink-escape protection
bounded, cancellable subprocess execution
content-addressed probe and transcript caching
vu-doctorreadiness checks for FFmpeg, FFprobe, and whisper.cppsynthetic media fixtures and MCP stdio contract tests
Requirements
Node.js 22 or newer
ffmpegffprobewhisper-clia local whisper.cpp GGML model
Install whisper.cpp and bootstrap a model
On macOS with Homebrew:
brew install whisper-cpp
npm run bootstrap:model
export VU_WHISPER_MODEL_PATH="$HOME/.local/share/video-understanding-mcp/models/ggml-large-v3-turbo-q5_0.bin"The bootstrap script downloads the official
ggml-large-v3-turbo-q5_0.bin
model and verifies its Git LFS SHA-256 digest,
394221709cd5ad1f40c46e6031ca61bce88931e6e088c188294c6d5a55ffa7e2,
before reporting the configuration value. A failed checksum leaves no accepted
model. Pass a different destination directory when required:
npm run bootstrap:model -- /absolute/model/directoryThe server never downloads a model or makes any other network request while processing media.
Build and run
git clone https://github.com/kwacky1/video-understanding-mcp.git
cd video-understanding-mcp
npm install
npm run build
VU_ALLOWED_READ_ROOTS="$HOME/Videos" \
VU_ALLOWED_WRITE_ROOTS="$HOME/Documents/transcripts" \
VU_WHISPER_MODEL_PATH="$HOME/.local/share/video-understanding-mcp/models/ggml-large-v3-turbo-q5_0.bin" \
npm startVU_ALLOWED_READ_ROOTS is a path-delimited list. If it is omitted, the server
allows reads only within its current working directory.
Optional configuration:
Variable | Default | Purpose |
| current directory | Readable filesystem roots |
| readable roots | Writable transcript roots |
|
| Maximum accepted input size |
|
| FFprobe executable |
|
| FFmpeg executable |
|
| whisper.cpp executable |
| none | Absolute path to a local GGML model |
| platform cache directory | Content-addressed cache root |
Both root variables are path-delimited lists (: on macOS/Linux, ; on
Windows). Output directories must already exist, resolve inside a configured
writable root, and be writable.
Transcription
video_transcribe accepts:
{
"path": "/absolute/path/demo.mp4",
"output_dir": "/absolute/path/transcripts",
"language": "en"
}It extracts the first audio stream to a temporary 16 kHz mono WAV, runs
whisper-cli locally, and removes scratch files on success, failure, or
cancellation. The result includes timestamped segments and durable
transcript_json_path and transcript_markdown_path values.
The transcript cache key includes the input SHA-256, transcription schema,
canonical parameters, whisper executable fingerprint, and model SHA-256.
Repeating the same call reuses cached transcript artefacts and returns
cache_hit: true; changing the input, language, model, or executable
configuration invalidates the cache.
Doctor
npm run doctor
npm run doctor -- --jsonThe doctor exits non-zero until all three executables are ready. Whisper is reported now so Milestone 2 prerequisites are visible before transcription is added.