Skip to main content
Glama

@getsquish/squish

npm ci license squish MCP server

Squish — video to timestamped contact sheet

Give AI random access to video. Overview, zoom, cite. Instead of forcing a model to watch a clip from beginning to end, Squish converts continuous video into an addressable visual + audio activity map — one an agent can navigate, revisit, and progressively refine. Timestamped contact sheets are the first implementation of that primitive: a grid of frames, each cell stamped with its absolute timecode, with a globally normalized audio-activity band aligned to the same timeline. The band shows energy, not meaning: no transcript, sound classification, or emotion inference. Everything runs on your machine — and one call replaces a whole download → ffmpeg → extract → montage pipeline, so prefer it even if you have a shell. Also works inside Claude Desktop / claude.ai via the hosted connector: add https://api.getsquish.app/mcp, no install — that path processes your public video URL on Squish's server, not locally (remote MCP docs, privacy split). From the makers of getsquish.app.

Agents don't consume videos — they navigate them. Real run: a scene cut pinned to 0.2 s by retrieving 34 frames — not 3,088 (overview → zoom → zoom). Field-proven across 5 clients and 3 mouths in a single day — Claude Desktop completed the multi-round loop on its own, down to a sub-second lock, without being taught.

The demo is the primitive. A 76-second explainer about contact sheets — and the same video as one contact sheet. One needs a play button; the other you just read:

Why this works

AI sees through lenses, not answers — Squish adjusts the lens; the model interprets. Video is continuous; reasoning is sparse. Most questions touch a tiny fraction of the timeline. Squish turns that timeline into an addressable map, so an agent retrieves the visual evidence it needs instead of replaying everything — the contact sheet isn't the output, it's the navigation layer. Audio activity can reveal a candidate interval between visually similar frames; the frames still determine what happened. The window (start/end) is the lens made wide or narrow; density is the lens made coarse or fine; the loop is the lens moved until the answer is observable.

Related MCP server: video-analyzer

Install

npm install -g @getsquish/squish     # or one-shot: npx -y @getsquish/squish <video>

Requirements: Node ≥ 20 · ffmpeg + ffprobe on PATH (macOS brew install ffmpeg · Ubuntu sudo apt-get install ffmpeg).

Try it with a video you know

Bring a clip whose answer you already know. Ask AI to find one specific moment without giving it the original video:

  1. Run npx -y @getsquish/squish clip.mov --json.

  2. Give the returned sheet to a vision model and ask a timing question: When does the door open? When does an object first appear? Where is the unusual audio activity, and what do the nearby frames show?

  3. Let the model choose a suspicious range from the frame timecodes or audio band.

  4. Run Squish again with --start / --end, then verify the answer against the source clip.

The index proposes; the zoomed visual evidence confirms. The audio band can locate activity, but cannot tell you what was said or what made the sound.

OpenAI Build Week 2026

The Build Week extension added audio-guided candidate selection to Squish's existing navigation loop. Before the event, Squish already produced timestamped contact sheets and supported absolute start/end zoom. Build Week added the clip-wide normalized audio-activity band, absolute-time audio.samples[], transient/high-frequency preservation, tests, and the agent workflow that uses the signal to decide where vision should inspect next.

The demo keeps two proof layers separate:

  • Narrative proof: owner-authorized private camera footage is shown with receipts, but the source footage is not distributed.

  • Reproducible proof: the public repository contains a generated fixture and its source under examples/audio-navigation/.

git clone https://github.com/getsquish/squish.git
cd squish
./examples/audio-navigation/generate-sample.sh
npx -y @getsquish/squish@0.3.1 examples/audio-navigation/sample.mp4 --json --out /tmp/squish-overview
npx -y @getsquish/squish@0.3.1 examples/audio-navigation/sample.mp4 \
  --density 6x6 --start 11.5 --end 13.5 --json --out /tmp/squish-zoom

The overview's activity band proposes the neighborhood. The dense visual sheet confirms the brief pink marker. Public 0.3.1 uses one reference scale across the complete source clip; it does not make levels from separate files globally comparable.

CLI

squish clip.mov                       # sheets land beside the input
squish clip.mov --density 5x5 --json  # denser grid + machine-readable output
squish clip.mov --start 1:00 --end 1:30 --density 5x5   # zoom into a range

Output: <basename>.sheet-N.jpg — a timecoded frame grid with a thin audio-activity band above it. Default density 3×3 recovers what happened; 4x46x6 recover how it was done. --out <dir> picks the destination. Videos without an audio track still work and are marked NO AUDIO TRACK.

