ViralTwin MCP server
Reference for the remote MCP server at https://mcp.viraltwin.app/mcp. Streamable HTTP transport, OAuth 2.1 with PKCE, ten tools.
Overview
The ViralTwin MCP server exposes ViralTwin's video remix pipeline as MCP tools that Claude — or any MCP client — can call. The flagship tool, remix_youtube, takes a YouTube URL and returns a finished 9:16 short. Lower-level tools let you orchestrate each step yourself.
| Endpoint | URL |
|---|---|
| MCP server (resource) | https://mcp.viraltwin.app/mcp |
| Resource metadata (RFC 9728) | https://mcp.viraltwin.app/.well-known/oauth-protected-resource |
| OAuth metadata (RFC 8414) | https://viraltwin.app/.well-known/oauth-authorization-server |
| DCR endpoint | https://viraltwin.app/oauth/register |
| Authorize | https://viraltwin.app/oauth/authorize |
| Token | https://viraltwin.app/oauth/token |
Authentication
Authentication uses OAuth 2.1 with Dynamic Client Registration (RFC 7591) and PKCE (RFC 7636). Compliant MCP clients (Claude Desktop, claude.ai, Claude Code, Cursor, Windsurf) handle the entire flow automatically — paste the URL, click Connect, sign in, click Allow.
What happens under the hood
- Client fetches
/.well-known/oauth-protected-resourcefrom the MCP endpoint to discover the auth server. - Client registers itself via
POST /oauth/register(DCR) and gets a publicclient_id. - Client opens
/oauth/authorizewith PKCE; ViralTwin shows the consent screen and (after Clerk sign-in) issues an auth code. - Client exchanges the code at
/oauth/tokenfor an access token (60 min) and refresh token (30 days, sliding). - Every MCP call uses
Authorization: Bearer <token>.
Scopes
| Scope | Grants |
|---|---|
| viraltwin.read | View canvases, credit balance, generated video URLs |
| viraltwin.generate | Run analyze, prompt, scene generation, render, remix tools |
| viraltwin.canvas | Create / edit / delete canvases (Stage 3 — not yet wired) |
Tools
All tools accept structured inputs (JSON Schema, validated server- side with Zod) and return MCP content arrays — typically a human-readable summary line plus a full JSON payload Claude can chain into the next call.
analyze_videoauth: authenticatedcost: 3 free per account, then subscriber-onlyScene-by-scene Gemini 2.5 Pro analysis. Same 3-analysis lifetime free quota as the web app — subscribers are unlimited.
| name | type | notes |
|---|---|---|
url | string (URL) | YouTube watch / shorts / youtu.be |
videoId, url, analysis { title, summary, style, characters[], scenes[] }, freeAnalysesRemaining
generate_scene_promptsauth: authenticatedcost: free (cheap GPT-5-mini call)Sanitization is automatic — banned cinematography phrases get auto-substituted. Warnings list anything we couldn't fix.
| name | type | notes |
|---|---|---|
analysis | object | Pass the analyze_video result |
userPrompt | string? | How to remix the video |
preferredModel | string? | Default seedance-2.0 |
characterConsistency | boolean? | Lock identity across scenes |
scenes[] with prompt + negativePrompt + purpose, plus optional characterBrief
generate_scene_videoauth: authenticated · subscriber or credit-positivecost: varies — see list_models for per-model price rangesSubmits to Kie. Seedance 2.0 / 2.0 Fast auto-fallback to Seedance 1.5 Pro on photoreal-face filter rejections (refunds + re-charges automatically).
| name | type | notes |
|---|---|---|
prompt | string | Required |
negativePrompt | string? | |
imageUrls | string[]? | Reference images (1-9) |
model | string? | Default seedance-2.0 |
aspectRatio | 9:16 | 16:9 | 1:1? | |
duration | number? | Snapped to model's nearest |
resolution | 480p | 720p | 1080p | 4K? | |
generateAudio | boolean? |
jobId, pollingUrl, ledgerRef, model, config, charged, fallbackUsed
check_video_statusauth: authenticatedcost: free (poll)On terminal failure, the original credit reservation auto-refunds idempotently.
| name | type | notes |
|---|---|---|
pollingUrl | string (URL) | From generate_scene_video |
ledgerRef | string? | From generate_scene_video |
status (queued | generating | completed | failed), videoUrl, error, refunded
render_canvasauth: authenticatedcost: free (just CPU)Single-scene calls skip ffmpeg and just mirror to R2. Multi-scene runs the concat demuxer (fast path) with re-encode fallback.
| name | type | notes |
|---|---|---|
sceneUrls | string[] (URLs) | Generated scene videos in order |
aspectRatio | 9:16 | 16:9 | 1:1? | Default 9:16 |
id, key, url (final MP4 on R2 CDN), sceneCount, bytes
remix_youtubeauth: authenticated · subscriber or credit-positivecost: N × generate_scene_video (one per detected scene, max 5)Blocks until done (typically 2-4 min). Submits all scenes in parallel. If any scene fails, the whole call returns an error; partial successes still count against credits.
| name | type | notes |
|---|---|---|
url | string (URL) | YouTube URL |
instructions | string? | How to transform |
model | string? | Default seedance-2.0 |
aspectRatio | 9:16 | 16:9 | 1:1? | Default 9:16 |
characterConsistency | boolean? |
videoUrl, sceneUrls, sourceVideo, model
list_modelsauth: authenticatedcost: free14 video models across Seedance, Wan, Kling (incl. 3.0), Sora 2, Veo 3.1.
defaultModelId, models[] with vendor, supported config, price ranges
get_creditsauth: authenticatedcost: freeReflects the same balance as the web app — credits are shared.
balance, planTier, status, hasActiveSubscription, currentPeriodEnd
list_canvasesauth: authenticatedcost: freeNewest first. Pair with get_canvas for the full graph.
| name | type | notes |
|---|---|---|
limit | number? | 1-100, default 20 |
canvases[] with id, title, updatedAt, nodeCount
get_canvasauth: authenticatedcost: freeReturns 'not found' if the canvas isn't owned by the connected user.
| name | type | notes |
|---|---|---|
id | string | 10-char nanoid |
full DTO: id, title, description, thumbnail, graph (nodes + edges)
Error handling
Tools return MCP error results (isError: true) with a human-readable message. The most common failures are:
| Reason | Tool message |
|---|---|
| Missing or invalid token | 401 with WWW-Authenticate header — Claude re-runs the connect flow |
| Free quota exhausted | Used all 3 free analyses → subscribe to continue |
| Out of credits | "You need N credits but only have M..." |
| Invalid YouTube URL | "That doesn't look like a valid YouTube URL..." |
| Generation failed | Provider error surfaced verbatim |
| Timeout | remix_youtube hit max wait — job is still running on Kie |
Every MCP request requires a valid bearer token. Unauthenticated requests return a 401 with the OAuth challenge header, which triggers Claude's connect flow.
Rate limits
- Free account: 3 analyses lifetime (not rolling) — same quota as the web app
- Subscriber: unlimited analyses, generation gated by credit balance
- Auth tokens: 60 min access, 30 day refresh (sliding)
Troubleshooting
Connector won't connect
- Make sure you pasted the full URL:
https://mcp.viraltwin.app/mcp(with/mcpat the end). - If your MCP client errors on the OAuth round-trip, check that it supports Dynamic Client Registration (RFC 7591). All Anthropic clients do; some third-party clients don't.
Auth screen loops
The consent screen requires you to be signed in to ViralTwin in the same browser. If sign-in keeps redirecting, clear cookies for viraltwin.app and retry.
"Out of credits" on a paid plan
Auto top-up may be off — check billing settings. Failed jobs auto-refund within ~30 seconds; if your balance looks short right after a failure, give it a minute.
Changelog
| Date | Change |
|---|---|
| 2026-05-08 | v0.1.0 — initial release: 10 tools, OAuth 2.1 + DCR |
Found a bug or want a tool we don't expose yet? Email us.