appsgolem-mcp (Node / TypeScript)
An MCP server for the AppsGolem YouTube
cutter API. It lets an AI agent (Claude Desktop, Claude Code, Cursor, …) cut
clips from YouTube videos — in any format the web cutter supports — and get a
direct download URL back. The REST logic lives in a small, dependency-light
client (src/client.ts); src/server.ts is the thin MCP tool layer over it.
Get your API key → appsgolem.com/agents — sign up, add prepaid credits, and generate a key (
ag_live_…). That page also has copy-paste setup for Claude Code, Codex, Cursor, and any MCP client, plus a prompt cookbook.
Requirements
- Node.js >= 18 (uses the global
fetch). - An AppsGolem API key (
ag_live_…) — get one at appsgolem.com/agents (sign up → add credits → generate a key in your dashboard). Credits are prepaid; buy a pack or a subscription, no auto-renewal required.
Install / connect (no manual install)
npx fetches and runs the server on demand — nothing to install globally.
Claude Desktop / Cursor — add to the client's MCP config (e.g.
claude_desktop_config.json):
{
"mcpServers": {
"appsgolem": {
"command": "npx",
"args": ["-y", "appsgolem-mcp"],
"env": { "APPSGOLEM_API_KEY": "ag_live_…" }
}
}
}
Claude Code — one command:
claude mcp add appsgolem -e APPSGOLEM_API_KEY=ag_live_… -- npx -y appsgolem-mcp
The server speaks MCP over stdio (the transport those clients use). A
missing APPSGOLEM_API_KEY is not fatal at startup — the server still starts
and advertises its tools; each call then returns a clear config_error telling
you to set the key.
Configuration
Pricing
1 produced clip = 1 credit. 2160p (4K) = 4 credits per clip — except
audio_only, which stays 1. A source longer than 2 h adds +1 once
per job, but only when its duration is known (the surcharge is skipped if the
probe can't determine it). A batch/stitch of N clips costs N per-clip.
Failed cuts are never billed.
Tools
The server exposes three tools. A call that passes MCP input-schema
validation returns a structured result — the API's own JSON on success, or
{ "error": … } on any handler/API failure — and never raises a protocol-level
error, so an agent always gets a usable object. (Invalid tool arguments are
rejected by the MCP SDK before the handler runs, as a text-only isError
result.)
1. cut_youtube_video
Cut a clip (or a batch of clips) from a YouTube video. By default it waits
until the clip is produced and returns its status (including a download_url
once a download token is ready); set wait: false to submit and return
immediately with the current job (its state is normally queued after dispatch).
Parameters
Returns (wait: true, default) — the produced job status. download_url is
present once a download token is available; if it isn't yet, poll again:
{
"id": "e48db1a2-1c3d-4e5f-8a9b-0c1d2e3f4a5b",
"state": "produced",
"credits_reserved": 1,
"created_at": "2026-08-22T12:00:00+00:00",
"download_url": "https://appsgolem.com/v1/download/…/clip.mp4"
}
Returns (wait: false) — the job immediately, with its current state
(normally queued after dispatch) and no download_url yet; poll
get_cut_status with the id (or fetch poll_url):
{
"id": "e48db1a2-1c3d-4e5f-8a9b-0c1d2e3f4a5b",
"state": "queued",
"credits_reserved": 1,
"poll_url": "/v1/cuts/e48db1a2-1c3d-4e5f-8a9b-0c1d2e3f4a5b"
}
If the wait times out before the clip is ready, the result carries
"still_processing": true and the job id — poll get_cut_status with that
id. If the job reaches a terminal failure, the result is
{ "error": "cut_failed", "state": "failed" | "refunded", "id": … } (and no
credit is charged).
2. get_cut_status
Check a cut job by its id. Use it to poll a job started with
cut_youtube_video(wait=false) or one that timed out.
Returns — the job's state; once produced/delivered it also carries a
download_url when a download token is available (otherwise poll again):
{ "id": "e48db1a2-…", "state": "queued", "credits_reserved": 1, "created_at": "…" }
States progress accepted → queued → produced → delivered, or
failed → refunded on error.
3. get_account_balance
Return the API account's spendable credit balance and current hourly cap. No parameters.
Returns
{ "balance": 412, "hourly_cap": 60 }
Modes
Example prompts
Because the agent picks the parameters from your request, you drive it in plain language:
- "Cut 0:30 to 1:15 from https://youtu.be/dQw4w9WgXcQ in 1080p." →
cut_youtube_video(url, start="0:30", end="1:15") - "Grab the audio of that video from 2:00 to 5:00 as an mp3." →
mode="audio_only", audio_format="mp3" - "Make a vertical short of the 10:00–10:45 highlight." →
mode="short", start="10:00", end="10:45" - "Turn 0:05–0:12 into a GIF." →
mode="gif" - "Extract a contact sheet of frames every 5 seconds from 1:00 to 2:00." →
mode="frames", interval_ms=5000, sheet=true - "Stitch 0:10–0:20 and 1:00–1:10 into one clip." →
clips=[{start:"0:10",end:"0:20"},{start:"1:00",end:"1:10"}], stitch=true - "Do a fast, stream-copy cut of 0:00–0:30." →
fast=true - "How many API credits do I have left?" →
get_account_balance()
Result & error shapes
Every result from a handler is a plain object (MCP argument-validation
failures are the exception — see the Tools note above). On failure the object has an error code
(the tool call still succeeds):
API-level errors — validation 400, 402 insufficient_credits,
404 not_found, 409 idempotency_conflict / duplicate_in_flight,
429 rate_limited, and 503 rate_limiter_unavailable / database_busy — are
returned as the API's own error body plus a status field. A 429 also
includes retry_after (seconds, from Retry-After) plus a reason
(submission_cap · request_rate · poll_rate) so an agent can tell which
limit it hit and back off correctly. A 503 is usually transient (retry after
a short delay), but a persistent 503 is a server-side problem to report — not
to retry indefinitely.
Status polling is not rate-limited for normal use — checking a job's
progress never counts against your submissions/hour cap. You never need to
throttle get_cut_status yourself: cut_youtube_video(wait=true) polls and
paces for you (honoring the server's poll_after cadence and any Retry-After),
so a single tool call handles even long jobs.
Produced download links expire after a bounded window (~72 hours by default on appsgolem.com; configurable per deployment) — fetch the file within it.
A relative download_url (the API returns a path) is resolved to a full URL
against the configured API base only when the result stays on that origin.
Any download_url that resolves off the API's origin — an absolute URL to
another host, or a relative path that escapes the origin — is dropped for
safety: the field is removed and the result carries download_url_dropped: true,
so you can tell it apart from a job that simply isn't produced yet. When
cut_youtube_video is waiting for you (wait=true, the default), an off-origin
link surfaces as a download_url_unsafe error instead of handing back a bad URL.
Develop
npm install
npm run build # tsc -> dist/
npm test # builds, then runs node --test (no network)
npm start # run the stdio server locally (key needed for calls, not startup)
Publishing
npm publish (from this directory) makes npx appsgolem-mcp work for everyone.
The prepare script builds dist/ automatically on install/publish.