ADR-0638: MCP P1 surface — vmaf-tune integration, list_extractors, describe_model, progress notifications¶
- Status: Accepted
- Date: 2026-05-19
- Deciders: Lusoris, Claude (Anthropic)
- Tags:
mcp,vmaf-tune,api,docs
Context¶
The MCP server shipped seven tools in the P0 surface (ADR-0172 / ADR-0495 / ADR-0513). The P1 scope adds five new tools and cross-cutting progress notifications:
-
list_extractors— enumerate allVmafFeatureExtractorimplementations in the C source tree without requiring a running binary. Fills a gap: agents had no programmatic way to discover what feature names are available. -
describe_model— return metadata (type, feature list, size) for a named VMAF model. The prior agent (a770012d) identified a realPath.stembug: for a model namedvmaf_v0.6.1,Path("vmaf_v0.6.1").stemreturns"vmaf_v0.6"(Python strips".1"as if it were a file extension). The fix matches model files by stripping only known extensions (.json,.pkl,.onnx) viaos.path.splitext, not by usingPath.stem. -
run_compare— wrapvmaf-tune compare, surfacing codec-comparison reports over MCP. Fills the gap between the existingrun_benchmark(fixed harness) and the ability to run arbitrary codec comparisons. -
run_ladder— wrapvmaf-tune ladder, building per-title bitrate ladders. -
run_tune_per_shot— wrapvmaf-tune tune-per-shot, providing per-shot CRF recommendations over MCP. -
Progress notifications (cross-cutting) —
run_benchmark,run_compare,run_ladder, andrun_tune_per_shotall emitnotifications/progresswhen the client supplies a_meta.progressToken(MCP spec §notifications/progress). These tools run 30 s–3 min; without progress the client has no feedback.
The vmaf-tune tools wrap the vmaf-tune CLI binary rather than importing the Python package directly. The MCP server runs in a separate process from the container's Python environment; editable-install state of vmaf-tune may differ. Wrapping the binary is the stable integration seam.
Decision¶
We will add five new tools to mcp-server/vmaf-mcp/src/vmaf_mcp/server.py: list_extractors, describe_model, run_compare, run_ladder, run_tune_per_shot. We will retrofit progress notifications onto run_benchmark and all three new run_* tools using the mcp library's server.request_context.session.send_progress_notification() API. The _vmaftune_binary() resolver follows the same priority-list pattern as the existing _vmaf_binary() resolver (env var → PATH → in-tree fallback). The _strip_model_ext() helper replaces any Path.stem usage in model name matching, fixing the .1 truncation bug permanently.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Import vmaftune Python package directly | No subprocess overhead; structured return values | MCP server and vmaf-tune may be in different venvs; circular editable-install coupling | Subprocess is the stable seam |
| Parse C headers for extractor names | Matches the public API surface | Headers don't always carry the name string; only the .c struct definitions do | C source parse is authoritative |
Use Path.stem with a pre-strip | Shorter code | Still wrong for vmaf_v0.6.1 if caller passes a bare name | os.path.splitext with extension whitelist is unambiguous |
| Finer-grained progress (per encode) | Better UX for long runs | vmaf-tune gives no hook for per-encode progress from subprocess | Start + completion notifications are what the subprocess model allows |
Consequences¶
- Positive: MCP clients can now enumerate extractors, inspect model metadata, and drive vmaf-tune workflows without shell access. Progress notifications unblock use of
run_*tools from clients with timeout guards. - Negative: The vmaf-tune tools require
vmaf-tuneto be installed; the error message is clear but the tools are silently unavailable in a CPU-only MCP install without vmaf-tune. - Neutral / follow-ups:
list_extractorsparses the source tree, so it returns all registered extractors regardless of which backends were compiled in. A future tool could filter by the running binary's compiled-in backends. Therun_*tools accept--format jsonand parse stdout; non-JSON stdout (e.g. HLS manifest) is returned as a raw string under{"manifest": "..."}.
References¶
- Prior agent session: a770012d89c6aef9d — identified Path.stem bug mid-debug.
- MCP spec §notifications/progress: https://modelcontextprotocol.io/docs/specification/server/notifications/progress
- req: "Second attempt at MCP P1 surface expansion. Prior agent died mid-debug after finding a real Path.stem bug."
- ADR-0172 (describe_worst_frames / T6-6)
- ADR-0495 (backend-probe allowlist)
- ADR-0513 (run_benchmark / bench_all.sh)
- ADR-0638 stub reserved by
scripts/adr/next-free.sh --claim mcp-p1-vmaftune-extractors-models-progress