# Edit videos with KLO

KLO imports original footage, saves an editable project, renders a finished video, and returns a download link. Users can ask for revisions in the same project. Personal custom connections do not need a marketplace listing, but the assistant must provide custom remote MCP or an equivalent authenticated HTTP integration.

Read the craft recipe at https://mcp.getklo.com/editing.md (also read_skill: 30-cloud-workflow) before a broad creative edit. On every profile, get_runtime_guidance {brief: the exact request, projectId: optional owned project, intendedTools: optional planned operations} selects installed craft guide names and reasons. Selection is not the guide bodies: read_skill {name} returns a whole guide, even before opening a project. list_skills lists all installed guides. For broad authored work read 19-editing-contract and 29-editorial-defaults plus the relevant domains; a narrow revision preserves approved work. Guides do not authorize unavailable tools or extra changes.

## Start with the user's request

1. Reuse a working KLO connection. If none exists, use the host's native custom-connector setup. Use KLO's private sign-in-link flow only when the host has HTTP access and secure persistent storage but cannot complete native OAuth.
2. Ask for the edit and original clips only if the user has not supplied them. Use a downloadable attachment or file link, transfer original bytes, or call create_upload_page so the user can choose the original file in their browser. This does not require a filename or byte count in advance. Keep the source aspect ratio and framing unless the user chooses another format.
3. Import the clips and wait until get_media reports them ready. Make the requested edit in one project; save its projectId for later changes.
4. Follow the job's polling interval until it completes. Continue in the background when the host supports it; otherwise explain how the user can resume the same job. Do not start a duplicate edit because a response is delayed.
5. Get the completed deliverable for this edit and return its protected review link and separate access code, plus an attachment if the host can send the actual file. Say what you verified and keep the project for revisions.

## Connect once

- Full MCP endpoint: https://mcp.getklo.com/mcp
- Transport: Streamable HTTP. Authentication: OAuth 2.1, PKCE S256; scope: klo:edit.
- Discover authorization at https://mcp.getklo.com/.well-known/oauth-protected-resource/mcp and https://mcp.getklo.com/.well-known/oauth-authorization-server. Dynamic client registration is supported. Do not invent a client ID or secret.
- First check an existing connection with a read-only call such as list_projects; do not send a new sign-in link when it already works. Do not display unrelated project details just to prove connection.
- If the host supports adding a custom remote MCP connector, use that native setup and its saved OAuth connection. If the user must open a settings page, give the relevant https://mcp.getklo.com/connect section and the next step. A prompt cannot install a connector where the host requires the user to add it.
- Let the user create/sign in to KLO with Google (or sign in to an existing password account), review the account balance and approve the connector. New verified accounts receive 200 free credits once with no card needed. An existing account retains its prior grant and balance. Paid AI permission is an optional unchecked box, separate from account connection and purchases. Never ask for a password or paste access tokens into a chat. The host must keep refresh tokens privately and save every rotated token before future use. Never ask the user to copy a code, configure an API key, run terminal commands, or move a token file.
- If native OAuth is unavailable but the host can make HTTP requests and has a private persistent vault, use the sign-in-link flow below. A temporary session file alone is not a lasting connection. If neither route is available, name that limitation and offer a supported setup from https://mcp.getklo.com/connect; do not promise a connection from reading this guide.
- Call tools/list after connecting; use the returned schemas. Tool availability can differ by endpoint or client cache. Confirm access with a successful read before starting an edit.

For the restricted editing-only profile, connect https://mcp.getklo.com/mcp/editing and use its own protected-resource metadata at https://mcp.getklo.com/.well-known/oauth-protected-resource/mcp/editing. It does not expose run_klo_agent, generation, generic dispatch, billing or sharing. Its OAuth token cannot authorize the full endpoint. Make edits using the tools returned by that profile.

## Keep the caller's context small

For integrations that support tool filtering, start with get_capabilities, get_runtime_guidance, list_skills, read_skill, discover_tools, run_tool, get_edit_context, create_project, create_upload, create_upload_page, get_media, get_job, get_job_events, get_deliverables, get_account, get_spending_link and export_video. Discover delivery tools only when a completed file exists. Discover a schema only when needed, then invoke its returned route; a directly advertised tool excluded by your host filter can also be invoked through run_tool on the full endpoint. Keep discovered schemas in your working context. This reduces schema overhead; it is not a permission or billing boundary, because run_tool retains the full endpoint's authorized dispatch capabilities. Use the editing-only endpoint when a restricted surface is needed.

