Edit Video from Claude Code
Add Valmera to Claude Code as a remote HTTP MCP server and the session that writes your code can also cut a screen recording: upload the file from disk, remove the dead air, caption it, reframe it to 9:16, render, and drop the review MP4 into ./dist. The source-quality final is created in Studio. One command and one browser sign-in.
This page is the CLI. For the Claude app's connector UI — the same server, no commands — see connecting Claude to video editing.
claude mcp add --transport http valmera \
https://entrepreneur-bot-backend.onrender.com/mcpThen /mcp inside Claude Code to sign in. Streamable HTTP · OAuth 2.1 with dynamic client registration and PKCE · 100+ live tools.
Why the Terminal Is Where This Belongs
Most of the video a developer produces is made a few feet from the code. Screen recordings of a bug. A demo of the feature that just merged. The forty-second clip that goes in the release notes. A walkthrough for the docs site. That footage is already on the machine Claude Code is running on, and the finished file has to end up in a repo, a release asset or a CDN bucket — which is also where Claude Code already is.
The mechanical reason the pairing works is narrower and more interesting. MCP arguments are JSON, so video bytes never cross the protocol. Valmera's upload_start therefore hands back a presigned URL and the literal command to push the file to it. A chat app cannot run that command — you run it. A terminal agent runs it itself. That single difference is what turns "upload this and cut it" from a two-tool conversation with a manual step in the middle into one uninterrupted sentence.
And a scripted edit is closer to a build step than a creative session. "Cut the silences, caption it, 9:16, save the review preview to dist" is a request you will make again next release, on next month's recording, with the same wording. That belongs in a CLAUDE.md or a slash command next to your other repeatable jobs. The request repeats exactly; the edit is still an agent's judgement each time, which is worth remembering before you wire it into a pipeline nobody watches.
How to Connect Valmera to Claude Code
- 1Create a Valmera accountSign up free at valmera.io with email or Google. Account creation and uploads are free, but agent editing requires a subscription. If you signed up with Google, set a password with "Forgot password" first — the OAuth consent screen needs one. MCP access is included automatically with an active Valmera Pro or Frontier subscription. If an earlier attempt was refused, reconnect using your verified subscriber email.
- 2Add the serverRun: claude mcp add --transport http valmera https://entrepreneur-bot-backend.onrender.com/mcp. Add --scope user to make it available in every repo, or --scope project to write a committed .mcp.json for your team. With no flag it is local scope: this repo, you only.
- 3AuthenticateStart Claude Code and run /mcp, then follow the browser sign-in and press Allow. Claude Code discovers the authorization server from the endpoint and registers itself — there is nothing to paste. From v2.1.186 you can run claude mcp login valmera from the shell instead, and from v2.1.191 it detects an environment with no browser — an SSH session, a Linux box with no display server — and prints the authorization URL to open elsewhere; --no-browser forces that prompt even when a browser is present. Either way the paste step needs an interactive terminal, so connect with ssh -t.
- 4Confirm it connectedRun claude mcp list. A working server reads ✔ Connected; ! Needs authentication means step 3 has not completed; ✘ Failed to connect is a transport or credential problem. Inside a session, /mcp shows the tool count next to the server.
One command and one sign-in. The first upload then needs a one-time analysis pass — transcript, silences, shot boundaries and frame tiles — which reports progress and is reused by every edit afterwards.
Local, Project or User Scope
claude mcp add writes the server somewhere, and the flag decides where. The default is local, which surprises people who expected the server to follow them between repos.
| Local | Project | User | |
|---|---|---|---|
| Flag | --scope local (default) | --scope project | --scope user |
| Loads in | This repo only | This repo only | Every repo on your machine |
| Stored in | ~/.claude.json | .mcp.json in the repo root | ~/.claude.json |
| Committed to git | ✗ | ✓ | ✗ |
| Teammates get it | ✗ | ✓ | ✗ |
| Use it when | Trying it out | The repo ships videos | It is your editor, everywhere |
When the same server name is defined at more than one scope, Claude Code connects once and uses the entry from the highest-precedence source — local, then project, then user. The whole entry wins; fields are not merged across scopes. So a local valmera with a stale token quietly shadows the correct project-scoped one, and claude mcp get valmera is how you find out which definition is live.
Pick user scope if Valmera is simply your editor. Pick project scope if the repo itself ships video — a docs site, a marketing site, a product with release demos — because then the tooling belongs to the repo rather than to whoever happened to set it up.
A Committed .mcp.json for a Team
Project scope writes a standard file at the repo root. Commit it:
claude mcp add --transport http valmera --scope project \
https://entrepreneur-bot-backend.onrender.com/mcp.mcp.json
{
"mcpServers": {
"valmera": {
"type": "http",
"url": "https://entrepreneur-bot-backend.onrender.com/mcp"
}
}
}Three things about this file are worth stating plainly.
It carries no credential. The endpoint is shared; the identity is not. Each teammate runs /mcp and signs in as themselves, against their own Valmera account, their own projects and their own credits. Nobody inherits anyone else's footage by cloning a repo.
Every teammate is asked before it is used. Claude Code prompts for approval before running a server defined in .mcp.json, and a pending one shows in claude mcp list as ⏸ Pending approval until someone runs claude interactively and answers. claude mcp reset-project-choices clears that answer. A cloned repo cannot approve its own servers, which is the point.
The type field is not optional. An entry with a url and no type is read as a stdio server and skipped, with MCP server "valmera" has a "url" but no "type". If you hand-edit the file, keep "type": "http" (streamable-http is accepted as an alias, so configs copied from other servers' docs work unchanged).
The Bearer Token Path
OAuth is the better path when there is a person and a browser. There often is not — a CI runner, a container, a client that never implemented the OAuth half of the spec. For those, the server also accepts a static token on the standard header:
claude mcp add --transport http valmera \
https://entrepreneur-bot-backend.onrender.com/mcp \
--header "Authorization: Bearer vlm_mcp_..."Tokens are issued once and stored only as a sha256 hash, so a lost one is replaced rather than recovered. Both credential types resolve to the same thing inside the server — who you are, and which project is open — so a token session and an OAuth session get an identical tool registry and identical refusals.
One asymmetry to know before you choose this path: if headers.Authorization is set and the server rejects it, Claude Code reports the connection as failed rather than falling back to OAuth. So a revoked token looks like a transport problem. Remove the header if you want the browser flow back.
Never commit the token. Claude Code expands environment variables inside headers and url, so a shared .mcp.json can reference a secret each developer supplies for themselves:
.mcp.json
{
"mcpServers": {
"valmera": {
"type": "http",
"url": "https://entrepreneur-bot-backend.onrender.com/mcp",
"headers": {
"Authorization": "Bearer ${VALMERA_MCP_TOKEN}"
}
}
}
}An unset variable does not fail the load — Claude Code warns in claude mcp list and leaves the literal ${VALMERA_MCP_TOKEN} in place, which then fails authentication with unknown or revoked token. Use ${VAR:-default} if you want a fallback.
A Session, End to End
A 90-second screen recording of a feature that just shipped, at ~/screencaps/v2-release.mov. The goal is a captioned vertical cut in ./dist. Here is the whole thing, with the tool calls the model makes shown between the two sides of the conversation.
$ claude mcp add --transport http valmera \
https://entrepreneur-bot-backend.onrender.com/mcp
Added HTTP MCP server valmera to local config
$ claude
> /mcp
valmera ! Needs authentication → Authenticate
… browser opens, sign in, Allow …
valmera ✔ connected · 100+ live tools> Make a Valmera project from ~/screencaps/v2-release.mov, cut the
silences and the ums, caption it in the podcast preset, reframe it
to 9:16, then save the review preview into ./dist.
⏺ create_project(title: "v2-release")
Project 4127 created and active.
⏺ Bash(stat -f%z ~/screencaps/v2-release.mov)
12648430
⏺ upload_start(filename: "v2-release.mov", size_bytes: 12648430)
Upload the file with this exact command, then call upload_finish(…)
curl -sS -f -X PUT -H 'Content-Type: video/quicktime' \
--upload-file '<LOCAL PATH>' 'https://…'
⏺ Bash(curl -sS -f -X PUT -H 'Content-Type: video/quicktime' …)
(12.6 MB uploaded)
⏺ upload_finish(storage_key: "…", filename: "v2-release.mov")
Uploaded (asset 9312). Analysis started as job 8811 — the
transcript, shots and silences do not exist until it finishes.
⏺ index_status()
running — 58% (job 8811).
⏺ index_status()
done — the video is analyzed and ready to edit.Those two Bash lines are the whole argument for doing this from a CLI. In the Claude app they are your job, in another window.
⏺ cut_silences()
17 silences removed. Program 91.4s → 68.2s.
⏺ remove_filler_words()
9 fillers removed (um ×6, uh ×2, you know ×1).
Program 68.2s → 66.9s.
⏺ add_captions(mode: "from_transcript", style: {preset: "podcast"})
⏺ auto_reframe(ratio: "9:16")
⏺ render_preview()
STILL RUNNING — render_preview is job 8814 (running, 12%). Nothing
has failed; call wait_for_job(job_id=8814) to pick the result up.
⏺ wait_for_job(job_id: 8814)
STILL RUNNING — job 8814 (mcp_tool) (running, 71%).
⏺ wait_for_job(job_id: 8814)
Preview of EDL v6 rendered.
⏺ look_at(output_times: [2.4, 19.8, 44.1, 63.0])
… four frames, read by the model …That look_at call is the agent checking its own work. It gets real frames out of the preview it just rendered — captions in place, the crop where it landed — rather than reporting what it intended to do. On this footage it is the step that catches a caption sitting over the toolbar you were demonstrating.
⏺ watch_video(project_id: 42)
Review handoff opened for the complete preview of EDL v6.
⏺ download_url(project_id: 42, kind: "preview")
preview of EDL v6 — https://… (link valid a few hours)
⏺ Bash(mkdir -p dist && curl -sS -o dist/v2-release-9x16.mp4 'https://…')
Review preview saved to dist/v2-release-9x16.mp4 — 66.9s, 9:16.
The edit is ready; create the source-quality final in Valmera Studio.Two details in that last line are load-bearing. The preview renders from a fast proxy because it has to be quick. When you approve the edit and create the final in Studio, that render goes back to the file you uploaded and runs at source quality. And nothing in the sequence touched your .mov — every tool wrote to an edit decision list, which is why any of it can be reversed by asking.
How Renders Behave: wait_for_job
The one part of this that reads oddly the first time. A render is minutes of ffmpeg; an MCP tool call is a request. Something has to give, and what gives is the pretence that the call finished.
Every call returns inside about 25 seconds
That bound is deliberate. Claude Code puts a 60-second timer on the first response byte from an HTTP MCP server, so a tool that blocked for the length of a render would be killed by the client rather than finished by the server. Valmera waits ~25 seconds for the job, then answers with whatever is true at that moment.
STILL RUNNING is a receipt, not an error
A preview render, burned-text erasure or a generated clip can come back as: STILL RUNNING — render_preview is job 8814 (running, 12%). Nothing has failed; call wait_for_job(job_id=8814) to pick the result up. The job is queued server-side and keeps going whether or not anything is waiting on it.
wait_for_job is meant to be called in a loop
It waits a bounded time too, and returns either the finished result or the same line at a higher percentage. There is no penalty for calling it repeatedly, and no state is lost between calls — the job id is the whole handle.
Three jobs per account at once
A fourth is refused with "Too much is already running on this account — wait for it to finish and try again." This matters more from a CLI than from a chat window, because a scripted run can fire off preview renders faster than they finish.
A preview is a link; final export is Studio-only
download_url(kind="preview") mints a temporary URL for the rendered review file, so Claude Code can curl that preview into ./dist/. It cannot create a source-quality final export: that last action is deliberately Studio-only, and download_url(kind="final") can only retrieve an export that already exists.
Claude Code has its own safety net underneath this: a main-conversation MCP call still running after two minutes moves to a background task rather than blocking the session (v2.1.212+). Valmera's 25-second bound means you will rarely see it fire. If you want a longer ceiling for a specific reason, set "timeout" in milliseconds on the server's .mcp.json entry — it is a hard wall-clock limit per call, and progress notifications do not extend it.
One Project, One Editor
If the studio is open on the same project in a browser tab, an MCP tool call answers:
Valmera's own agent is mid-turn on this project — wait for it to
finish before editing, or the two of you will overwrite each other's
edit.It is refused in both directions: the studio will not start a turn while an MCP call is in flight either. Two editors on one timeline write conflicting EDL versions and each reads state the other is halfway through changing, so the loser is not a merge conflict — it is a silently wrong edit.
The fix is to let the turn finish, or work on a different project. The other direction is specific too: a studio request sent while an MCP call is in flight answers "Another editing session is working on this project right now — give it a moment", which is a different sentence from the one you get when the studio's own agent is busy. Neither side pretends the other does not exist.
Permissions for Unattended Runs
If you script this, Claude Code's permission rules are what stop each tool call stopping for a prompt. MCP rules use the server name as configured:
.claude/settings.json
{
"permissions": {
"allow": ["mcp__valmera__*"]
}
}mcp__valmera matches every tool from the server, mcp__valmera__* does the same with a wildcard, and mcp__valmera__cut_silences matches one. Allow globs must be anchored after a literal mcp__<server>__ prefix — an unanchored "*" or "mcp__*" is skipped with a warning and auto-approves nothing.
Worth being deliberate here rather than pasting the blanket rule. Reading the transcript costs nothing; rendering, generating a clip and erasing pixels are real compute and spend credits. An allow-all on a loop nobody is watching is a way to spend money without a decision. Allowing the read tools and prompting on render_preview is a reasonable middle.
What This Does Not Do
The connector is not a local toolchain and does not pretend to be one.
- Nothing renders on your machine. The only thing that runs locally is the upload and the download. There is no local ffmpeg step to cache, parallelise or pin a version of.
- Each version needs review. A 16:9 version and a 9:16 version need their own framing checks. Multiple child clip projects can be seeded with make_shorts, but each needs its own edit and preview. The user starts final exports in Studio; there is no automatic batch-export matrix over MCP.
- Captions are burned in. No SRT or VTT is produced or accepted, so there is no subtitle file to commit alongside the MP4, and no chapter metadata.
- It edits footage, it does not generate it. Short generated clips and stills can be spliced in, but there is no whole-video text-to-video. Upload something real.
- No NLE interchange. No project file for Premiere, Resolve or Final Cut, no multi-cam sync, no true crossfade, and one transition style per video rather than per cut.
- Uploads cap at 14 GB and 3 hours, in MP4, MOV, M4V, MKV or WebM. A five-hour raw capture is refused before the upload, not after it.
- No team seats, share links or direct publishing. The user creates the final export in Studio, then downloads and posts that file.
Claude Code calls Valmera's tools directly and writes its own replies. Tool results and recorded edit state provide evidence to check, but Valmera does not guarantee the external assistant's summary. Inspect the preview and verify the requested cuts, captions and audio. For supported operations, use the tool reference; the common ones have their own pages, like silence removal, captions and reframing.
Frequently Asked Questions
Add It to Your Next Session
Create a free Valmera account, run one claude mcp add, sign in with /mcp — then edit your next screen recording without leaving the terminal.
Create a free account →