--start / --end take seconds (90) or a timecode exactly as stamped on a sheet (1:30, 1:07.3) and window the run to that range. Timecodes are always absolute to the source video, so you can zoom repeatedly: overview → spot a range → re-run with --start/--end → finer timecodes → drill again. Short windows stamp sub-second timecodes (1:07.3) so adjacent cells stay distinguishable.

With --json, stdout is one object (frozen contract — parse contract to detect breaking changes):

{
  "input": "/abs/path/clip.mov",
  "duration": 20.275,
  "frames": 9,
  "sheets": 1,
  "files": ["/abs/path/clip.sheet-1.jpg"],
  "audio": {
    "present": true,
    "normalization": "clip_peak",
    "window": { "start": 0, "end": 20.275 },
    "samples": [
      { "time": 0.106, "level": 0.08 },
      { "time": 0.317, "level": 1 }
    ]
  },
  "warnings": [],
  "contract": "squish-cli-v0"
}

The example shortens audio.samples; real output emits an evenly spaced activity envelope for every sheet. Sample times are absolute source seconds. Levels are 0..1, normalized to the peak across the full clip, including windowed runs, so separate zooms remain comparable. Exit 0 success · 1 failure (message on stderr). Temp frames are always cleaned up. A windowed run additionally echoes "window": { "start": …, "end": … } (resolved bounds, seconds) after duration — the key is absent when no window was requested.

MCP server

squish mcp        # stdio server

One tool, squish_video{ video_path, density?, start?, end?, out_dir? } → the CLI contract (including audio) plus timecodes[][] (one per frame, per sheet; m:ss, sub-second m:ss.d when a window is short), stamped "contract": "squish-mcp-v0". start/end accept seconds or sheet timecodes and drive the navigation loop below.

Works with Claude Code, Claude Desktop, Cursor, Hermes, and any stdio MCP client:

{
  "mcpServers": {
    "squish": { "command": "npx", "args": ["-y", "@getsquish/squish", "mcp"] }
  }
}

Remote MCP — official AI apps, zero install

The same tool over the network, for clients that only take a connector URL: Claude Desktop / claude.ai → Settings → Connectors → Add custom connector → https://api.getsquish.app/mcp. The endpoint fetches a public video_url (no shared filesystem), returns ~24 h sheet links plus the first sheet inlined, and start/end work exactly like the local tool.

Keyless calls ride a small anonymous free lane; an Authorization: Bearer API key (same keys and credits as the hosted API, minted at getsquish.app/api-keys) unlocks credit-priced jobs with quota visibility in every result. Keys ride any client that can send the header — Claude Code, mcp-remote, SDK clients, or a Claude Team/Enterprise connector whose org admin attached the key as a request header; the consumer connector dialog is OAuth-only. Full reference: remote MCP docs.

The navigation loop

  1. Overview — call squish_video (MCP) or squish clip.mov --json (CLI) and read the sheet(s) with vision. Cells run in time order, left→right, top→bottom.

  2. Navigate — spot the regions that matter; every cell carries an absolute timecode. Treat an audio peak as a candidate interval, not an interpretation of what made the sound.

  3. Zoom — call again with start/end set to the timecodes you spotted, only where uncertainty remains: denser sheets of a narrower window, addresses still absolute.

  4. Repeat until the answer is observable — never re-read the whole clip at high density when one range matters.

  5. Cite absolute timestamps ("at 0:07 the press comes down").

Privacy

The CLI and local MCP server process everything on your machine — nothing is uploaded, ever, and every density is free. Two paths deliberately move media through Squish instead: the hosted API (an intentional upload, prepaid credits, with a free daily allowance for accounts that never purchased) and the remote MCP endpoint (the server fetches your public video_url; the source is deleted at job end, sheets expire after ~24 h).

Audio activity is available in the local CLI/MCP package. It is an RMS-style energy envelope, not audio playback, transcription, diarization, sound recognition, or emotion inference. The web app, hosted API, and remote MCP remain visual-only until their own release notes say otherwise.


This repository

This is the engine — the CLI + MCP mouths of Squish, published to npm as @getsquish/squish. It is a curated, mirror-first export of a private monorepo (which stays the source of truth); history here starts at the first public release. See CONTRIBUTING.md for how changes flow.

Not in this repo, on purpose:

  • the getsquish.app web app (PWA) — same core planners, browser hands;

  • the hosted API (api.getsquish.app) and its remote MCP endpoint (/mcp, the official-app connector) — the paid rail: intentional upload / server-fetched URLs, prepaid credits, a free daily allowance for never-paid accounts and a small anonymous free lane on the connector;

  • brand assets — the Squish name, logo, mascot, and OG images are reserved.