xAI's remote MCP API supports allowed_tools (allowed_tool_names in its native SDK): https://docs.x.ai/developers/tools/remote-mcp. Without a filter it injects every advertised definition. This API configuration is host-owned; do not claim a consumer bot's settings changed just by reading this page.

## Original clips to a finished video

1. Call create_project with a name and optional canvas, or open_project with an existing projectId. Preserve source aspect ratio and framing unless the user chooses a different format; a generic request for a polished edit does not authorize a vertical or square crop. When the source dimensions are known, choose the matching supported canvas. Keep projectId explicit on subsequent calls so other assistant sessions cannot change your target.
2. Import footage using one of the methods below. Poll get_media with projectId until each required media item is ready. Inspect its width and height, then confirm the canvas before editing. If it was unknown at creation, use set_canvas_ratio with a matching supported ratio (through run_tool if not listed directly). For mixed or unsupported source ratios, use contain framing rather than silently cropping; ask only if the requested composition needs a format decision. If an item is failed, report its error and correct the source; do not edit an empty project or pretend an attachment arrived.
3. Lead the creative edit yourself using your own model reasoning and KLO's direct tools. On the full endpoint, get_edit_context returns saved progress, active jobs and the next step without a model call. discover_tools returns exact schemas and invocation routes; follow its direct tool or run_tool route. Use get_runtime_guidance with the exact brief for relevant guide names; read the whole guides with read_skill. Inspect source footage and transcripts, work out a source-backed story and then assemble and refine it. Use a formal write_plan only when its documented planning and approval workflow is appropriate. Creative editing is not restricted to simple trims. After each meaningful pass inspect a rendered frame, cut boundary or short preview_range video and the sound; revise from evidence. Save milestones with save_version. Do not perform a full export for each small adjustment. Basic direct edits/exports currently do not debit KLO AI credits; transcription, provider analysis and generation can. Hosting and rendering still consume infrastructure.

   Optional delegation: call run_klo_agent only when you choose to hand KLO a bounded editing task or the user prefers it. It consumes KLO credits; honor the user's budget. Include the audience, length, must-haves, sound and framing. Use {projectId, brief, autoExport, requestId}; set autoExport:false for an intermediate pass you will review. Reuse requestId with identical inputs after an uncertain response. It returns jobId immediately; get_job_events with afterId/nextCursor provides incremental tool outcomes without noisy render ticks. send_job_message supplies direction between model steps. Do not mutate the timeline concurrently with the delegated agent. If it fails, inspect the saved project and continue from that progress rather than redoing the entire brief.
4. Poll get_job with {jobId} at the returned pollAfterSec interval, normally 10–20 seconds. Wait for done, failed or cancelled. A queued/running response is not a finished edit. Use cancel_job only when the user wants the work stopped.
5. Read the completed job's deliverables, or get_deliverables with {projectId}. Match the requested job and revision; a project can contain earlier exports and multiple formats. Inspect the resulting video or sampled frames and audio when your tools permit. Return the protected review URL and separate accessCode from that completed deliverable and say what you verified. show_editor opens the preview in compatible clients when that tool is exposed and has a text fallback.
6. For revisions, keep the projectId, read get_edit_context and get_project_state, and apply the requested change directly. Review the affected frames, motion and audio, then export the revised cut. Use run_klo_agent only for deliberate delegation, not as a mandatory revision path. Existing exported files remain separate deliverables. If access expires, use create_delivery_link for that deliverable to issue a fresh link/code without rerendering.

The editing-only profile uses direct editing tools and export_video instead of run_klo_agent. Follow its live export_video schema; asynchronous registry exports use export_status. Long-running tools may return a deferred jobId to poll with get_job.

If the user asks to keep the original audio levels unchanged, retain the source audio, avoid gain or cleanup changes, and set export_video master:false. Mastering is on by default and changes loudness; do not call that unchanged audio. The rendered export may still re-encode the source.

