← Home
CLI GUIDE

Published · Updated

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 exported MP4 into ./dist. 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.

RUN THIS
claude mcp add --transport http valmera \ https://entrepreneur-bot-backend.onrender.com/mcp

Then /mcp inside Claude Code to sign in. Streamable HTTP · OAuth 2.1 with dynamic client registration and PKCE · 108 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, export 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

  1. 1
    Create a Valmera account
    Sign up free at valmera.io with email or Google. Every account gets 50 credits, no card required. If you signed up with Google, set a password with "Forgot password" first — the OAuth consent screen needs one. MCP access is then enabled per account while the connector is in limited release, so if the sign-in succeeds and the server still answers "this account is not enabled for MCP access", that is the allowlist rather than your password.
  2. 2
    Add the server
    Run: 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.
  3. 3
    Authenticate
    Start 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.
  4. 4
    Confirm it connected
    Run 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.

LocalProjectUser
Flag--scope local (default)--scope project--scope user
Loads inThis repo onlyThis repo onlyEvery repo on your machine
Stored in~/.claude.json.mcp.json in the repo root~/.claude.json
Committed to git
Teammates get it
Use it whenTrying it outThe repo ships videosIt 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 · 108 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 export it 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.

⏺ export_final()
    STILL RUNNING — the final export of v6 is job 8817 (queued, 0%).

⏺ wait_for_job(job_id: 8817)
    The final export is rendered. Call download_url(kind="final").

⏺ download_url(kind: "final")
    final of EDL v6 — https://… (link valid a few hours)

⏺ Bash(mkdir -p dist && curl -sS -o dist/v2-release-9x16.mp4 'https://…')

  Done. dist/v2-release-9x16.mp4 — 66.9s, 9:16, captions burned in.
  Rendered from your original .mov, not from the preview proxy.

Two details in that last line are load-bearing. The preview renders from a fast proxy because it has to be quick; the export goes back to the file you uploaded and renders 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 render, an export, burned-text erasure or a generated clip comes 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 will happily fire off exports faster than they render.

A finished export is a link, not a file transfer

export_final renders, then download_url(kind="final") mints a temporary URL. In a terminal that is the good ending: the agent curls it straight into ./dist/ and tells you the path. MCP arguments are JSON, so no video ever crosses the protocol itself in either direction.

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, exporting, 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 export_final 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.
  • One deliverable per request. A 16:9 for the docs and a 9:16 for social are two requests, not one matrix build. There is no batch output.
  • 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 or 3 hours, in MP4, MOV, 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 export is a file you download and post yourself.

The agent knows these edges too, and refuses out-of-scope requests instead of faking them — every reply is verified server-side against the edit decisions actually recorded, so it cannot report a change it did not make. The full inventory of what it can do is the tool reference; the common ones have their own pages, like silence removal, captions and reframing.

Frequently Asked Questions