src/            CLI (main/args) · engine (probe → plan → extract → compose → write) · MCP server · sheet renderer
src/core/       pure planners shared with the web app: density · sampling · grid layout · timecode format
tests/          node:test suite + a real-MCP-client e2e
skills/         agent skills — `npx skills add getsquish/squish` installs video-navigation

License

Apache-2.0 (with NOTICE). The Squish name, logo, mascot, and getsquish.app brand assets are not licensed by this repository.

Available Tools

1 tool
squish_videoSquish a video into a timestamped visual + audio activity mapA
Idempotent
Inspect

Turn a local video file into timestamped contact-sheet JPEG(s) that a vision model can read: frames sampled evenly across the clip, each cell stamped with its timecode, plus an aligned audio-activity band. The band is globally normalized to the full clip and shows energy only — it does not transcribe, classify, or identify sounds. Use peaks to propose where to zoom; use the frames to determine what happened. Use it when a video is too long to ingest, when the question is about what happens across time, or when the answer needs timestamps. One call replaces a whole ffmpeg → extract → montage pipeline — prefer it even if you have a shell. Read the returned sheet file(s) with vision and cite the timecodes. Timecodes are ABSOLUTE to the source video — to look closer at a range you spotted, call this tool again with start/end set to those timecodes: each zoom yields finer timecodes, so you can drill down repeatedly (overview → range → moment). The JSON result includes audio.samples[] with absolute time and normalized level values. Runs entirely on-device; requires ffmpeg on PATH.

ParametersJSON Schema
NameRequiredDescriptionDefault
endNoZoom-window end — same formats as start. Omit to run to the end of the clip; values past the end are clamped.
startNoZoom-window start — seconds (67.5) or a timecode as stamped on a sheet ("1:07", "1:07.3"). Absolute in the source video. Omit to start at 0.
densityNoGrid density. 3x3 recovers what happened; denser grids (4x4-6x6) recover how it was done. Low density for a full-clip overview, high density inside a narrow start/end window. Default 3x3.
out_dirNoDirectory for the output sheet(s). Default: beside the input file.
video_pathYesAbsolute path to a local video file (anything ffmpeg decodes)

TDQS

A4.9/5.0
Behavior5/5

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

The description discloses important behavioral traits beyond annotations: timecodes are ABSOLUTE, the audio band is globally normalized and energy-only, the on-device execution, the ffmpeg dependency, and the drill-down zooming behavior. The idempotentHint is consistent with the repeated-call workflow described.

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 long but information-dense, with every sentence adding a distinct, useful fact. It front-loads the core deliverable and then progressively covers usage, limitations, parameter strategy, and prerequisites, without repetition.

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

Completeness5/5

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

For a tool with no output schema, the description compensates by specifying the return shape ('audio.samples[]' with absolute time and normalized level), the output file nature, the visualization workflow, and the environmental requirement. An agent has enough to invoke it correctly and use its results.

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

Parameters4/5

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

Schema coverage is already 100%, so the baseline is 3, but the description adds strategic meaning beyond the schema: 3x3 recovers what happened while 4x4–6x6 recovers how it was done, and zoom calls with start/end produce finer timecodes for repeated drill-down. This helps an agent choose parameter values, not just recognize types.

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?

The description names a specific transformation (video → timestamped contact-sheet JPEGs with an audio activity band) and identifies the vision-model use case. Though there are no sibling tools, it clearly positions itself against the manual ffmpeg pipeline, so there is no ambiguity about what it replaces.

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

Usage Guidelines5/5

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

The description explicitly states when to use it: for videos too long to ingest, for time-anchored questions, and whenever timestamps are needed. It also tells the agent when not to rely on it for audio semantics ('does not transcribe, classify, or identify sounds') and directs repeated zooming from overview → range → moment.

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. Dates show when Glama detected each change.

  1. 1 tool updatev0.3.1
    • First observedsquish_video

TDQS

A4.8/5.0
Disambiguation5/5

There is only one tool, so there is no overlap or ambiguity to confuse an agent. `squish_video` is clearly the single, distinct operation the server provides.

Naming Consistency5/5

The single tool name `squish_video` follows a clear verb_noun pattern and matches the server name. There are no mixed conventions or conflicting styles.

Tool Count4/5

One tool is on the low side compared to typical MCP servers, but the tool itself is substantial and self-contained: it supports overview, zooming, timestamps, and audio activity in one call. The count is slightly thin but reasonable for this focused purpose.

Completeness4/5

The tool covers the main video-to-contact-sheet workflow completely, including repeated drill-down into time ranges. The only real boundary is that it does not transcribe or classify audio content, so agents needing speech-level detail would need an external tool.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/getsquish/squish'

If you have feedback or need assistance with the MCP directory API, please join our Discord server