muvid.mcp

muvid MCP server — the music-visualizer tool surface for a remote connector.

Optional subpackage (extra muvid[mcp]: fastmcp + py2mcp + nw). import muvid never imports this. The connector references the tools by name via TOOL_REFS; register_tools() aggregates them onto a host FastMCP server (the unified reelee AV connector, thorwhalen/muvid#3), and build_server() assembles a standalone server for local (stdio) testing.

Almost every tool is free. The one exception is propose_lyric_treatments_ai (COSTED_TOOLS), which calls an LLM to author a lyric-video treatment — muvid’s first tool that spends money. It is a separate tool from the free heuristic proposer because a host meters by tool NAME and cannot see an argument, so a “free unless you pass a flag” tool is unmeterable by construction. Its cost is reported as UNKNOWN rather than zero: muvid’s budget gate is conjunctive and an unpriced call must force approval (muvid#47).

Module Attributes

TOOL_NAMES

All tools this package exposes (all free).

FREE_TOOLS

Alias — muvid has no costed tools.

TOOL_REFS

Bare tool name → its module:function reference (tools live in three modules).

Functions

register_tools(server, *[, prefix, include, ...])

Register muvid's MCP tools onto an EXISTING FastMCP server — the aggregation seam for a host connector (the unified reelee connector, muvid#3).

build_server(*[, name, instructions, auth, ...])

Assemble a standalone FastMCP server exposing muvid's tools (stdio dev/testing).

current_email()

The caller's identity for the in-flight tool call (raises if unauthenticated).

token_email()

The verified caller's email from the OAuth token (email claim, else sub).

use_email(email)

Bind the caller identity for the duration of the block (local/stdio/testing).

data_root()

The muvid data root: $MUVID_DATA_HOME or ~/.local/share/muvid.

Classes

VisualizerWorkspace(email, root)

A single caller's private visualizer area, addressed by email.

muvid.mcp.FREE_TOOLS = ['list_visuals', 'list_projects', 'project_status', 'render_visualizer', 'footage_status', 'set_song', 'add_footage', 'remove_footage', 'align_footage', 'footage_set_offset', 'footage_clear_offset', 'footage_set_has_song', 'footage_timeline', 'beat_grid', 'footage_peaks', 'footage_beat_signals', 'footage_filmstrips', 'footage_filmstrip', 'list_strategies', 'propose_edit', 'footage_save_edit', 'footage_edits', 'footage_explain_edit', 'footage_get_edit', 'footage_replace_edit', 'footage_set_cut', 'footage_split_cut', 'footage_merge_cut', 'footage_fit_to_beat', 'footage_set_span', 'footage_rename_edit', 'footage_looks', 'footage_undo_edit', 'footage_redo_edit', 'footage_delete_edit', 'footage_render', 'footage_renders', 'footage_editor_document', 'add_footage_folder', 'assemble_music_video', 'list_music_video_projects', 'footage_edl_from_annotations', 'score_footage', 'footage_scores', 'footage_score_status', 'list_archetypes', 'analyze_song_lyrics', 'propose_lyric_treatments', 'validate_lyric_treatment', 'render_lyric_video', 'list_subgenres', 'render_subgenre']

Alias — muvid has no costed tools.

muvid.mcp.TOOL_NAMES = ['list_visuals', 'list_projects', 'project_status', 'render_visualizer', 'footage_status', 'set_song', 'add_footage', 'remove_footage', 'align_footage', 'footage_set_offset', 'footage_clear_offset', 'footage_set_has_song', 'footage_timeline', 'beat_grid', 'footage_peaks', 'footage_beat_signals', 'footage_filmstrips', 'footage_filmstrip', 'list_strategies', 'propose_edit', 'footage_save_edit', 'footage_edits', 'footage_explain_edit', 'footage_get_edit', 'footage_replace_edit', 'footage_set_cut', 'footage_split_cut', 'footage_merge_cut', 'footage_fit_to_beat', 'footage_set_span', 'footage_rename_edit', 'footage_looks', 'footage_undo_edit', 'footage_redo_edit', 'footage_delete_edit', 'footage_render', 'footage_renders', 'footage_editor_document', 'add_footage_folder', 'assemble_music_video', 'list_music_video_projects', 'footage_edl_from_annotations', 'score_footage', 'footage_scores', 'footage_score_status', 'list_archetypes', 'analyze_song_lyrics', 'propose_lyric_treatments', 'propose_lyric_treatments_ai', 'validate_lyric_treatment', 'render_lyric_video', 'list_subgenres', 'render_subgenre']

All tools this package exposes (all free). Bare names; a host may prefix them.

muvid.mcp.TOOL_REFS = {'add_footage': 'muvid.mcp.footage_tools:add_footage', 'add_footage_folder': 'muvid.mcp.footage_tools:add_footage_folder', 'align_footage': 'muvid.mcp.footage_tools:align_footage', 'analyze_song_lyrics': 'muvid.mcp.lyricvid_tools:analyze_song_lyrics', 'assemble_music_video': 'muvid.mcp.footage_tools:assemble_music_video', 'beat_grid': 'muvid.mcp.footage_tools:beat_grid', 'footage_beat_signals': 'muvid.mcp.footage_tools:footage_beat_signals', 'footage_clear_offset': 'muvid.mcp.footage_tools:footage_clear_offset', 'footage_delete_edit': 'muvid.mcp.footage_tools:footage_delete_edit', 'footage_editor_document': 'muvid.mcp.footage_tools:footage_editor_document', 'footage_edits': 'muvid.mcp.footage_tools:footage_edits', 'footage_edl_from_annotations': 'muvid.mcp.footage_tools:footage_edl_from_annotations', 'footage_explain_edit': 'muvid.mcp.footage_tools:footage_explain_edit', 'footage_filmstrip': 'muvid.mcp.footage_tools:footage_filmstrip', 'footage_filmstrips': 'muvid.mcp.footage_tools:footage_filmstrips', 'footage_fit_to_beat': 'muvid.mcp.footage_tools:footage_fit_to_beat', 'footage_get_edit': 'muvid.mcp.footage_tools:footage_get_edit', 'footage_looks': 'muvid.mcp.footage_tools:footage_looks', 'footage_merge_cut': 'muvid.mcp.footage_tools:footage_merge_cut', 'footage_peaks': 'muvid.mcp.footage_tools:footage_peaks', 'footage_redo_edit': 'muvid.mcp.footage_tools:footage_redo_edit', 'footage_rename_edit': 'muvid.mcp.footage_tools:footage_rename_edit', 'footage_render': 'muvid.mcp.footage_tools:footage_render', 'footage_renders': 'muvid.mcp.footage_tools:footage_renders', 'footage_replace_edit': 'muvid.mcp.footage_tools:footage_replace_edit', 'footage_save_edit': 'muvid.mcp.footage_tools:footage_save_edit', 'footage_score_status': 'muvid.mcp.scoring_tools:footage_score_status', 'footage_scores': 'muvid.mcp.scoring_tools:footage_scores', 'footage_set_cut': 'muvid.mcp.footage_tools:footage_set_cut', 'footage_set_has_song': 'muvid.mcp.footage_tools:footage_set_has_song', 'footage_set_offset': 'muvid.mcp.footage_tools:footage_set_offset', 'footage_set_span': 'muvid.mcp.footage_tools:footage_set_span', 'footage_split_cut': 'muvid.mcp.footage_tools:footage_split_cut', 'footage_status': 'muvid.mcp.footage_tools:footage_status', 'footage_timeline': 'muvid.mcp.footage_tools:footage_timeline', 'footage_undo_edit': 'muvid.mcp.footage_tools:footage_undo_edit', 'list_archetypes': 'muvid.mcp.lyricvid_tools:list_archetypes', 'list_music_video_projects': 'muvid.mcp.footage_tools:list_music_video_projects', 'list_projects': 'muvid.mcp.tools:list_projects', 'list_strategies': 'muvid.mcp.footage_tools:list_strategies', 'list_subgenres': 'muvid.mcp.subgenre_tools:list_subgenres', 'list_visuals': 'muvid.mcp.tools:list_visuals', 'project_status': 'muvid.mcp.tools:project_status', 'propose_edit': 'muvid.mcp.footage_tools:propose_edit', 'propose_lyric_treatments': 'muvid.mcp.lyricvid_tools:propose_lyric_treatments', 'propose_lyric_treatments_ai': 'muvid.mcp.lyricvid_tools:propose_lyric_treatments_ai', 'remove_footage': 'muvid.mcp.footage_tools:remove_footage', 'render_lyric_video': 'muvid.mcp.lyricvid_tools:render_lyric_video', 'render_subgenre': 'muvid.mcp.subgenre_tools:render_subgenre', 'render_visualizer': 'muvid.mcp.tools:render_visualizer', 'score_footage': 'muvid.mcp.scoring_tools:score_footage', 'set_song': 'muvid.mcp.footage_tools:set_song', 'validate_lyric_treatment': 'muvid.mcp.lyricvid_tools:validate_lyric_treatment'}

Bare tool name → its module:function reference (tools live in three modules).

class muvid.mcp.VisualizerWorkspace(email, root)[source]

Bases: object

A single caller’s private visualizer area, addressed by email.

email and every project_id are validated as single path components, so a caller can never escape their own subtree.

create_project(project_id, *, title='', force=False)[source]

Create (and return) a new visualizer bucket under this user.

Return type:

VisualizerProject

list_projects()[source]

This user’s buckets: [{project_id, title}] (newest-modified first).

Return type:

list[dict]

open_project(project_id)[source]

Open an existing visualizer bucket (raises if it doesn’t exist).

Return type:

VisualizerProject

muvid.mcp.build_server(*, name='muvid', instructions="muvid music-visualizer — turn a song into a 16:9, YouTube-ready visualizer video (+ thumbnail), deterministically and for free (ffmpeg only, no AI, no keys).\n\nWorkflow:\n1. Create a project: create_project(genre='music-visualizer', template='<look>'). See list_visuals() for the looks (still / cqt / bars / spectrum / waves / scope) or use 'auto'.\n2. Render: render_visualizer(project_id, audio='<https URL to the song>', cover='<https URL to the cover>', visual='<look>'). Audio/cover are direct media URLs, fetched server-side; the 'still' look needs a cover.\n3. Inspect: project_status(project_id) lists your renders (paths + the platform-check verdict).\n\nAll tools are free. Renders are stored server-side in your project bucket.", auth=None, middleware=None)[source]

Assemble a standalone FastMCP server exposing muvid’s tools (stdio dev/testing).

The hosted path aggregates onto the reelee connector via register_tools(); this is the convenience builder for muvid.mcp on its own.

muvid.mcp.current_email()[source]

The caller’s identity for the in-flight tool call (raises if unauthenticated).

Resolves from the explicit use_email() override when present (local/stdio/ tests), else the verified OAuth token — so tools work under any host middleware, and an unauthenticated call is failed closed.

Return type:

str

muvid.mcp.data_root()[source]

The muvid data root: $MUVID_DATA_HOME or ~/.local/share/muvid.

Public API (muvid.mcp re-exports it), so the name stays though the body moved. A forwarder, not an alias, for the introspection reason given on the footage twin.

Return type:

Path

muvid.mcp.register_tools(server, *, prefix='', include=None, exclude=None)[source]

Register muvid’s MCP tools onto an EXISTING FastMCP server — the aggregation seam for a host connector (the unified reelee connector, muvid#3).

Mirrors braidio.mcp.register_tools / falaw.bridges.mcp.register_tools. prefix namespaces the tool names (e.g. "muvid_") to avoid collisions; include / exclude (sets of bare names) select a subset. Returns the registered (prefixed) names. The host installs identity/metering separately — muvid’s tools resolve the caller via current_email(), which works under any host middleware.

muvid.mcp.token_email()[source]

The verified caller’s email from the OAuth token (email claim, else sub).

Lowercased, or None when there is no request/token context — deliberately no fallback, so a caller is failed closed rather than handed a shared identity.

Return type:

Optional[str]

muvid.mcp.use_email(email)[source]

Bind the caller identity for the duration of the block (local/stdio/testing).

Modules

footage_tools

MCP tools for the footage-aligned music_video genre (thorwhalen/reelee#229).

identity

Caller identity for the muvid MCP tools — resolved from the OAuth token, fail-closed.

scoring_tools

MCP tools for the footage SCORING layer (thorwhalen/muvid#13).

workspace

Per-user output bucket for the muvid music-visualizer MCP genre.