{
  "markdown": "# @ffmpeg-micro/mcp-server\n\n[![npm version](https://img.shields.io/npm/v/@ffmpeg-micro/mcp-server.svg)](https://www.npmjs.com/package/@ffmpeg-micro/mcp-server)\n[![CI](https://github.com/javidjamae/ffmpeg-micro-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/javidjamae/ffmpeg-micro-mcp/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n\nA [Model Context Protocol](https://modelcontextprotocol.io) 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](https://ffmpeg-micro.com) REST API.\n\n## What it does\n\nExposes tools that map onto FFmpeg Micro's public API:\n\n| Tool | What it does |\n| --- | --- |\n| `transcode_video` | Create a transcode job from one or more input videos (`gs://` or `https://`). Supports quality/resolution presets and raw FFmpeg options. |\n| `get_transcode` | Fetch the current state of a single job. |\n| `list_transcodes` | List jobs with optional `status`, `page`, `limit`, `since`, `until` filters. |\n| `cancel_transcode` | Cancel a pending or processing job. |\n| `get_download_url` | Generate a 10-minute signed HTTPS URL for a completed job's output file. |\n| `transcode_and_wait` | Convenience: create a job, poll until it finishes, return the signed download URL in one call. |\n| `request_upload_url` | Step 1 of the direct-upload flow. Returns a presigned HTTPS URL that the host PUTs the file bytes to. |\n| `confirm_upload` | Step 2 of the direct-upload flow. Returns the final `gs://` URL plus probe metadata, ready to use as a transcode/transcribe input. |\n| `run_blueprint` | Start a blueprint run — a pre-built video workflow (captioning, resizing, watermarking, ads, and more). |\n| `get_blueprint_run` | Fetch a blueprint run's status, step, and output URLs (multi-output blueprints return labeled `outputs`). |\n| `run_blueprint_and_wait` | Convenience: start a blueprint run and poll until it completes, fails, or pauses for transcript review. |\n| `continue_blueprint_run` | Resume a `caption-video` run paused in `awaiting_review` by submitting the approved SRT transcript. |\n\n### Blueprints\n\nBlueprints are pre-built workflows behind `POST /v1/blueprints/{slug}/runs`. The tool descriptions document each blueprint's input fields. Notes:\n\n- Most blueprints run on the FFmpeg lane and meter plan compute minutes (no tokens). Generative blueprints (`product-ad`) charge tokens; a `402 insufficient_tokens` response means the account needs a token pack ([dashboard](https://www.ffmpeg-micro.com/dashboard/blueprints)).\n- `caption-video` pauses in `awaiting_review` with the transcript (`srt_text`) so the agent can review/edit before rendering; resume with `continue_blueprint_run`.\n- Multi-output blueprints (`listing-kit`, `hook-variants`) return an `outputs` array of `{label, url}` — prefer it over `output_url` when present.\n- Output URLs are signed with a 10-minute TTL; re-fetch the run for fresh links.\n\n### Uploading a local file\n\nThe `request_upload_url` + `confirm_upload` pair lets an MCP host upload a local file to the FFmpeg Micro storage bucket without dealing with raw API keys or `gs://` URLs:\n\n1. Host calls `request_upload_url` with `{filename, contentType, fileSize}` → receives a short-lived presigned HTTPS URL.\n2. Host PUTs the file bytes to that URL with the same `Content-Type`.\n3. Host calls `confirm_upload` with `{filename: <storage filename from step 1>, fileSize}` → receives the final `gs://...` `fileUrl`.\n4. Host passes that `fileUrl` to `transcribe_audio` / `transcode_video` / `transcode_and_wait`.\n\n## Quick start\n\nAdd this to your project's `.mcp.json` (or your MCP client's config):\n\n```json\n{\n  \"mcpServers\": {\n    \"ffmpeg-micro\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.ffmpeg-micro.com\"\n    }\n  }\n}\n```\n\nThat's it. The first time your AI tool connects, it will open a browser window for you to sign in with your [FFmpeg Micro](https://ffmpeg-micro.com) account via OAuth. After you approve, the token is cached and you won't be asked again.\n\nNo API keys to copy, no environment variables to set.\n\n## Authentication\n\n### OAuth (recommended)\n\nThe MCP server supports OAuth 2.1 with PKCE and dynamic client registration. Your MCP client handles the entire flow automatically:\n\n1. Client discovers OAuth endpoints via `/.well-known/oauth-authorization-server`\n2. Client registers itself dynamically\n3. Browser opens for you to sign in and approve access\n4. Token is exchanged and cached — subsequent connections are instant\n\nThis is the default when you use the config above with no `headers` or `env` block.\n\n### API key (alternative)\n\nIf you prefer to use an API key directly (e.g., for automation or CI), you can pass it as a Bearer token:\n\n```json\n{\n  \"mcpServers\": {\n    \"ffmpeg-micro\": {\n      \"type\": \"http\",\n      \"url\": \"https://mcp.ffmpeg-micro.com\",\n      \"headers\": {\n        \"Authorization\": \"Bearer your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\nGet your API key from the [dashboard](https://www.ffmpeg-micro.com/dashboard/api-keys).\n\n### stdio (local install)\n\nRuns the server as a local process using `npx`. Requires Node.js 22.14 or later.\n\n```json\n{\n  \"mcpServers\": {\n    \"ffmpeg-micro\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@ffmpeg-micro/mcp-server\"],\n      \"env\": {\n        \"FFMPEG_MICRO_API_KEY\": \"your_api_key_here\"\n      }\n    }\n  }\n}\n```\n\n`npx -y` fetches the latest version each time. Any MCP client that supports stdio servers works with this config.\n\n## Compatible tools\n\nThe HTTP config (OAuth) works with any MCP client that supports streamable HTTP transport:\n\n- **Claude Code** (CLI)\n- **Claude Desktop**\n- **Cursor**\n- **Windsurf**\n- **VS Code** (GitHub Copilot MCP)\n\nThe stdio config works with any MCP client that supports stdio transport.\n\n## Example prompts\n\nOnce connected, you can ask things like:\n\n- \"Transcode this video to 720p MP4 and give me the download URL when it's done.\"\n- \"Crop this landscape video to a square.\"\n- \"Add a text overlay saying 'Episode 12' to my video.\"\n- \"List my failed jobs from this week.\"\n- \"Cancel job `b5f5a9c0-9e33-4e77-8a5b-6a0c2cd9c0b3`.\"\n\n## Development\n\n```bash\ngit clone https://github.com/javidjamae/ffmpeg-micro-mcp.git\ncd ffmpeg-micro-mcp\n./scripts/setup.sh\n```\n\n`setup.sh` installs dependencies, builds, and wires up the git hooks.\n\nPoint your MCP client at the local build to iterate:\n\n```json\n{\n  \"mcpServers\": {\n    \"ffmpeg-micro-dev\": {\n      \"command\": \"node\",\n      \"args\": [\"/absolute/path/to/ffmpeg-micro-mcp/dist/index.js\"],\n      \"env\": { \"FFMPEG_MICRO_API_KEY\": \"…\" }\n    }\n  }\n}\n```\n\nThe [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is the fastest way to iterate on tool schemas and responses:\n\n```bash\nnpx @modelcontextprotocol/inspector node dist/index.js\n```\n\nTo run the HTTP server locally against a local API gateway:\n\n```bash\nFFMPEG_MICRO_API_URL=http://localhost:8081 npm run serve\n```\n\n### Running integration tests locally\n\n```bash\nFFMPEG_MICRO_API_KEY=your_key npm run test:integration\n```\n\nIntegration tests hit the real FFmpeg Micro production API. They are read-only (no jobs are created).\n\n### Smoke-testing the upload tools end-to-end\n\nUnit tests use a mocked `fetch`, so they prove tool registration + Zod schemas + URL paths but not that the wire shapes match what the gateway actually returns. Two smoke scripts exercise the full `request_upload_url` → PUT → `confirm_upload` flow against a real MCP server using a real API key. Run them in order — stdio first (fastest signal), then a deployed HTTP server before/after merge:\n\n```bash\n# 1. stdio (local dist build) — spawns dist/index.js as a subprocess\nnpm run build\nFFMPEG_MICRO_API_KEY=your_key node scripts/smoke-upload-stdio.mjs <local-file>\n\n# 2. HTTP (any deployed server — local `npm run serve`, Vercel preview, or prod)\nFFMPEG_MICRO_API_KEY=your_key MCP_URL=https://mcp.ffmpeg-micro.com/ \\\n  node scripts/smoke-upload-http.mjs <local-file>\n```\n\nBoth scripts hit the production API by default and consume billable minutes (the stdio script chains into `transcribe_audio` for an end-to-end check). Pass a small file like `15-second.mp3` to keep the cost negligible.\n\nA third script smoke-tests the blueprint tools (`run_blueprint` + `get_blueprint_run` polled to completion on `resize-format`, then `run_blueprint_and_wait` on `hook-variants` to exercise multi-output). It uses FFmpeg-lane blueprints only, so it consumes plan compute minutes but no tokens:\n\n```bash\nnpm run build\nFFMPEG_MICRO_API_KEY=your_key node scripts/smoke-blueprints-stdio.mjs\n```\n\n#### Hitting protection-protected Vercel previews\n\nVercel preview deployments are gated by Deployment Protection by default. To exercise the HTTP smoke script against a preview URL, generate a Protection-Bypass-for-Automation token in the project's Vercel settings and pass it via `VERCEL_BYPASS`:\n\n```bash\nFFMPEG_MICRO_API_KEY=your_key \\\n  MCP_URL=https://your-preview.vercel.app/ \\\n  VERCEL_BYPASS=your_bypass_token \\\n  node scripts/smoke-upload-http.mjs <local-file>\n```\n\nThe script sends the token as the `x-vercel-protection-bypass` header on every request. **It does not** send `x-vercel-set-bypass-cookie: true` — that variant triggers a 307 cookie-setting redirect on POST that the MCP SDK's `StreamableHTTPClientTransport` does not follow, so the request fails. The header alone returns 200 directly without the redirect dance.\n\n## Release process\n\nReleases are published to [npm](https://www.npmjs.com/package/@ffmpeg-micro/mcp-server) via [trusted publishing](https://docs.npmjs.com/trusted-publishers/) and to the [MCP Registry](https://registry.modelcontextprotocol.io) 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 uses OIDC trusted publishing, so no npm token is stored.\n\nReleases are automated via [Changesets](https://github.com/changesets/changesets). Contributors don't manually bump versions, tag commits, or run publish commands — they attach a changeset to their PR and the release pipeline handles the rest.\n\n### Contributor flow (every PR)\n\nEvery PR that changes shipped code must include a changeset. A [CI check](.github/workflows/require-changeset.yml) enforces this.\n\n```bash\n# While working on your PR:\nnpx changeset\n```\n\nThe CLI prompts for bump type (major/minor/patch) and a short summary. It writes a markdown file under `.changeset/` — commit that file with your PR.\n\n**Escape hatches for non-release PRs** (docs, CI, internal refactor, test changes with no behavioral impact):\n\n- Add the `no-changeset` label to the PR, **or**\n- `npx changeset --empty` to explicitly declare \"no release needed.\"\n\n### Maintainer flow (cutting a release)\n\nYou don't manually cut releases. The pipeline does it:\n\n1. **PRs land on `main`** with changeset files attached.\n2. **`.github/workflows/release.yml`** runs on every push to `main`. When pending changesets exist, it opens (or updates) a `chore(release): version packages` PR authored by the action. That PR:\n   - Runs `changeset version` to consume the pending changesets\n   - Bumps `package.json`\n   - Re-syncs `server.json` via `scripts/sync-server-version.mjs`\n   - Appends entries to `CHANGELOG.md`\n   - Commits the result to its own branch\n3. **Review and merge** the Version Packages PR when you're ready to ship. You can let several changesets accumulate before merging — the PR updates itself as more land on `main`.\n4. On merge, the release workflow runs again. This time there are no pending changesets, so `changesets/action` detects the version bump and:\n   - `npm publish` (OIDC trusted publishing, with provenance attestation)\n   - Creates the GitHub Release + git tag automatically\n5. The workflow's final steps install `mcp-publisher`, authenticate via the DNS private key, and publish to the MCP Registry as `com.ffmpeg-micro/mcp-server`.\n\n### Version-sync guard\n\n`.github/workflows/release.yml` still runs a version-parity check on every push to `main`. If `package.json.version`, `server.json.version`, and `server.json.packages[0].version` ever drift, the build fails loudly. Normally `scripts/sync-server-version.mjs` keeps them aligned, but the guard catches manual edits that missed the sync.\n\n### Verify\n\nAfter the Version Packages PR is merged and the workflow is green:\n\n```bash\nnpm view @ffmpeg-micro/mcp-server version\ncurl -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}'\n```\n\n### Example: contributor walkthrough\n\nSuppose you're adding a new `delete_transcode` tool. Your PR flow:\n\n```bash\ngit switch -c feat/delete-transcode\n# ... make the code + test changes ...\n\nnpx changeset\n# ? Which packages would you like to include? › @ffmpeg-micro/mcp-server\n# ? Which type of change is this for @ffmpeg-micro/mcp-server? › minor\n# ? Please enter a summary for this change › Add delete_transcode tool\n\ngit add .changeset/*.md src/ tests/\ngit commit -m \"feat: add delete_transcode tool\"\ngit push -u origin feat/delete-transcode\ngh pr create\n```\n\nCI runs three checks:\n- `test` — unit tests\n- `check` (Require changeset) — confirms `.changeset/*.md` is present\n- `Vercel` — preview deploy\n\nAfter merge, the Version Packages PR either opens or updates itself to include your entry. Merge that when you're ready to ship.\n\n### Rules\n\n- **Never edit version fields in `server.json` or `package.json` by hand.** Changesets owns both — `scripts/sync-server-version.mjs` mirrors `package.json` into `server.json`. The CI drift guard fails the release if they diverge.\n- **Never `git tag` a release manually.** `changesets/action` creates the tag + GitHub Release as part of publish. Manual tags aren't picked up by the new workflow.\n- **Never bypass the Require-changeset check** by committing changes to `.changeset/config.json` or `.changeset/README.md` (those don't count). Use `npx changeset`, the `no-changeset` label, or `npx changeset --empty`.\n\n### Release-related files\n\n- `package.json` — source of truth for version. Also holds `mcpName` (required by the MCP Registry for npm package validation). Bumped by `changeset version`.\n- `server.json` — MCP Registry metadata. Version fields are auto-synced from `package.json`.\n- `.changeset/config.json` — Changesets configuration (public access, GitHub-aware changelog formatter).\n- `.changeset/*.md` — pending release notes waiting to be consumed by the next `changeset version` run.\n- `scripts/sync-server-version.mjs` — mirrors `package.json` version into `server.json`.\n- `.github/workflows/release.yml` — the publish pipeline (changesets/action + MCP Registry step).\n- `.github/workflows/require-changeset.yml` — enforces changeset presence on PRs.\n\n### Troubleshooting\n\n- **`Require changeset` check fails on my PR** — run `npx changeset` and commit the generated file. For docs-only / CI-only PRs, add the `no-changeset` label or `npx changeset --empty`.\n- **CI fails at the version-sync guard step** — `server.json` was edited manually. Locally: `node scripts/sync-server-version.mjs`, commit, push. The guard compares `package.json.version`, `server.json.version`, and `server.json.packages[0].version`.\n- **`changesets/action` didn't open a Version Packages PR after my feature PR merged** — check that your PR's `.changeset/*.md` file actually had content (non-empty front matter with a bump type and summary). Empty changesets signal \"no release needed\" and are intentionally ignored.\n- **`mcp-publisher publish` fails with \"package not found\"** — npm hasn't finished propagating the new version yet. The release workflow's `Determine if MCP Registry publish is needed` step retries `npm view` for up to ~50 seconds and backs off if the version still isn't live, deferring the registry publish to the next push to main (which self-heals the drift). If you see this in a manual run, just wait 30s and re-publish.\n- **MCP Registry stuck a version behind npm** — the `Determine if MCP Registry publish is needed` step skipped (or returned `needed=false`). Push any commit to main to trigger a re-run; the gate compares `package.json` ↔ npm ↔ registry and catches up automatically. If it keeps skipping, check the step's log output for which version each source reported.\n- **`mcp-publisher publish` fails validation with \"mcpName mismatch\"** — `package.json` `mcpName` must equal `server.json` `name` (both should be `com.ffmpeg-micro/mcp-server`).\n- **`mcp-publisher login dns` fails with \"public key mismatch\"** — the `MCP_PRIVATE_KEY` secret no longer matches the TXT record on `ffmpeg-micro.com`. Regenerate the keypair locally, update both the TXT record and the GitHub secret.\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n",
  "bytes": 16939,
  "sha": "0c357b638465ed9a3b8bb61d8d657037a25fbd5eb71bd47d31280e54f8db46ff",
  "repo_slug": "javidjamae/ffmpeg-micro-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_com_ffmpeg_micro_mcp_server_f51963bb/readme"
}