Skip to main content
Glama

🎞️ broll-mcp

Find, preview and cut public-domain b-roll from the Internet Archive, from inside any MCP agent.

Every clip lands on disk with a provenance record next to it: source, license, exact segment and attribution text.

CI License: MIT Python 3.12+ MCP No API key


You:    "I need 8 seconds of children eating bananas, ideally black and white."

Agent → search_footage("children eating bananas")       5 ranked items, license + tier on each
Agent → inspect_item("AboutBan1935")                    scenes with a keyframe image per scene
Agent → extract_clip("AboutBan1935", start_s=300, 8s)   verified H.264 MP4 + provenance JSON
Agent → get_provenance(clip_id)                         "About Bananas" (1935), Prelinger Archives
                                                        via Internet Archive · Public Domain

The agent sees the footage before it cuts: inspect_item returns real keyframe images, so a vision model can pick the shot instead of guessing from titles.

Why

archive.org holds decades of public-domain film (Prelinger, NASA, newsreels, stock footage), but using it from an agent is awkward:

  • Raw item metadata can exceed 1 MB for one item. That's a huge token cost before you've seen a single frame.

  • Licenses differ per item, even inside one collection.

  • Clips cut with -c copy snap to keyframes. An 8 s request came back as 11.35 s.

broll-mcp handles all of this behind four small tools. Responses are compact and cached, and the server applies polite rate limits. Each cut is re-encoded and checked against the requested length.

Related MCP server: heritage-research-mcp

Features

🔎 Brief-driven search

Plain-language briefs become archive.org queries. A two-stage search first requires every term, then matches any term. Local ranking adds collection trust tiers and a black-and-white preference. Results come back 5 per page.

🖼️ Visual inspection

Scene detection runs over HTTPS (PySceneDetect, with ffmpeg as fallback) and returns one keyframe per scene as an MCP image. Items that hold hundreds of clips return a paged clip list with thumbnails.

✂️ Frame-accurate cuts

Cuts are re-encoded to H.264 MP4 with faststart. ffprobe confirms the duration is within ±0.1 s and the decode shows zero errors, and you get 3 check frames back. The same request twice returns the same clip.

📜 Provenance by design

A JSON record sits next to every clip. It holds the source file MD5, the license copied verbatim, commercial_use, the data node, a timestamp and ready-to-paste attribution. Provenance is written before the clip, so a clip never exists without its record.

🤝 Polite to archive.org

Follows archive.org's bot guidance: a descriptive User-Agent, a 1 req/s token bucket, at most 4 media connections, Retry-After support and exponential backoff.

💾 Cache-first

Uses a SQLite WAL cache. Repeating a search, inspection or cut sends 0 upstream requests, and every tool result reports upstream_requests.

Quick start

Requirements: Python 3.12+, uv, and ffmpeg / ffprobe built with HTTPS support (brew install ffmpeg, apt install ffmpeg).

Claude Code

claude mcp add broll -- uvx --from git+https://github.com/edigeh/broll-mcp broll-mcp

Claude Desktop, Cursor and other MCP hosts

{
  "mcpServers": {
    "broll": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/edigeh/broll-mcp", "broll-mcp"],
      "env": { "BROLL_AGENT_MODEL": "claude-opus-5-5" }
    }
  }
}

From a clone

git clone https://github.com/edigeh/broll-mcp && cd broll-mcp
uv sync
uv run broll-mcp          # stdio server; point your host at this command

Try it without an agent using the MCP Inspector:

npx @modelcontextprotocol/inspector --cli uv run broll-mcp \
  --method tools/call --tool-name search_footage --tool-arg 'brief=aerial highway 1950s'

Tools

Tool

What it does

Upstream cost

search_footage(brief, filters?, cursor?)

Ranked items with title, year, trust tier, license, runtime, tile image URL and a short why it matched. Filters: max_tier, license (stated · commercial_ok · any), collections, year_from/to, color.

