video-evidence-mcp
A self-hosted, read-only MCP service that searches public YouTube and Bilibili videos and produces compact evidence packages with verified metadata, timestamped captions or ASR, frames, OCR, and contact sheets for ChatGPT/Codex analysis.
README
video-evidence-mcp
video-evidence-mcp is a self-hosted, read-only MCP service and a video-evidence ChatGPT/Codex plugin. It searches anonymous public YouTube and Bilibili content and produces a compact evidence package: verified metadata, timestamped captions or local ASR, whole-video distributed frames, scene-change frames, Chinese/English OCR, contact sheets, and bounded window reinspection.
The default deployment listens only on 127.0.0.1:8787. Long analyses are queued in Redis and executed by a separate worker; an MCP request only enqueues or polls work. No server-side LLM is required. The calling ChatGPT reads the transcript and ImageContent contact sheet and writes the final explanation.
Code and state are deliberately separate: the checkout contains only code/configuration, while all persistent service state is bind-mounted below the dedicated host directory /data/video-evidence-mcp (app, redis, models, optional Caddy state, and tunnel profile).
Architecture and data flow
ChatGPT/Codex plugin
|
| Secure MCP Tunnel (outbound HTTPS only)
v
127.0.0.1:8787/mcp -> MCP service -> SQLite/WAL job + evidence metadata
|
v
Redis durable queue
|
v
one worker
|
URL/DNS guard -> yt-dlp metadata -> Playwright popup handling
|
captions -> faster-whisper fallback
|
FFmpeg distributed + scene frames -> timestamp overlay
|
RapidOCR -> evidence selection -> WebP sheets
|
retain metadata/transcript/OCR/thumbnails; delete raw media
The four MCP tools are search_videos, start_video_analysis, get_video_analysis, and get_video_window. Every input/output model forbids extra fields. Responses include a trace ID, machine-readable status, warnings, and an error code on failure. get_video_analysis and get_video_window add a compressed WebP ImageContent block when requested.
Security boundaries:
- Input URLs are HTTPS-only canonical YouTube/Bilibili video URLs; playlists, userinfo, non-default ports, and unknown hosts are rejected.
- DNS answers are checked for loopback/private/link-local/reserved addresses. Browser requests are limited to the selected platform and required CDN/API suffixes.
TRUSTED_DNS_PROXY_CIDRis empty by default. A host whose verified transparent proxy maps public names into RFC 2544 benchmarking space may opt into a subnet of198.18.0.0/15; arbitrary private CIDRs are rejected by configuration validation, and the platform/redirect host allowlists still apply.- The adapters only dismiss known close/cancel/continue-without-login/cookie/app prompts. They never enter credentials or bypass CAPTCHA, age, payment, private, or forced-auth controls.
- The private Compose mapping is exactly
127.0.0.1:8787:8787; Redis has no host port.AUTH_MODE=nonerefuses a non-loopback listener unlessTRUSTED_LOOPBACK_PROXY=true, which the private Compose deployment uses only behind that loopback mapping. - The public profile requires an external OIDC/OAuth issuer, validates issuer/audience/scopes/signatures, publishes protected-resource metadata, returns
WWW-Authenticate, rate-limits requests, bounds concurrency, and redacts sensitive headers/query values. Caddy caps public request bodies at 4 MB.
This implementation follows the current OpenAI MCP server guide, plugin packaging guide, authentication guide, ChatGPT connection guide, and Secure MCP Tunnel guide. The server uses the current stable v2 line of the official MCP Python SDK.
Resource guidance
The detected server (Intel N100, 4 cores, 7.5 GiB RAM, no GPU) should keep ANALYSIS_CONCURRENCY=1, ASR_MODEL=small, ASR_COMPUTE_TYPE=int8, standard analysis at 24 frames, and deep analysis at 48 frames. Expect ASR on long videos to be CPU-bound. About 10–15 GiB free disk is a comfortable minimum for images, browser binaries, ASR model cache, and temporary media; this checkout defaults to a 10 GiB evidence limit and a 4 GiB per-job temporary-media limit.
For a supported NVIDIA host, verify nvidia-smi and NVIDIA Container Toolkit first, stop the CPU worker, then build/start worker-gpu:
sudo docker compose stop worker
sudo docker compose --profile gpu up -d --build worker-gpu
The GPU image targets CUDA 12/cuDNN 9. This host has no detected GPU, so only the CPU profile is locally validated.
Local start
cp .env.example .env
sudo ./scripts/prepare_data_dir.sh /data/video-evidence-mcp
sudo docker compose build mcp
sudo docker compose up -d --wait redis mcp worker
curl --fail http://127.0.0.1:8787/healthz
curl --fail http://127.0.0.1:8787/readyz
No inbound home-network port is opened. Do not change the Compose port mapping to 0.0.0.0:8787 while AUTH_MODE=none.
If both getent ahosts www.youtube.com and getent ahosts www.bilibili.com return synthetic 198.18.x.x addresses because this host uses a trusted transparent DNS proxy, set TRUSTED_DNS_PROXY_CIDR=198.18.0.0/15 in the local ignored .env. Leave it empty on ordinary DNS.
For development and tests inside the locked image:
sudo docker compose run --rm --no-deps mcp ruff check .
sudo docker compose run --rm --no-deps mcp mypy src
sudo docker compose run --rm --no-deps mcp pytest
MCP Inspector
The official Inspector CLI can initialize the live Streamable HTTP server and enumerate tools:
npx -y @modelcontextprotocol/inspector@latest --cli \
http://127.0.0.1:8787/mcp --transport http --method tools/list
For the browser UI, run npx -y @modelcontextprotocol/inspector@latest, select Streamable HTTP, and enter http://127.0.0.1:8787/mcp. The automated in-memory equivalent is python scripts/mcp_smoke.py.
Secure MCP Tunnel activation
Secure MCP Tunnel is the preferred private route: the server stays loopback-only and tunnel-client makes outbound HTTPS requests to OpenAI. A Tunnel ID and a control-plane API key cannot be fabricated locally.
-
In OpenAI Platform tunnel settings, create or select a tunnel, associate the intended Platform organization and ChatGPT workspace, and grant the operator Tunnels Read + Use (Manage is needed to create/edit).
-
Download the latest
tunnel-clientfrom the Platform page or the latest publicopenai/tunnel-clientrelease; save it asdeploy/tunnel/tunnel-client, make it executable, and keep it out of Git. -
Create
/etc/video-evidence-mcp/tunnel.envas root with mode0600:TUNNEL_ID=tunnel_... CONTROL_PLANE_API_KEY=sk-... -
Initialize the profile as the dedicated service user from
/data/video-evidence-mcp/tunnel:cd /data/video-evidence-mcp/tunnel set -a . /etc/video-evidence-mcp/tunnel.env set +a /opt/video-evidence-mcp/deploy/tunnel/init-profile.sh tunnel-client doctor --profile video-evidence --explain -
Install
deploy/systemd/video-evidence-compose.serviceanddeploy/systemd/video-evidence-tunnel.serviceunder/etc/systemd/system, then enable them. These are templates; review absolute paths and create the unprivilegedvideo-evidenceuser before installation.
The unit runs doctor before run and restarts on failure. The tunnel-client local admin UI, /healthz, /readyz, and /metrics should remain loopback-only. Secrets never belong in .env, Compose YAML, an image, command-line logs, or this repository.
Add the connection in ChatGPT
Per the current OpenAI flow:
- Open ChatGPT Settings → Security and login → enable Developer mode (subject to account/workspace policy).
- Open ChatGPT Plugins, select
+, enter a name/description, choose Tunnel, and select or paste thetunnel_id. - Review the discovered four tools and create the connection. Refresh metadata after server tool changes.
- Install/enable the
video-evidenceplugin in the same target account/workspace and test the behavior cases underevals/plugin-behavior.json.
The repository marketplace (marketplace.json) and local .mcp.json are development fixtures. They make the plugin visible to a local Codex/desktop development installation; they do not publish or synchronize it to ChatGPT web, desktop, and mobile. Same-account/workspace cross-device use requires creating/installing the corresponding plugin connection in that account/workspace. Public availability requires OpenAI plugin submission/review and a stable public HTTPS endpoint.
To install this repository marketplace in Codex development:
codex plugin marketplace add /absolute/path/to/video-evidence-mcp
After changes, run the cachebuster helper from the installed plugin-creator skill and reinstall the plugin; start a new thread so refreshed skill instructions are loaded.
Optional public HTTPS/OAuth profile
Do not write a password system for this service. Configure a mature external OAuth 2.1/OIDC provider that supports Authorization Code, PKCE S256, the MCP resource parameter/audience, required scopes, and either preferred CIMD (none or private_key_jwt) or DCR. The provider—not this repository—owns login, consent, CIMD/DCR, token issuance, and account security.
Set DOMAIN, OIDC_ISSUER, OIDC_AUDIENCE, OIDC_REQUIRED_SCOPES, and optionally OIDC_JWKS_URL, point public DNS at the server, and explicitly start only the public services:
sudo docker compose --profile public up -d --build redis mcp-public worker-public caddy
Caddy obtains HTTPS automatically. The MCP endpoint is https://<domain>/mcp; metadata is at https://<domain>/.well-known/oauth-protected-resource/mcp. Validate the issuer discovery document advertises Authorization Code, PKCE S256, CIMD or DCR as selected, and correct token authentication methods. Validate tokens include the configured audience and scopes. Never expose the private mcp service or use AUTH_MODE=none on a public listener.
Maintenance and operations
Upgrade deliberately and regenerate the lock; never update one runtime in place:
# All Python dependencies, including yt-dlp/faster-whisper/RapidOCR
sudo docker run --rm -e UV_CACHE_DIR=/app/.uv-cache -v "$PWD:/app" -w /app \
ghcr.io/astral-sh/uv:python3.12-bookworm-slim lock --upgrade
# Prefer Playwright's matching Chromium when its CDN is reachable
sudo docker compose run --rm --user root mcp playwright install chromium
# Rebuild (the image has a distro Chromium fallback for restricted CDNs)
sudo docker compose build --pull --no-cache mcp
sudo docker compose up -d --wait redis mcp worker
# Choose a different ASR model only after sizing CPU/RAM/disk
sed -i 's/^ASR_MODEL=.*/ASR_MODEL=medium/' .env
sudo docker compose up -d worker
Back up /data/video-evidence-mcp while services are stopped, or use SQLite's online backup API. Evidence metadata is in /data/video-evidence-mcp/app/video-evidence.sqlite3, cache files are under /data/video-evidence-mcp/app/cache, Redis AOF/RDB files are under /data/video-evidence-mcp/redis, and ASR downloads are under /data/video-evidence-mcp/models. Restore the matching directory tree and ownership before starting the same application version.
sudo docker compose logs --since 1h mcp worker
sudo docker compose exec mcp video-evidence-cache disk-check
sudo docker compose exec mcp video-evidence-cache cleanup --dry-run
sudo docker compose exec mcp video-evidence-cache cleanup
Cleanup removes only expired/over-limit evidence entries. It never deletes configuration, secrets, the database, Redis state, or ASR models. To uninstall, stop the units/Compose stack first; docker compose down leaves /data/video-evidence-mcp untouched. Archive that directory before explicitly removing it. Remove /etc/video-evidence-mcp/tunnel.env separately and securely.
Known limitations and troubleshooting
- Platform markup, captions, and anonymous-access policy change. When popup fixtures still pass but live access fails, capture only redacted status/selector diagnostics, update the platform adapter's stable roles/attributes/text, and rerun fixture plus live smoke tests.
- The 2026-08-17 build environment reset every Playwright CDN TLS download, so the verified image explicitly launches Debian Chromium. When CDN access returns, install Playwright's matching browser and remove the executable override during a planned rebuild.
- This host's transparent proxy resolves both platforms into
198.18.0.0/15; its ignored local.envexplicitly trusts only that benchmarking CIDR. On another server, remove this setting unless the same mapping is independently verified. - Region restrictions, bot challenges, forced authentication, age gates, private/paid videos, and live streams are reported as limitations; they are not bypassed.
- yt-dlp extraction may break after site changes. Reproduce with
yt-dlp --verbose --skip-download '<canonical-url>'in the worker image, redact request data, then upgrade/lock/rebuild. - Automatic captions, Whisper, and OCR can be wrong, especially for proper names, numbers, overlapping speech, stylized text, and low-resolution frames. The Skill requires transcript/visual window cross-checking for important claims.
- Scene detection plus fixed samples gives whole-video coverage, not frame-complete observation.
get_video_windowis capped and returns cached thumbnails, never arbitrary original media. - The first ASR job downloads the configured model and can take longer. Check worker logs, free disk, and model-volume permissions.
- If Inspector returns
421, check the Host allowlist and connect to exactly127.0.0.1:8787. If readiness is503, check Redis health. If a job was interrupted by restart, it is explicitly marked failed and can be resubmitted. - Optional server-side OpenAI visual description is intentionally disabled by default; the core evidence workflow does not require
OPENAI_API_KEY.
Live smoke tests are opt-in because they contact third-party platforms:
RUN_LIVE_TESTS=1 pytest -m live -vv
python scripts/live_smoke.py
python scripts/live_analysis_smoke.py
Results are written under test-results/ with the URL, UTC date, result, and exact error class. A blocked or rate-limited live test is recorded as such, never reported as passed.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。