@ffmpeg-micro/mcp-server
A Model Context Protocol server that lets AI agents — Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, and any other MCP-compatible client — create, monitor, and download video transcodes through the FFmpeg Micro REST API.
What it does
Exposes six tools that map onto FFmpeg Micro's public API:
| Tool | What it does |
|---|---|
transcode_video | Create a transcode job from one or more input videos (gs:// or https://). Supports quality/resolution presets and raw FFmpeg options. |
get_transcode | Fetch the current state of a single job. |
list_transcodes | List jobs with optional status, page, limit, since, until filters. |
cancel_transcode | Cancel a queued or processing job. |
get_download_url | Generate a 10-minute signed HTTPS URL for a completed job's output file. |
transcode_and_wait | Convenience: create a job, poll until it finishes, return the signed download URL in one call. |
Quick start
Add this to your project's .mcp.json (or your MCP client's config):
{
"mcpServers": {
"ffmpeg-micro": {
"type": "http",
"url": "https://mcp.ffmpeg-micro.com"
}
}
}
That's it. The first time your AI tool connects, it will open a browser window for you to sign in with your FFmpeg Micro account via OAuth. After you approve, the token is cached and you won't be asked again.
No API keys to copy, no environment variables to set.
Authentication
OAuth (recommended)
The MCP server supports OAuth 2.1 with PKCE and dynamic client registration. Your MCP client handles the entire flow automatically:
- Client discovers OAuth endpoints via
/.well-known/oauth-authorization-server - Client registers itself dynamically
- Browser opens for you to sign in and approve access
- Token is exchanged and cached — subsequent connections are instant
This is the default when you use the config above with no headers or env block.
API key (alternative)
If you prefer to use an API key directly (e.g., for automation or CI), you can pass it as a Bearer token:
{
"mcpServers": {
"ffmpeg-micro": {
"type": "http",
"url": "https://mcp.ffmpeg-micro.com",
"headers": {
"Authorization": "Bearer your_api_key_here"
}
}
}
}
Get your API key from the dashboard.
stdio (local install)
Runs the server as a local process using npx. Requires Node.js 22.14 or later.
{
"mcpServers": {
"ffmpeg-micro": {
"command": "npx",
"args": ["-y", "@ffmpeg-micro/mcp-server"],
"env": {
"FFMPEG_MICRO_API_KEY": "your_api_key_here"
}
}
}
}
npx -y fetches the latest version each time. Any MCP client that supports stdio servers works with this config.
Compatible tools
The HTTP config (OAuth) works with any MCP client that supports streamable HTTP transport:
- Claude Code (CLI)
- Claude Desktop
- Cursor
- Windsurf
- VS Code (GitHub Copilot MCP)
The stdio config works with any MCP client that supports stdio transport.
Example prompts
Once connected, you can ask things like:
- "Transcode this video to 720p MP4 and give me the download URL when it's done."
- "Crop this landscape video to a square."
- "Add a text overlay saying 'Episode 12' to my video."
- "List my failed jobs from this week."
- "Cancel job
b5f5a9c0-9e33-4e77-8a5b-6a0c2cd9c0b3."
Development
git clone https://github.com/javidjamae/ffmpeg-micro-mcp.git
cd ffmpeg-micro-mcp
./scripts/setup.sh
setup.sh installs dependencies, builds, and wires up the git hooks.
Point your MCP client at the local build to iterate:
{
"mcpServers": {
"ffmpeg-micro-dev": {
"command": "node",
"args": ["/absolute/path/to/ffmpeg-micro-mcp/dist/index.js"],
"env": { "FFMPEG_MICRO_API_KEY": "…" }
}
}
}
The MCP Inspector is the fastest way to iterate on tool schemas and responses:
npx @modelcontextprotocol/inspector node dist/index.js
To run the HTTP server locally against a local API gateway:
FFMPEG_MICRO_API_URL=http://localhost:8081 npm run serve
Running integration tests locally
FFMPEG_MICRO_API_KEY=your_key npm run test:integration
Integration tests hit the real FFmpeg Micro production API. They are read-only (no jobs are created).
Release process
Releases are published to npm via trusted publishing and to the MCP Registry as com.ffmpeg-micro/mcp-server, authenticated via an Ed25519 DNS TXT record on ffmpeg-micro.com. The corresponding private key lives in the MCP_PRIVATE_KEY GitHub Actions secret. The npm side still uses OIDC trusted publishing, so no npm token is stored.
Cutting a release
Direct commits to main are blocked by .githooks/pre-commit, so the release goes through a PR. From a clean main:
git checkout main && git pull
git status # must be clean
git switch -c release/vX.Y.Z
npm version patch --no-git-tag-version # or minor / major / explicit X.Y.Z
git add package.json package-lock.json server.json
git commit -m "chore(release): X.Y.Z"
git push -u origin release/vX.Y.Z
gh pr create --title "chore(release): X.Y.Z" --body "Release X.Y.Z"
npm version --no-git-tag-version bumps package.json and runs scripts/sync-server-version.mjs, which mirrors the new version into server.json (both version and packages[0].version). No commit or tag is created yet — those come from the PR merge and the explicit git tag below.
Review the PR, then merge it (any merge strategy is fine — the tag is created after merge, so there's no orphan-tag risk). After merge:
git checkout main && git pull
git tag vX.Y.Z
git push origin vX.Y.Z # only the tag; main is not pushed
The tag push triggers the release workflow.
What CI does
The push triggers .github/workflows/release.yml, which on the vX.Y.Z tag:
- Runs
npm run typecheck,npm run build,npm test. - Runs the version-sync guard — fails the build if
package.json.version,server.json.version, orserver.json.packages[0].versionhave drifted. npm publishwith provenance attestation (trusted publishing via OIDC — no npm token).- Installs
mcp-publisher, authenticates withmcp-publisher login dns --domain ffmpeg-micro.com --private-key $MCP_PRIVATE_KEY, then runsmcp-publisher publishto register the new version in the MCP Registry ascom.ffmpeg-micro/mcp-server.
Verify
After the workflow is green:
npm view @ffmpeg-micro/mcp-server version
curl -s "https://registry.modelcontextprotocol.io/v0/servers?search=com.ffmpeg-micro/mcp-server" | jq '.servers[] | {v: .server.version, isLatest: ._meta."io.modelcontextprotocol.registry/official".isLatest}'
Rules
- Never edit version fields in
server.jsonby hand — the sync script owns them. The CI drift guard will fail the release if they diverge frompackage.json. - Never hand-edit
package.jsonversion and commit — always go throughnpm versionsoserver.jsonstays in sync and the tag is created atomically. - Never tag without
npm version— the workflow assumesvX.Y.Zmatchespackage.json.
Release-related files
package.json— source of truth for version. Also holdsmcpName(required by the MCP Registry for npm package validation).server.json— MCP Registry metadata. Version fields are auto-synced frompackage.json.scripts/sync-server-version.mjs— runs during thenpm versionlifecycle..github/workflows/release.yml— the publish pipeline.
Troubleshooting
npm versionfails with "working tree not clean" — commit or stash local changes first.- CI fails at the version-sync guard step —
server.jsonwas edited manually. Locally:node scripts/sync-server-version.mjs, commit, delete the bad tag (git tag -d vX.Y.Z && git push --delete origin vX.Y.Z), re-tag, re-push. mcp-publisher publishfails with "package not found" — npm hasn't finished propagating the new version yet. Re-run just the failed job after ~30 seconds.mcp-publisher publishfails validation with "mcpName mismatch" —package.jsonmcpNamemust equalserver.jsonname(both should becom.ffmpeg-micro/mcp-server).mcp-publisher login dnsfails with "public key mismatch" — theMCP_PRIVATE_KEYsecret no longer matches the TXT record onffmpeg-micro.com. Regenerate the keypair locally, update both the TXT record and the GitHub secret.
License
MIT — see LICENSE.