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: broll-studio-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, collections, 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.

≀ 2 requests, 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.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. Any value the table doesn't recognize is reported as unknown, never 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)

ARCHITECTURE.md has the full design, built on evidence (E1–E16) from live archive.org responses. Raw captures are in research/.

Development

uv sync
uv run pytest                 # 76 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.

NameRequiredDescriptionDefault
fileYes
audioNoB-roll is usually silent; false strips audio.
briefNoThe brief this clip answers; stored in the provenance record.
labelNoShort name used in the output file name.
start_sYes
duration_sYes
identifierYes

Output Schema

NameRequiredDescription
pathYes
cacheYes
clip_idYes
verifiedYes
provenanceYes
provenance_pathYes
upstream_requestsYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (write, idempotent, open-world), the description discloses the output container and codec, the destination directory, and the sidecar provenance file, plus that 3 check frames are returned. It does not mention failure modes (e.g., download errors, invalid time ranges) or that audio is stripped/handled, but the added context is substantial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences with zero filler, front-loading the core action and slice definition, then the output artifact and idempotency behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description needn't detail the returned frames, and it already covers output format, location, and idempotent repeat behavior. Missing pieces are prerequisites and the semantics of the optional audio/brief/label parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 43%, yet the description only clarifies start_s and duration_s semantics (the slice definition) and hints at identifier/file via 'remote archive.org video'. Optional parameters audio, brief, and label are not explained in the description, so it only partly compensates for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (cut), the resource (a remote archive.org video), the exact time slice derived from start_s and duration_s, and the output artifact (verified H.264 MP4 under BROLL_HOME/clips plus a provenance JSON). This is clearly distinguishable from search_footage, inspect_item, and get_provenance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Conveys implied usage (produce a clip after locating footage) and explicitly notes that repeating the same cut returns the existing clip. However, it never states when to prefer this over siblings like inspect_item or search_footage, nor any preconditions such as inspecting the item first.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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.

NameRequiredDescriptionDefault
cursorNo
clip_idNo
identifierNo

Output Schema

NameRequiredDescription
itemNo
kindYes
cacheYes
clipsNo
recordNo
clips_totalNo
next_cursorNo
upstream_requestsYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so safety is covered; the description adds genuinely new behavior β€” results come from local records, no archive.org round-trip, and the identifier mode also returns clips already cut from the item. Cursor/pagination behavior is not disclosed, which is the remaining behavioral gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence plus one short constraint clause, with the clip vs item distinction front-loaded and zero filler. Every phrase adds information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be explained, and the two access modes plus the offline-only constraint are covered. The only missing piece an agent needs is how cursor-based pagination works, which is absent from both description and schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must carry parameter meaning: it does explain clip_id and identifier semantics and their oneOf exclusivity, but the third parameter (cursor) is never mentioned anywhere, leaving pagination undocumented. Two of three parameters are covered, so it compensates only partially.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb ('Read') and resource ('provenance record') and splits the tool into two clearly described modes keyed on clip_id vs identifier. It does not explicitly differentiate itself from the sibling inspect_item, whose item-level scope could be confused with the 'license/source record of an item' mode here.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear selection rule between the two call modes (clip-level provenance vs item license plus derived clips) and states a hard scope limit: local records only, never contacts archive.org. It stops short of naming when to prefer a sibling tool such as inspect_item or search_footage instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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=.

NameRequiredDescriptionDefault
fileNoVideo file name from a previous inspect_item. Omit to let the server choose the best playable file; required when the item holds many separate clips.
cursorNo
windowNoLimit scene detection to this span. At most 900 s. Defaults to the first 900 s.
page_sizeNo
identifierYes

Output Schema

NameRequiredDescription
fileNo
modeYes
tierYes
cacheYes
clipsNo
titleYes
scenesNo
windowNo
licenseYes
detectorNo
identifierYes
resolutionNo
clips_totalNo
next_cursorYes
other_filesNo
scenes_totalNo
file_length_sNo
shotlist_excerptNo
upstream_requestsYes
transcript_availableNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already establish read-only and open-world behavior, and the description adds meaningful context: paged scene results with keyframes, shotlist excerpt and license, or a paged clip list with thumbnails. It also discloses the follow-up pattern needed when an item contains many clips. It does not cover auth, rate limits, or failure behavior, but it adds solid operational detail beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two tight sentences with no wasted language, and it front-loads the overall purpose before branching into the two item shapes. The conditional follow-up instruction is embedded without clutter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a five-parameter read-only inspection tool with an output schema and existing annotations, the description covers the main item shapes and follow-up behavior well. The remaining gap is paging parameter semantics, but the presence of an output schema and schema-defined defaults/maximums makes the definition largely complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is low at 40%, so the description needs to compensate. It explains file usage and implies paging for both modes, but cursor, page_size, and window semantics are left mostly to the schema, with cursor and page_size lacking textual descriptions in both places.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: showing what is inside an archive.org item. It clearly distinguishes the two inspection modes (single video scenes vs. many separate clips), but it does not differentiate itself from siblings such as search_footage or extract_clip.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives useful conditional guidance for the two internal modes, including calling again with file=<name> when an item has many separate clips. However, it does not say when to use inspect_item instead of the sibling tools, so alternative routing remains implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

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.

NameRequiredDescriptionDefault
briefYesWhat the shot must show, in plain words. Example: 'aerial view of a 1950s highway interchange with cars'.
cursorNonext_cursor from a previous call with the same brief and filters.
filtersNo

Output Schema

NameRequiredDescription
cacheYes
errorNo
termsNo
resultsYes
query_idYes
next_cursorYes
total_upstreamYes
upstream_requestsYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly and openWorld, but the description adds real context: results are capped at 5, ranked, and annotated with license, collection tier and match rationale. It also discloses that text matching happens remotely on archive.org while ranking is local, which matters for latency and failure expectations. Pagination mechanics are mentioned but not detailed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, each load-bearing: output shape first, pagination second, execution model third. No filler and well front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not enumerate return fields, yet it usefully summarizes them, and it covers the remote-search/local-rank split that an agent should know before calling. Minor gap: no guidance on how many results to expect per page or what an empty result means.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67% and the schema already documents brief, cursor and the filter semantics (license modes, tier meaning). The only added meaning is tying the cursor parameter to the next_cursor output, which is a modest but genuine clarification. Baseline 3 is appropriate since the schema carries most of the weight.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: turning a written shot brief into ranked archive.org video items, capped at 5. That is clearly distinguishable from siblings like inspect_item, extract_clip and get_provenance, which act on items rather than search for them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'turn a written shot brief into...' establishes the entry condition clearly, and 'Page with next_cursor' signals the follow-up call. It does not explicitly say when not to use it or when to switch to inspect_item, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 4 tool updatesv0.1.0
    • First observedextract_clip
    • First observedget_provenance
    • First observedinspect_item
    • First observedsearch_footage

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 issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Provides access to the Internet Archive Wayback Machine to list snapshots, fetch archived web pages, and search archive.org items. Enables retrieval of historical website content and metadata through natural language queries.
    3
    4
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to search, retrieve, transcribe, and summarize a local audio/video library over MCP, with timestamps and saved reports.
    4
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to retrieve the closest archived snapshot of a web page, list historical captures over a date range, and count or bound when a URL was first and last archived.
    41 npm
    MIT