媒体分析MCP服务器

EnriVision是一个基于Model Context Protocol(MCP)的服务器,通过stdio将本地媒体上传至EnriProxy,并返回服务器端提取与模型分析结果,适用于视频、音频、扫描PDF、HEIC/AVIF等MCP客户端难以可靠读取的媒体类型。

  • by Bedolla
  • TypeScript
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 Bedolla/EnriVision

使用说明

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)

Requirements

  • Node.js >= 24
  • A reachable EnriProxy server with these endpoints enabled:
    • POST /v1/uploads
    • HEAD /v1/uploads/:id
    • PATCH /v1/uploads/:id
    • DELETE /v1/uploads/:id (best-effort cleanup of orphaned upload sessions)
    • POST /v1/vision/analyze
    • POST /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 --help

Build

npm install
npm run typecheck
npm run build

Usage

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"
    }
  }
}
Use a local dev checkout
{
  "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) with single = 10 min (one pass, fast/cheap), multipass/auto = 20 min (per-segment/batch map + reduce; auto may escalate to multipass server-side). Uploads are performed in chunks; per-chunk timeouts honor min(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 1 to reject symlinked path/paths inputs. Strict mode opens with O_NOFOLLOW (POSIX) and compares the dev:ino handle identity from fstat. On Windows (win32) O_NOFOLLOW is 0 (advisory only), so strict mode there rests solely on the lstat-vs-fstat comparison 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 1 to 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. retryable is 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
Tool inputs (option-by-option)

General notes:

  • The tool accepts a single JSON object as its input (the MCP arguments).
  • At least one of path, paths, or cursor is required. 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). A cursor (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_url ingestion (resumable download with extra hops); local files use resumable upload up to 4 GiB.
  • EnriVision does not accept per-call server_url/api_key overrides (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 inside video/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 in warnings.

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-side source_url ingestion).
  • 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, uses ENRIVISION_DEFAULT_LANGUAGE when 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; env ENRIVISION_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 in warnings, ignored).
  • transcription_language (string, optional): whisper hint (auto, es, en, ...).

Continuation:

  • cursor (string, optional): opaque cursor from a truncated response (segment_summaries_cursor or transcription_segments_cursor); reads the next window without re-analyzing.
  • offset (integer, optional): continuation start index (defaults to the response next_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 over clip_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"
}
Claude Code CLI Read(...) compatibility (reference)

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.

Supported media types (by extension)

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