The no-AI-credit behavior above applies to those direct tools, not every operation an assistant might call during a session. Additional transcription, AI analysis or generation can have separate costs. Report observed charges when available; do not promise that the entire session spent zero credits or attribute a shared account-balance change to one job without evidence.

## Account, credits and spending

Connection is free and starts no work. Call get_account before paid work and use billing.spendableCredits, heldCredits, pendingOperations and welcome receipt; a connection alone does not establish a plan or available credits. A new eligible registered verified account receives a one-time 200-credit welcome grant. Historical grants remain as recorded, including accounts that previously received a different amount. Do not promise a new grant on reconnect or infer that the receipt was issued today.

Paid provider tools require the human's spending consent for this OAuth connection or API key. When get_account reports it disabled, offer get_spending_link. The human signs in, reviews the named connection, and enables or disables paid AI in the browser. Do not submit this consent for them. Consent survives OAuth refresh, not a different independent connection. Revocation is checked again before paid operations. The permission does not buy credits and is not a hard per-run spending cap. Agree a practical budget, use small bounded passes, and disclose uncertainty when an exact estimate or cap is not available.

- billing status ready: use the authoritative spendable amount, with user scope and known costs.
- held: inspect pending work and its events. Do not buy credits or retry an uncertain paid call merely to resolve a hold.
- unavailable/verification_required: do not submit paid work. Explain the account check or verification needed; direct editing can continue.
- exhausted: preserve the project and offer direct editing or a human-reviewed billing link. Choose an offer with the user before get_billing_link action checkout. A checkout link is not a completed purchase. After the browser payment, refresh get_account and resume the same project and original conversation.

Hosted import does not automatically transcribe. Call get_transcript explicitly when needed. Sponsored transcription can be available at zero spendable credits while the account has an eligible allowance; it still requires human AI permission. Let the backend decide eligibility, and never promise the allowance is available or renewable.

Keep the outside model's token spending separate from KLO credit usage. Account balance changes alone cannot identify the cost of one job while other work runs. Report actual provider usage receipts where available; never promise all processing was free because the timeline tools did not debit credits.

## Get footage into the project

### Downloadable attachment or file link

Call add_footage with {projectId, sources:[{url,name}]}. The URL must return media bytes accessible to KLO. Single-file Drive and Dropbox share links are supported when the downloader can access them. Do not change a private file's sharing permissions just to make an import work.

ChatGPT clients that expose file parameters can instead supply files:[{download_url,file_id,file_name,mime_type}] to add_footage; file_name and mime_type are optional. A filename, local filesystem path, chat_upload:// URI, or a web page requiring login is not a downloadable attachment. Do not copy credentials from another service into source URLs.

### Original file bytes available to the assistant

Call create_upload with {projectId,name,bytes}, where bytes is the exact original file size. POST those bytes to the returned uploadUrl with Content-Type: application/octet-stream. No Authorization header is required on this scoped URL. It expires after 15 minutes and is single-use. The successful HTTP 201 response provides mediaId and jobId; ingestion is automatic, so do not call add_footage on the uploaded file again. An interrupted or wrong-size attempt needs a new grant.

Authenticated HTTP clients can also use POST https://mcp.getklo.com/upload?project=PROJECT_ID&name=FILE_NAME for a raw upload, or POST https://mcp.getklo.com/upload/init followed by PATCH chunks for resumable uploads. These routes require the client's securely stored bearer token. Do not expose it to a separate uploader.

Uploads preserve the bytes sent. A chat platform may already have compressed an attachment; use the original file when quality matters. Exports are newly rendered videos, not bit-for-bit copies of source media.

### Attachment access unavailable

Call create_upload_page with {projectId} and share its uploadPageUrl privately. No filename or byte count is needed: the user selects their original file and clicks Upload to KLO, and the browser reads its metadata and transfers the original bytes. The link permits one file up to the returned maxBytes in this project and expires after 15 minutes. Opening or previewing the page does not consume it. The upload capability stays in the URL fragment and request headers; the page never receives the assistant's OAuth token.

Record the project's existing media IDs before sharing the link. Poll get_media in the same project until the new required upload is ready, then continue the edit; an older ready file does not prove that this upload arrived. Continue polling in the background when the host supports it, without requiring an extra “done” message. Uploads ingest automatically; do not call add_footage again. If an upload attempt was interrupted or its result is uncertain, check get_media before requesting another link so the user does not upload twice. Existing create_upload links still work for an original file of the exact size given when the link was created.