≤ 4 requests at the default max_tier (2 at tier 1, 6 at tier 3), 0 when cached

inspect_item(identifier, file?, window?, page_size?, cursor?)

Scene mode: scenes with timings plus a keyframe image each, a shotlist excerpt and license. Clip-list mode: for items with many separate clips, a paged list with thumbnails.

a few requests, 0 when cached

extract_clip(identifier, file, start_s, duration_s, label?, audio?, brief?)

Cuts 1–60 s into BROLL_HOME/clips/, verifies it and writes the provenance JSON. Returns 3 check frames.

~3 requests, 0 on repeat

get_provenance(clip_id | identifier, cursor?)

Reads the record for a clip, or for an item and the clips already cut from it. Local only.

always 0

Resource: broll://stats reports request counts by endpoint, cache contents, the active scene detector and the ffmpeg version.

Every tool declares an outputSchema and returns structuredContent. Errors come back as tool results with a stable code, such as NO_RESULTS, ITEM_NOT_FOUND, FILE_NOT_IN_ITEM, RANGE_OUT_OF_BOUNDS, THROTTLED or CUT_VERIFY_FAILED. Each message tells the agent how to recover.

Provenance record

// clips/AboutBan1935__0300.00-0308.00__bananas__4ee00c.provenance.json
{
  "schema": "broll-mcp/provenance/1",
  "clip_id": "clp_20261023_4ee00c",
  "clip_sha256": "78e33da7…",
  "source": {
    "identifier": "AboutBan1935",
    "title": "About Bananas",
    "file": "AboutBan1935.mp4",
    "file_md5": "de484b1b573d28be4860f00a593f4416",
    "derived_from": "AboutBan1935.mpeg",
    "collections": ["prelinger"],
    "tier": 1,
    "date": "1935",
    "creator": "Castle Films"
  },
  "license": {
    "licenseurl": "http://creativecommons.org/licenses/publicdomain/",
    "license_label": "Public Domain (CC PD dedication)",
    "commercial_use": "allowed",
    "attribution_required": "no",
    "determined_from": "licenseurl"
  },
  "segment": { "start_s": 300.0, "duration_s": 8.0, "verified_duration_s": 7.975 },
  "retrieval": { "retrieved_at": "2026-10-23T12:28:30Z", "data_node": "dn600301.us.archive.org", "user_agent": "broll-mcp/0.1.0 (…)" },
  "processing": { "ffmpeg": "8.1.1", "audio": false, "reencoded": true },
  "attribution_text": "\"About Bananas\" (1935), Prelinger Archives via Internet Archive, https://archive.org/details/AboutBan1935. License: Public Domain (CC PD dedication)."
}

License labels come only from an exact URL table covering PD, CC0, the PD Mark, and CC BY / BY-SA / BY-ND / BY-NC variants for versions 2.0–4.0. A URL outside the table is copied verbatim with the label unrecognized and commercial_use: "unknown"; nothing is guessed.

Configuration

Variable

Default

Purpose

BROLL_HOME

platform data dir (~/Library/Application Support/broll-mcp, ~/.local/share/broll-mcp)

Cache, keyframes, clips. The server writes nowhere else.

BROLL_AGENT_MODEL

unspecified

Model name sent in the User-Agent, as archive.org asks of AI agents.

BROLL_CACHE_MAX_MB

2048

Keyframe cache budget; older keyframes are evicted first.

Collection trust tiers live in BROLL_HOME/tiers.toml. Tier 1 is prelinger and nasa, tier 2 is stock_footage and feature_films, and everything else is tier 3. Edit the file to tune ranking and the max_tier filter.

