EnriVision
EnriVision is an MCP server that lets any model analyze local or remote media by uploading it to EnriProxy and returning text-based server-side extraction and model analysis.
Analyze images, videos, audio, documents (PDF, DOCX, XLSX, PPTX), animated images, and image sets via the
analyze_mediatool.Upload local files (resumable, up to 4 GiB) or download http(s) URLs (up to 64 MiB each; larger solitary URLs escalate to server-side ingestion).
Ask custom questions, provide context hints, and choose response language (Spanish/English and others).
Target video clips by start/duration/end seconds and control frame counts.
Enable or disable audio transcription, with optional Whisper language hints.
Choose analysis modes:
single(fast/cheap),multipass(segmented/batched for long PDFs, videos, image sets), orauto.Continue truncated results with opaque cursors, offsets, and limits.
Zoom into image regions at native resolution using element boxes returned by previous analyses.
Tune multipass behavior: segments, max pages, batch sizes, image dimensions, and scanned-text thresholds.
Receive structured output:
analysis,media_type,extraction, plus optional element boxes and warnings.Handle errors with bilingual messages and machine-readable
structuredContentcodes for retryable failures.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@EnriVision summarize the video at /Users/me/demo.mp4 and transcribe the audio"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
EnriVision
EnriVision is a Model Context Protocol (MCP) server over stdio that uploads local media to EnriProxy and returns server-side extraction + model analysis.
This is useful for media types that many MCP clients cannot read reliably (videos, audio, scanned PDFs, HEIC/AVIF, large files), while keeping the MCP server itself lightweight.
What this project is
An MCP server process your MCP host launches (OpenCode, Claude Code, Codex, etc.)
A thin client for EnriProxy (resumable upload + structured output)
Related MCP server: multimodal-reader-mcp
Requirements
Node.js
>= 24A reachable EnriProxy server with these endpoints enabled:
POST /v1/uploadsHEAD /v1/uploads/:idPATCH /v1/uploads/:idDELETE /v1/uploads/:id(best-effort cleanup of orphaned upload sessions)POST /v1/vision/analyzePOST /v1/vision/segments(cursor continuation for long analyses)GET /v1/account/models(fail-open vision-capability probe before upload)
An EnriProxy API key (configured on the EnriProxy side)
Install
# Global install
npm install -g @bedolla/enrivision
# Or run without installing
npx -y @bedolla/enrivision@latest --helpBuild
npm install
npm run typecheck
npm run buildUsage
1) Configure your MCP host
EnriVision runs as an MCP server over stdio. Your MCP host is responsible for launching the process.
Example: global install
{
"EnriVision": {
"type": "stdio",
"command": "enrivision",
"args": [],
"env": {
"ENRIPROXY_URL": "http://127.0.0.1:8787",
"ENRIPROXY_API_KEY": "YOUR_ENRIPROXY_API_KEY",
"ENRIVISION_DEFAULT_LANGUAGE": "es"
}
}
}Example: no install (always uses whatever npm currently tags as latest)
{
"EnriVision": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@bedolla/enrivision@latest"],
"env": {
"ENRIPROXY_URL": "http://127.0.0.1:8787",
"ENRIPROXY_API_KEY": "YOUR_ENRIPROXY_API_KEY",
"ENRIVISION_DEFAULT_LANGUAGE": "es"
}
}
}{
"EnriVision": {
"type": "stdio",
"command": "node",
"args": ["C:\\Users\\Administrator\\Projects\\EnriVision\\dist\\index.js"],
"env": {
"ENRIPROXY_URL": "http://127.0.0.1:8787",
"ENRIPROXY_API_KEY": "YOUR_ENRIPROXY_API_KEY",
"ENRIVISION_DEFAULT_LANGUAGE": "es"
}
}
}Configuration
EnriVision is configured via environment variables:
ENRIPROXY_URL(string, optional, default:http://127.0.0.1:8787)ENRIPROXY_API_KEY(string, required)ENRIVISION_TIMEOUT_MS(string, optional, default:1800000)Parsed as an integer (milliseconds). This is the operator cap: the per-call analyze timeout is
min(operator, mode budget)withsingle= 10 min (one pass, fast/cheap),multipass/auto= 20 min (per-segment/batch map + reduce;automay escalate to multipass server-side). Uploads are performed in chunks; per-chunk timeouts honormin(operator, derived 30s..300s)floored at 30 s (an operator budget below 30 s never forces tighter single-chunk budgets).
ENRIVISION_DEFAULT_LANGUAGE(string, optional)Default language to send when the tool call does not provide
language.
ENRIVISION_DENY_SYMLINKS(string, optional)Set to
1to reject symlinkedpath/pathsinputs. Strict mode opens withO_NOFOLLOW(POSIX) and compares thedev:inohandle identity fromfstat. On Windows (win32)O_NOFOLLOWis0(advisory only), so strict mode there rests solely on thelstat-vs-fstatcomparison with a small swap window: prefer POSIX hosts when symlink races are in scope.
ENRIVISION_MODEL(string, optional)Model id for server-side dispatch affinity; omit for auto-dispatch.
ENRIVISION_QUIET(string, optional)Set to
1to silence upload/retry progress lines on stderr.
Analysis budgets
The client analyze timeout is min(ENRIVISION_TIMEOUT_MS, mode budget):
single→ 10 min (mirrors EnriCode and the EnriProxy single-pass stage budget).multipass→ 20 min (mirrors EnriCode and the server multipass wall-clock budget).auto(default) → 20 min: the server picks the mode and may escalate to multipass, so the client cannot assume the short budget. If unsure, omit tuning (auto).
Error shape
Tool failures return MCP isError with Spanish-first bilingual text (ES first, EN second) plus machine-readable structuredContent: { code, retryable, httpStatus? } reusing the EnriCode vocabulary:
ENRICODE_ERR_TOOL_INPUT_INVALID— argument/tuning errors (including proxy 400/422). Never retry unchanged (retryable: false).ENRICODE_ERR_TOOL_EXECUTION_FAILED— server/transport failures.retryableis true for 408/429/5xx, false otherwise.ENRICODE_ERR_TOOL_EXECUTION_TIMEOUT— expired upload/analyze budgets (retryable: true; retry with a smaller scope).ENRICODE_ERR_TOOL_EXECUTION_ABORTED— caller-cancelled (retryable: false).
httpStatus is present only when the failure carries a proxy HTTP status.
MCP tools
EnriVision exposes this MCP tool:
analyze_media
General notes:
The tool accepts a single JSON object as its input (the MCP
arguments).At least one of
path,paths, orcursoris required. Whenpathscarries at least one valid entry,pathis ignored (explicit ignore-path contract: sending both is allowed,pathis silently ignored — prefer oneOf semantics and send only one). Acursor(from a truncated response) reads the next window of the list without uploading or analyzing anything.Paths must be absolute on the machine running the MCP server, or http(s) URLs. URLs are downloaded to a temporary directory on the MCP host (up to 64 MiB each; localhost and private-network destinations are blocked) and deleted after analysis. A solitary URL above 64 MiB escalates to EnriProxy's server-side
source_urlingestion (resumable download with extra hops); local files use resumable upload up to 4 GiB.EnriVision does not accept per-call
server_url/api_keyoverrides (these are configured via env vars).Nothing you send is dropped quietly: any unrecognized parameter is rejected with the Spanish coaching
Parámetro no reconocido: <keys>. Parámetros aceptados: <real list>(top level and insidevideo/audio/document/images/region), closed enums (analysis_mode,delivery) reject any present non-null value that is not exactly a valid selector (non-strings included;null/blank count as omitted), and two spellings of the same knob with different values (e.g.max_frames+maxFrames) are rejected — send a single spelling. A flat value that differs from its nested counterpart applies the flat (documented precedence) and declares it inwarnings.
analyze_media
Inputs:
path(string, optional): absolute local file path, or one http(s) URL to download and analyze (up to 64 MiB; a solitary larger URL escalates to server-sidesource_urlingestion).paths(string[], optional): absolute local image paths or http(s) image URLs (useful for UI screenshot sets).context(string, optional): high-level hint (examples:ui,diagram,chart,error,code,meeting,tutorial,photo).question(string, optional): what you want to extract/answer.language(string, optional): preferred response language (ISO 639-1; e.g.,es,en). If omitted, usesENRIVISION_DEFAULT_LANGUAGEwhen set.analysis_mode(string, optional):auto|single|multipass.max_frames(number, optional): single-pass video frames (1..20).model(string, optional): model id for server-side dispatch affinity (max 128 chars; envENRIVISION_MODEL; omit for auto-dispatch).region(object, optional): relative[0,1]zoom box{x, y, width, height}for one image (native-resolution reading of small text); single images only.transcribe(boolean, optional): enable/disable transcription (videos). Has no effect on images/documents (declared inwarnings, ignored).transcription_language(string, optional): whisper hint (auto,es,en, ...).
Continuation:
cursor(string, optional): opaque cursor from a truncated response (segment_summaries_cursorortranscription_segments_cursor); reads the next window without re-analyzing.offset(integer, optional): continuation start index (defaults to the responsenext_offset).limit(integer, optional): continuation window length (1..100; defaults to the server window size).
Video targeting:
video.clip_start_seconds(number, optional)video.clip_duration_seconds(number, optional)video.clip_end_seconds(number, optional; end = start + duration, wins overclip_duration_seconds)
Multipass tuning (advanced; used only for analysis_mode: multipass):
video.segment_seconds(number, optional)video.max_segments(number, optional)video.max_frames_per_segment(number, optional)document.max_pages_total(number, optional)document.pages_per_batch(number, optional)document.max_images_per_batch(number, optional)document.scanned_text_threshold_chars(number, optional)audio.timestamps(boolean, optional)audio.segment_seconds(number, optional)audio.max_segments(number, optional)images.max_images_total(number, optional)images.images_per_batch(number, optional)images.max_dimension(number, optional)
Output:
analysis(string): model-produced analysis.media_type(string): detected media type (video,audio,image,document,image_set).extraction(object): safe metadata summary (internal routing details are stripped).
Example arguments object:
{
"path": "C:\\path\\to\\video.mp4",
"question": "What are the key steps demonstrated?",
"analysis_mode": "auto",
"transcribe": true,
"language": "es"
}Many MCP clients include a built-in Read(...) tool that can ingest local files and attach them to the model request.
This is convenient, but the set of supported formats is limited and can change across client versions.
If the file you need to analyze is not reliably supported by your client (for example .avif, .heic, .svg, videos,
audio, or Office documents), prefer EnriVision MCP so the client can upload bytes and EnriProxy can do extraction reliably.
EnriProxy determines media type using content-type and extension allow-lists.
Videos:
.mp4,.mov,.avi,.mkv,.webm,.m4v,.wmv,.flv,.3gp,.3g2,.ts,.mts,.m2ts,.mpeg,.mpg,.gif
Audio:
.mp3,.mp1,.mp2,.mpa,.mpga,.wav,.aiff,.aif,.aifc,.caf,.flac,.m4a,.m4b,.m4r,.aac,.ogg,.oga,.wma,.opus,.weba,.mka
Images:
.png,.apng,.jpg,.jpeg,.gif,.webp,.avif,.heic,.heif,.tiff,.tif,.bmp,.svg,.ico
Documents:
.pdf,.docx,.pptx,.xlsx
Available Tools
1 toolanalyze_mediaAnálisis de medios EnriVisionARead-onlyIdempotent
Sube y analiza un archivo mediante EnriProxy (extracción del lado servidor + análisis con modelo).
/ Upload and analyze a media file via EnriProxy (server-side extraction + model analysis).
IMPORTANTE para modelos sin visión: la respuesta es SIEMPRE TEXTO (descripción visual generada del lado del servidor y/o transcripción del audio); nunca se devuelven bloques de imagen, así que CUALQUIER modelo puede consumirla — si no puedes ver imágenes, esta herramienta es tu vía para 'ver' archivos multimedia pidiendo la descripción en question.
/ IMPORTANT for models without vision: the response is ALWAYS TEXT (server-side visual description and/or audio transcription); image blocks are never returned, so ANY model can consume it — if you cannot see images, this tool is how you 'see' media by asking for the description in question.
Formatos aceptados — Imágenes estáticas: PNG, JPEG, WebP, TIFF, BMP, AVIF, HEIC/HEIF, SVG. Imágenes animadas: GIF animado, WebP animado, APNG, SVG animado (se extraen fotogramas clave y se describen sus cambios). Video: MP4, WebM, MKV, MOV, AVI y cualquier contenedor/códec decodificable, CON o SIN audio (en video con audio se procesan juntos: fotogramas + transcripción sobre la misma línea de tiempo). Audio: WAV, MP3, OGG (Vorbis/Opus), M4A/AAC, FLAC, ALAC, Opus y cualquier formato común (todo se normaliza a WAV 16 kHz mono antes de transcribir). Documentos: PDF (de texto, escaneado o mixto), Word (.docx), Excel (.xlsx), PowerPoint (.pptx) — con texto e imágenes embebidas — y JSONL. Conjuntos de varias imágenes: use paths.
/ Accepted formats — Static images: PNG, JPEG, WebP, TIFF, BMP, AVIF, HEIC/HEIF, SVG. Animated images: animated GIF, animated WebP, APNG, animated SVG (key frames are extracted and their changes described). Video: MP4, WebM, MKV, MOV, AVI and any decodable container/codec, WITH or WITHOUT audio (video with audio processes both together: frames + transcription on the same timeline). Audio: WAV, MP3, OGG (Vorbis/Opus), M4A/AAC, FLAC, ALAC, Opus and any common format (everything is normalized to 16 kHz mono WAV before transcription). Documents: PDF (text, scanned, or mixed), Word (.docx), Excel (.xlsx), PowerPoint (.pptx) — with embedded text and images — and JSONL. Multiple-image sets: use paths.
Cuándo usarla: PDFs grandes o escaneados donde el Read puede truncar; video/audio u otros binarios que el cliente no puede leer; HEIC/AVIF/TIFF/BMP/APNG/SVG/Office cuando el Read no es confiable; archivos muy grandes con subidas reanudables (hasta 4 GiB).
/ When to use: large or scanned PDFs where client Read may truncate; video/audio or binary media the client cannot Read; HEIC/AVIF/TIFF/BMP/APNG/SVG/Office docs when client Read is unreliable; very large files needing resumable uploads (up to 4 GiB).
Reglas: use path para un archivo, paths para varias imágenes. Cuando paths trae al menos una entrada válida, path se ignora (contrato explícito: mandar ambos se permite, path se ignora en silencio — prefiera semántica oneOf y mande solo uno). Las entradas en blanco se descartan; claves desconocidas en video/audio/document/images se rechazan. question es opcional aquí (obligatoria en EnriCode); attachmentIndex/attachmentId no existen aquí (sólo EnriCode).
/ Rules: use path for one file, paths for several images (UI screenshots/photo sets). When paths carries at least one valid entry, path is ignored (explicit ignore-path contract: sending both is allowed, path is silently ignored — prefer oneOf semantics and send only one). Blank paths entries are discarded; unknown keys inside video/audio/document/images are rejected (check typos like max_pages_totall). question is optional here (required in EnriCode vision.analyze_media); attachmentIndex/attachmentId do not exist here (EnriCode-only).
Presupuestos (timeout = min(ENRIVISION_TIMEOUT_MS del operador, presupuesto del modo)): single = 10 min (una pasada, rápida y barata); multipass = 20 min (por segmentos/lotes + reducción); auto = 20 min (el servidor elige y puede escalar a multipass). Si no sabe cuál usar, omita el afinado (auto).
/ Analysis budgets (client analyze timeout = min(operator ENRIVISION_TIMEOUT_MS, mode budget)): single = 10 min (one pass, fast and cheap, 1 image or simple questions); multipass = 20 min (per-segment/batch map + reduce; PDFs over ~20 pages, long videos, image sets); auto = 20 min (the server picks and may escalate to multipass). If unsure, omit tuning (auto).
Clip de video: para preguntas en un tiempo específico ("¿qué pasa en 12:34?") use video.clip_start_seconds + video.clip_duration_seconds: convierta a segundos (12:34 = 1260+34 = 754), por ejemplo clip_start_seconds=754 y clip_duration_seconds=30. O dé video.clip_end_seconds (fin = inicio + duración, 0-86400 s).
/ Video clip targeting: for time-specific questions ("what happens at 12:34?") use video.clip_start_seconds + video.clip_duration_seconds: convert to seconds (12:34 = 1260+34 = 754) and request a window, e.g. clip_start_seconds=754 and clip_duration_seconds=30. Or give video.clip_end_seconds instead (end = start + duration, 0-86400 s).
Enteros estrictos: los knobs enteros aceptan números o strings enteras completas ("60" vale; "8.0", "8abc" y 7.9 fallan). Los flotantes aceptan decimales ("12.5" vale). transcribe vale true por defecto y no tiene efecto en imágenes/documentos (se declara en warnings, se ignora). Requiere API key válida de EnriProxy (env ENRIPROXY_API_KEY).
/ Strict integers: integer knobs accept numbers or complete integer strings ("60" works; "8.0", "8abc", 7.9 fail). Floats accept decimals ("12.5" works). transcribe defaults to true and has no effect on images/documents (declared in warnings, ignored). Requires a valid EnriProxy API key (env ENRIPROXY_API_KEY, sent as Authorization: Bearer ...).
Errores: las fallas devuelven isError con texto bilingüe más structuredContent {code, retryable, httpStatus?} con el vocabulario EnriCode; retryable marca 429/5xx/timeouts. Si el mensaje trae Detalle del servidor: en el idioma del proxy, repórtelo tal cual. Fotogramas y transcripción comparten la MISMA línea de tiempo. model es el id del modelo para afinidad de dispatch (máximo 128 caracteres o env ENRIVISION_MODEL; omita para auto-dispatch). language controla el idioma de la RESPUESTA; transcription_language aparte el idioma que Whisper espera al TRANSCRIBIR ("auto" = detectar solo).
/ Errors: failures return isError with bilingual text plus structuredContent {code, retryable, httpStatus?} reusing the EnriCode vocabulary (ENRICODE_ERR_TOOL_INPUT_INVALID / EXECUTION_FAILED / EXECUTION_TIMEOUT / EXECUTION_ABORTED); retryable marks 429/5xx/timeouts. If the message carries a Detalle del servidor: fragment in the proxy language, report it verbatim. Video frames and transcription share the SAME video timeline. Animated GIF/WebP/APNG/SVG become representative key frames. model is the active model id for server-side dispatch affinity (max 128 chars, or env ENRIVISION_MODEL; omit for auto-dispatch). Set language (e.g. "es") to match the user language and avoid drift: language controls the analysis RESPONSE language; transcription_language separately controls the language Whisper expects when TRANSCRIBING audio ("auto" = detect only).
Ejemplos mínimos: (1) una imagen: {"path": "/tmp/foto.png", "question": "..."}. (2) clip de video 12:34->754s: {"path": "/tmp/charla.mp4", "question": "...", "video": {"clip_start_seconds": 754, "clip_duration_seconds": 30}}. (3) PDF largo multipass: {"path": "/tmp/manual.pdf", "question": "...", "analysis_mode": "multipass"}. Rutas absolutas del host MCP (en Windows valen C:/...; en POSIX lanzarían error).
/ Minimal examples: (1) single image: {"path": "/tmp/shot.png", "question": "What does each capture show?"}. (2) video clip 12:34->754s: {"path": "/tmp/talk.mp4", "question": "What happens at 12:34?", "video": {"clip_start_seconds": 754, "clip_duration_seconds": 30}}. (3) long PDF multipass: {"path": "/tmp/manual.pdf", "question": "Summarize each chapter.", "analysis_mode": "multipass"}. Absolute MCP-host paths (C:/... drive paths only work on a Windows host; POSIX rejects them).
Continuación: si la respuesta trae has_more con cursor (segment_summaries_cursor o transcription_segments_cursor), pida el resto con solo cursor (+ offset opcional, por defecto next_offset; también limit opcional 1-100 para acotar la ventana). Con cursor no mande path/paths. / Continuation: when the response carries has_more with a cursor (segment_summaries_cursor or transcription_segments_cursor), ask for the rest with only cursor (+ optional offset, defaults to next_offset; optional limit 1-100 bounds the window); never send path/paths with cursor.
Depuración de capturas de UI: abra con un veredicto de una línea; describa zona por zona; aproxime colores como hex; cuantifique defectos de layout; transcriba etiquetas, botones y errores visibles; compare observado vs esperado cuando aplique. / UI-screenshot debugging (when the media are app screenshots): open with a one-line plain verdict; describe zone by zone (header, sidebar, main content, modals, notifications), not as a general scene; approximate colors as hex values (e.g. #1F6FEB) and name them; quantify layout defects (overflows, clipping, overlaps, misalignments, missing spacing, cut text) estimating pixel magnitudes when possible; transcribe labels, buttons, and any visible error/status text; when the request states what was expected, compare observed vs expected explicitly.
Inputs: path, audio, limit, model, +33 more. Returns: analysis, elements, warnings, extraction, +3 more
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 1 tool
Only one tool exists, so there is zero risk of an agent selecting the wrong tool for a task. The single analyze_media tool unambiguously covers any media-analysis request, with no overlapping purposes to confuse.
analyze_media follows the standard verb_noun convention used across well-designed MCP servers. While a single tool offers little evidence of a broader pattern, the name is self-consistent, descriptive, and aligned with common conventions.
A single tool sits at the thin end of the calibration range, where 1-2 tools feels sparse. This is partially redeemed by the tool being a deliberately consolidated mega-tool that absorbs image, video, audio, and document analysis into one entry, but that pushes substantial complexity into a single schema.
For the server's stated purpose — media analysis — coverage is remarkably complete: static and animated images, video with shared audio timeline, transcription, PDFs, Office documents, multi-image sets, video clipping, multipass budgets, and continuation cursors for long outputs. An agent can fully accomplish the server's job with this one tool and no obvious dead ends.
Maintenance
Related MCP Connectors
OCR, transcription, file extraction, and image generation for AI agents via MCP.
The Listenetic MCP server is a remote, cloud-hosted server that enables AI assistants like ChatGPT and Claude to convert articles, documents, websites, and videos into high-quality AI-generated audio. It provides multi-format support for text and binary files, natural-sounding text-to-audio conversion using AI, and specialized processing for SSML, markup, markdown, and various media formats through three core tools: listentic_supported_mimetypes, listentic_add_content_text, and listentic_add_content_binary.
The CustomGPT.ai MCP server is a fully managed, RAG-powered endpoint that connects large language models with private knowledge bases and external data sources. It provides tools for retrieval-augmented generation queries (send_message), data ingestion (upload_file), and source listing, enabling AI agents to query private documents like PDFs with high accuracy and real-time citations.
MCP server for Wan AI video generation
Related MCP Servers
- AlicenseBqualityDmaintenanceAn MCP server that lets AI assistants read and visually analyze local documents — PDFs, Excel spreadsheets, CSV files, Word documents, PowerPoint presentations, and images.457 npm48 PyPIMIT
- FlicenseBqualityDmaintenanceMCP server for analyzing local audio and video files with Google Gen AI, returning structured summaries, timelines, transcripts, and observations.11-

Augentofficial
AlicenseBqualityDmaintenanceMCP server that turns any audio or video source into structured, searchable intelligence for agents, enabling download, transcription, semantic search, speaker identification, and more.226MIT- AlicenseAqualityDmaintenanceMCP server that analyzes images, reads code and ZIP archives, and provides text context for non-vision models.314 npm2MIT