If the assistant cannot call KLO tools at all, a connected client is required first. Explain the missing capability and offer a compatible assistant. Never stage private footage on an unrelated public hosting service.

## Return the video

Human delivery is protected by a review link plus a separate access code. get_deliverables returns completed records with url, accessCode, expiresAt, grantId and access:"code_required". Match the requested job/revision. Give the intended recipient the clickable URL and the code separately; never append the code to a URL. Anyone with both can access the file, so this is possession-based protection, not verified recipient identity. Existing legacy signed links are not made private retroactively.

Use get_deliverables {projectId,metadataOnly:true} when inspecting history without creating new links. create_delivery_link {deliverableId} creates a fresh bounded link/code, normally for seven days. If a code is lost or the link expires, issue a new grant for the same file; do not rerender or run another model. list_delivery_links returns metadata without revealing codes; revoke_delivery_link disables a grant. These tools never publish to an external audience by themselves.

For agent-side inspection or an actual chat attachment, create_agent_delivery {deliverableId} returns a short-lived HTTP URL requiring the connection's private Authorization header. It is bound to this account and OAuth family/API key, not a public browser link. A refreshed token in the same OAuth family works; another connection needs its own grant. Never paste bearer tokens into chat, a URL or a third-party downloader. If the host cannot fetch authenticated HTTP privately, read_agent_delivery {grantId,offset,length} returns bounded base64 chunks over MCP. Follow the returned size/end markers; do not put base64 in the user's chat. Revoke unused access with revoke_agent_delivery. A real host attachment is optional; never claim an attachment when only a link was returned.

Keep projectId, jobId and the receipt's polling tool in the conversation. A worker job uses get_job; an export receipt explicitly naming export_status uses that tool. IDs are different namespaces. get_job reports progress and deliverable metadata but does not reveal review codes. A private jobPageUrl is a progress page, not authorization to download a protected video. Server work may continue after the chat disconnects; automatic chat follow-up depends on the host. Resume recorded IDs and saved state instead of re-importing footage or starting the brief again.

Detached exports publish completed records even if the host stops polling. Match filename, format, job and completion time so an older export is not described as the requested revision. Pending and failed work is not a finished video. Before delivery, inspect the file or honest sampled evidence, and state what was checked versus what still needs a listen. Preserve the project for revisions.

## Sign-in link for assistants without an OAuth callback

This is an assistant implementation detail, not setup work for the user. Native saved OAuth remains the first choice. KLO supports RFC 8628 device authorization for HTTP-capable assistants with private persistent storage. The user taps a link, signs in with Google, confirms the assistant name and matching code, then returns to the chat. Opening a link never grants access on its own. Tokens go privately to the requesting assistant, never through the browser or chat.

1. Register a public device client at POST https://mcp.getklo.com/oauth/register with client_name identifying your assistant, token_endpoint_auth_method:"none", grant_types:["urn:ietf:params:oauth:grant-type:device_code","refresh_token"], and response_types:[]. No redirect URI or client secret is required.
2. POST https://mcp.getklo.com/oauth/device/authorize with client_id, scope:"klo:edit", resource:"https://mcp.getklo.com/mcp". Keep device_code private. Share only verification_uri_complete and the matching user_code with the user. Do not ask them to type the code when using that complete link. Start private background polling after sharing the link so approval resumes the connection automatically; do not require an extra “done” message when the host can continue in the background. Start only when the user is ready; the request expires after 10 minutes.
3. Poll POST https://mcp.getklo.com/oauth/token with grant_type:"urn:ietf:params:oauth:grant-type:device_code", client_id and device_code at the returned interval. Continue only for authorization_pending or slow_down. On slow_down add 5 seconds to the interval permanently. Stop on access_denied or expired_token; do not silently request another grant.
4. Store the returned connection bundle in the host’s private vault. Refresh on demand using grant_type:"refresh_token", client_id and refresh_token at the same token endpoint. Serialize calls and save the new pair atomically; refresh tokens rotate and replay revokes the connection. Do not keep independent copies that can refresh concurrently.
5. Prove reuse by restoring the saved connection in a later execution and making a read-only call. Verify refresh as well as initial access. Never claim durable connection from a successful first call alone.