How it works

 MCP host ──stdio──► server.py ── jsonschema validation, result shaping, images
                        │
        ┌───────────────┼──────────────────┬────────────────────┐
   SearchService   SceneService        ClipService          SQLite cache (WAL)
   two-stage query  PySceneDetect /     cut → ffprobe verify  searches · items · scenes
   + local ranking  ffmpeg, keyframes   → provenance → clip   clips · provenance · request_log
        └───────────────┴─────── ArchiveClient ────────────────┘
                     UA · 1 req/s bucket · 4 media slots · backoff
                                    │
                     archive.org (advancedsearch · metadata · download)

The design rests on live archive.org responses captured in research/, which the offline tests also use as fixtures.

Development

uv sync
uv run pytest                 # 155 offline tests (mock transport, captured metadata)
uv run ruff check . && uv run ruff format --check .
uv run python scripts/e2e_smoke.py /tmp/broll-e2e   # live end-to-end over stdio against archive.org

See CONTRIBUTING.md.

A note on rights

broll-mcp copies license information exactly as archive.org publishes it, and it makes no legal judgement. commercial_use: "unknown" means archive.org states no machine-readable license for that item. Check the source item before you publish footage, especially material that carries only a rights statement.

License

MIT for the code. Footage belongs to its respective rights holders under the terms recorded in each clip's provenance file.

Available Tools

4 tools
extract_clipCut a clipA
Idempotent

Cut start_s..start_s+duration_s from a remote archive.org video into a verified H.264 MP4 under BROLL_HOME/clips, with a provenance JSON beside it. Returns 3 check frames. Repeating the same cut returns the existing clip.

Inputs: file (required), start_s (required), duration_s (required), identifier (required), +3 more. Returns: path, cache, clip_id, verified, +3 more

get_provenanceRead provenanceA
Read-only

Read the provenance record of a clip (clip_id) or the license/source record of an item plus clips already cut from it (identifier). Local records only; never contacts archive.org.

Inputs: cursor, clip_id, identifier. Returns: item, kind, cache, clips, +4 more

inspect_itemInspect an item's scenesA
Read-only

Show what is inside an archive.org item. For one video: detected scenes with a keyframe image each (paged), plus shotlist excerpt and license. For items holding many separate clips: a paged clip list with one thumbnail per clip; call again with file=.

Inputs: identifier (required), file, cursor, window, +1 more. Returns: file, mode, tier, cache, +16 more

search_footageSearch archive.org footageA
Read-only

Turn a written shot brief into up to 5 ranked archive.org video items with license, collection tier and why each matched. Page with next_cursor. Text matching runs on archive.org; ranking is local.

Inputs: brief (required), cursor, filters. Returns: cache, error, terms, results, +4 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.1/5.0

    Scored across 4 tools

    Disambiguation4/5

    Each tool maps to a distinct stage: search remote footage, inspect a remote item, extract a clip locally, and read local provenance. There is minor overlap because both inspect_item and get_provenance can return license/source information for an item, but the remote-vs-local distinction is clearly stated.

    Naming Consistency5/5

    All four names follow a consistent snake_case verb_noun pattern: search_footage, inspect_item, extract_clip, get_provenance. The convention is predictable and immediately readable.

    Tool Count5/5

    Four tools are well-scoped for a focused footage search, inspection, extraction, and provenance workflow. Each tool has a clear role and none appears redundant.

    Completeness4/5

    The surface covers the core lifecycle from discovery through extraction and provenance, with paging and repeat-cut handling described. Minor gaps exist around managing or listing already extracted clips, but agents can work around this through provenance lookups.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      Enables AI assistants to search and retrieve historical materials from five public archives in a unified format, including full-text search inside scanned books, rights statements, and provenance-tracked media downloads.
      23
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to read videos from YouTube links, web pages, media URLs, or local files by returning timestamped transcripts, labelled frame contact sheets, and lossless audio or spectrograms. Also searches YouTube, channels, pages, and folders to find videos worth reading.
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to source real, license-labelled photos and video clips of the exact person, company, product, or place named in a script, with each candidate checked by a vision model and scored before returning download links or capture commands. It also plans b-roll across a whole transcript, matching each moment to the words it plays over.
      4
      MIT