Not on its own — Claude Code has no video engine and cannot render a file. Connected to a video editing MCP server it can. With Valmera added as a remote HTTP server, Claude Code gets 108 tools (97 editing, 11 session) and can create a project, upload a local file, cut silences and filler words, add captions, reframe to 9:16, render a preview, look at the frames it produced, export from the original file at source quality, and download the MP4 to a path in your repo — without leaving the session.
Run: claude mcp add --transport http valmera https://entrepreneur-bot-backend.onrender.com/mcp. Then start Claude Code, run /mcp, and complete the browser sign-in. Claude Code discovers the authorization server from the endpoint, registers itself dynamically, and stores the token in your keychain. Confirm with claude mcp list, which shows a health status next to each server.
Point an MCP client that has a shell at an editing engine that has an API. Claude Code is that client; Valmera is that engine. The pairing works because upload_start hands back a presigned URL and the exact curl command to push the bytes — a chat app cannot run that command, and a terminal agent can. So "cut the silences in ~/screencaps/v2.mov, caption it, 9:16, export to ./dist" is one sentence and the file lands on disk.
Local (the default) stores the server in ~/.claude.json under the current project's path — private to you, this repo only. Project writes .mcp.json in the repo root, which you commit, so every teammate gets it. User stores it in ~/.claude.json for all your repos, still private to you. When the same name appears in more than one, local wins, then project, then user; the whole entry from the winning source is used and fields are not merged.
claude mcp add --transport http valmera --scope project https://entrepreneur-bot-backend.onrender.com/mcp writes .mcp.json at the repo root. Commit it. The file carries the URL and the transport type, never a credential — each teammate authenticates as themselves with /mcp, against their own Valmera account and their own credits. Claude Code prompts each of them for approval before it will use a server defined in .mcp.json; claude mcp reset-project-choices clears that answer if someone needs to redecide.
Yes. claude mcp add --transport http valmera https://entrepreneur-bot-backend.onrender.com/mcp --header "Authorization: Bearer vlm_mcp_..." attaches a static token, which is what a client with no OAuth support or a headless environment needs. Tokens are shown once and stored only as a sha256 hash, so a lost token is replaced rather than recovered. In a committed .mcp.json, reference it as ${VALMERA_MCP_TOKEN} — Claude Code expands environment variables inside headers, so the secret stays out of git.
Because it has not finished, and saying so is better than blocking or lying. Renders, exports and pixel repainting outlast any sensible request timeout, so they return a job id: "STILL RUNNING — render_preview is job 8814 (running, 12%). Nothing has failed; call wait_for_job(job_id=8814) to pick the result up." Every Valmera call returns inside about 25 seconds, which keeps it under Claude Code's 60-second per-request timer for HTTP servers. The job continues server-side regardless.
Mechanically yes, and there are three things to get right. Authenticate with a bearer token — a claude -p or Agent SDK run has no /mcp panel, so Claude Code cannot run the OAuth flow for you, and claude mcp login --no-browser is not the way round it: that path still needs an interactive terminal for the paste step, which makes it an SSH answer rather than a CI one. Allow the tools you need in permissions (mcp__valmera__* matches every tool from the server; an allow glob must be anchored after the mcp__<server>__ prefix). And know that non-interactive runs do not background long tool calls unless CLAUDE_AUTO_BACKGROUND_TASKS is set to 1, so the wait_for_job loop is your own responsibility. The honest caveat is editorial, not technical: an unattended run has nobody to judge the preview. The agent checks its own frames, but that is a correctness check, not your taste.
Yes, and that is the main thing it has over the Claude app. upload_start returns a presigned URL plus the literal curl command to run, and Claude Code runs it with Bash. Files up to 16MB go as one PUT; above that the upload is multipart, so upload_start returns a part size and one presigned URL per part, and the agent PUTs each part and passes the ETags back to upload_finish. You can also skip the local file entirely and give it a link to fetch.
No, and it is refused in both directions rather than allowed to corrupt the edit. An MCP tool call on a project with a studio agent turn in flight 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." The studio refuses to start a turn while an MCP call is running. Two writers on one edit decision list each read state the other is halfway through changing.
It is a standard streamable-HTTP MCP server with OAuth 2.1, dynamic client registration and PKCE, plus a bearer-token path for clients that do not implement OAuth. Any compliant client should work. Claude Code and the Claude app are the two we have verified end to end, and we would rather name those two than list clients we have not tested.
You need a Valmera account, and MCP access is enabled per account while the connector is in limited release. Every account gets 50 free credits at signup with no card. Paid plans are Creator $30/mo (2,000 credits), Pro $50/mo (4,000) and Frontier $100/mo (10,000), each opening with a 3-day free trial. Credits are spent by the work actually done — a render and an export cost real compute, and the thinking your model does costs nothing.

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 →
See pricing →

Related Articles

Connect Claude to Video Editing
The same server from the Claude app's connector UI — one paste, one sign-in, no commands.
Valmera MCP Server
The server itself: transport, auth, and the design decisions behind it.
MCP Tool Reference
All 108 tools, what each does and what it refuses.
Video Editing MCP Servers
Every MCP server that edits video, compared — including where another one is the better answer.
Agentic Video Editor
Why an editor built as an agent is the kind another agent can drive.