### Optional helper for the assistant

The Python 3 standard-library client at https://mcp.getklo.com/klo-connect.py runs in a Linux or macOS environment with private writable storage. It uses POSIX file permissions and locking; hosts without that runtime can implement the HTTP flow above with their private vault. Download the file from this official KLO origin, inspect it, and invoke it as a file. Do not pipe a download into a shell or ask the user to run it. The helper prints the sign-in link and status, never credentials.

Choose one absolute state path per assistant/account connection in a private 0700 directory, with a 0600 state file. Replace the example path and assistant name below with the host's real values. Global options such as --state and --base go before the command; use the same path for every operation:

    python3 klo-connect.py --state "/absolute/private/klo/connection.json" --base "https://mcp.getklo.com" start --name "Your assistant"
    python3 klo-connect.py --state "/absolute/private/klo/connection.json" --base "https://mcp.getklo.com" wait
    python3 klo-connect.py --state "/absolute/private/klo/connection.json" --base "https://mcp.getklo.com" call list_projects --input '{}'
    python3 klo-connect.py --state "/absolute/private/klo/connection.json" --base "https://mcp.getklo.com" refresh

Share the link returned by start before starting wait in the background. Monitor that task's completion; wait holds the connection lock, so do not issue status or disconnect concurrently against the same state. Stop the waiting process before another command; an interrupted wait can resume from its retained state.

In a temporary environment, restore the latest private JSON bundle from the vault before an operation. Save the resulting state back after every operation that can change it: start, wait, status, call, tools/list-tools, refresh and disconnect, including after an error or interruption. start saves the pending device request; wait saves issued tokens; even status may rotate tokens. Serialize the entire restore → operation → save sequence across executions, using one vault entry and no independently refreshing copies. If saving fails, stop and recover that latest state before further calls. Never print the bundle or put it in chat. A vault approval is the host's permission step. It does not require the user to handle credentials.

## Assistant availability

- Muse: ask it to create a custom remote MCP connector using https://mcp.getklo.com/mcp and OAuth, then complete its sign-in link. A personal connection is separate from marketplace approval; confirm access to the actual footage before promising an edit.
- Pally: ask in chat to connect KLO as a custom remote MCP server at https://mcp.getklo.com/mcp, transport Streamable HTTP, authentication OAuth. Pally's October 27 update explicitly supports connecting a custom server by its address in chat: https://pally.com/whats-new/2026-10. An HTML attachment preview is not a media download: resolve a direct video URL or upload the original bytes with create_upload. If Pally cannot access the bytes or metadata, call create_upload_page with {projectId} and return uploadPageUrl so the user can choose the original in their browser. Verify the new upload's readiness with get_media before editing.
- Boski: custom MCP and original attachment transfer are not yet verified. A message saying “use KLO” cannot enable missing platform capabilities. Use a compatible assistant if the platform provides no custom connector or authenticated tool execution.
- Instinct: where the host permits HTTP connections and private vault storage, use the sign-in-link flow above and save one private connection bundle. This worked in KLO's October 25 test; availability can vary by account. Confirm the vault can restore and update that bundle across executions; a session-only file is insufficient. The user signs in and approves KLO access, then approves use of the saved vault entry. Restore and update the same entry privately for later calls. If the host does not permit this flow, report that limitation. Never ask the user for an API key or copied authorization code.
- Claude, ChatGPT, Poke, Cursor, Grok, Manus, Gemini and Perplexity: see https://mcp.getklo.com/connect for setup links and steps. Availability depends on the account and client. Test connection, footage import, completed render and returned download separately; a documented install link does not prove a completed edit in that host.

## Paste into a compatible assistant

Use KLO to edit my videos. Follow https://mcp.getklo.com/agent.md and reuse my connection if it already works. Help me add my original clips and make the edit I describe. Keep their aspect ratio and framing unless I ask for a different format. Send back the finished video with a download link, and keep the project for changes. If setup needs my help, send me the right link and explain the next step.

Support: https://mcp.getklo.com/support. Privacy: https://mcp.getklo.com/privacy.
