Skip to content

Weftly

by weftly.ai · remote · no sign-in to list tools · v0.35.3 · published by ai.weftly

Find & cut horizontal and vertical video clips (Shorts/Reels), transcribe & summarize. Pay per job.

Changes · 6

9 tools: 6 change things and 3 only read.

Scanned Oct 21, 2026

9 checks matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http weftly https://api.weftly.ai/mcp

Findings

Matches of fixed checks, with the text they matched.

9 info
  • The input schema at properties.payment_credential.description mentions "credential".

    Matched text

    inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

    What this check looks for
  • The input schema at properties.payment_credential.description mentions "credential".

    Matched text

    inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

    What this check looks for
  • The input schema at properties.payment_credential.description mentions "credential".

    Matched text

    inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

    What this check looks for
  • The description is 2,013 characters long, over the 2,000 this check looks for.

    Matched text

    description ends: "...ngs. Retrying with `job_id` alone returns current state. Failed jobs auto-refund."

    What this check looks for
  • The description is 3,831 characters long, over the 2,000 this check looks for.

    Matched text

    description ends: "...Retrying with `job_id` alone recovers the current state. Failed jobs auto-refund."

    What this check looks for
  • The description is 2,025 characters long, over the 2,000 this check looks for.

    Matched text

    description ends: "...errors to the user from the response that returned them. Failed jobs auto-refund."

    What this check looks for
Show 3 more findings
  • The description is 2,404 characters long, over the 2,000 this check looks for.

    Matched text

    description ends: "...allenge (status "awaiting_payment") or the upload URL (status "awaiting_upload")."

    What this check looks for
  • The input schema at properties.payment_credential.description mentions "credential".

    Matched text

    inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

    What this check looks for
  • The description is 2,641 characters long, over the 2,000 this check looks for.

    Matched text

    description ends: "...se` to render them without. `orientation: "horizontal"` clips never get captions."

    What this check looks for

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

9 tools

Changes things 6Claude Code: ask
  • clips_from_jobCut one or more clips from any prior video job (find_clips, summarize, or video transcribe).1 finding

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.

    Findings

    • Info

      The description is 3,831 characters long, over the 2,000 this check looks for.

      Matched text

      description ends: "...Retrying with `job_id` alone recovers the current state. Failed jobs auto-refund."

      What this check looks for
    Description, as the server wrote it
    Cut one or more clips from any prior video job (find_clips, summarize, or video transcribe). Operates on a parent job — possessing the parent `source_job_id` is the capability, no upload step. Contrast with `clips_from_video`, which takes a local `filename` and uploads a video that has never been in Weftly before; use this tool whenever a video job already exists. Two choices are required on every new job, with no default — if the customer's intent is genuinely ambiguous, ask rather than guess: `orientation` (`horizontal` keeps the source framing; `vertical` crops to 9:16 for TikTok/Reels/Shorts) and `output` (`files` delivers one file per clip; `reel` concatenates every clip into a single file). Two-call flow: (1) call with `source_job_id` + `clips` (1+ objects `{start, end, title?}` in source seconds) + `orientation` + `output` to receive {job_id, payment_challenge}; (2) pay via MPP and call again with `job_id` + `payment_credential` to start processing. Price: `output: "reel"` bills a flat $0.50 regardless of segment count; `output: "files"` bills N × $0.50 for N clips, charged once for the whole batch (Stripe quantity). See /.well-known/mpp.json for the Tempo USDC rate. `output: "files"` caps a batch at 5 clips; `output: "reel"` concatenates every clip into one file, capped at 30 minutes of total output for `orientation: "horizontal"` or, for `orientation: "vertical"`, the selected profile's cap: 240s for `tiktok-primary` and `tiktok-primary-720p`, 180s for `instagram-reels`, 60s for `instagram-stories`. The 240s ceiling is an encode limit (crop+scale cost per segment against the container's own timeout), not a platform rule; the shorter profile caps are the destination's own limit. `orientation: "vertical"` accepts `profile` (default `tiktok-primary`; also `tiktok-primary-720p`, `instagram-reels`, `instagram-stories`) and `subject` (`center`/`auto`/`follow`, default `follow` — switches crop between active speakers across clip and segment boundaries, the mode that makes multi-speaker interview clips usable; `manual`/`subject_id` need per-clip data this tool cannot supply — use the REST API's `extract_vertical_clip` job type directly for those); both are rejected for `orientation: "horizontal"`, which keeps the source framing and has no crop to aim. `include_transcript` (default true) applies only to `output: "reel"` — mirrors extract_clip's clipped SRT + word-level transcript outputs — and is rejected for `output: "files"`. Outputs: `output: "files"` writes roles `clip-1-video` through `clip-N-video` plus a `clips-manifest` (JSON) recording each clip's timing, output role, and any per-clip failure — a batch delivering fewer than N clips is not refunded, only one delivering zero is; `output: "reel"` writes role `clip-video` (frame-accurate boundaries, 15ms audio fades at segment joins) plus, when `include_transcript` is true, roles `clip-srt` + `clip-words`. Every output is audio loudness-normalized to -14 LUFS / -1.5 dBTP; vertical output is additionally cropped to the selected profile's dimensions (1080×1920 by default) and burned with word-level captions by default (center-third placement, uppercase, one short line per card) — pass `captions: false` to render vertical output without them; horizontal output never gets captions. Payment: pay by credit card via the Stripe Checkout link (open the returned `payment_url` in any browser) or Tempo USDC via mppx; the challenge's WWW-Authenticate header and /.well-known/mpp.json are authoritative for which methods are offered. Source must still be in storage (72h TTL for find_clips parents, 24h elsewhere — check `expires_at` from get_job_status on the parent). Multiple clips_from_job calls against one parent are independent paid jobs. Retrying with `job_id` alone recovers the current state. Failed jobs auto-refund.
  • complete_uploadConfirm that the file has been uploaded (via HTTP PUT to the upload_url from transcribe or summarize) and start processing.No findings

    Why it is in this group

    • The name "complete_upload" says "upload": a word for a change.
    Description, as the server wrote it
    Confirm that the file has been uploaded (via HTTP PUT to the upload_url from transcribe or summarize) and start processing. Verifies that the file is present in storage and that the job has been paid. Returns status "processing". Poll get_job_status to track progress and retrieve download URLs when done.
  • edit_from_transcriptCut and re-assemble a video from an edited copy of its own word-level transcript — the text-editing counterpart to clips_from_job's timestamp-based cutting.1 finding

    Why it is in this group

    • The name "edit_from_transcript" says "edit": a word for a change.

    Findings

    • Info

      The description is 2,025 characters long, over the 2,000 this check looks for.

      Matched text

      description ends: "...errors to the user from the response that returned them. Failed jobs auto-refund."

      What this check looks for
    Description, as the server wrote it
    Cut and re-assemble a video from an edited copy of its own word-level transcript — the text-editing counterpart to clips_from_job's timestamp-based cutting. Operates on a parent job (find_clips, summarize, or video transcribe) that has a word-level transcript; possessing the parent `source_job_id` is the capability, no upload step. Get the editable text first via get_job_status(job_id, format: "edit") or the download route — one `[NNNN]`-marked line per sentence — then edit it in any text editor: delete words or whole lines, move whole lines, but do not add or change a word (a marker used twice, or any added/changed word, invalidates the whole edit and is rejected before payment). Two-call flow: (1) call with `source_job_id` + the full edited text as `edited_transcript` (sent inline, max 262144 UTF-8 bytes) + optional `title` to receive {job_id, payment_challenge} — an invalid edit is rejected here, before any charge, with the exact failing lines; (2) pay via MPP (Tempo USDC) or open the Stripe Checkout `payment_url` in a browser, then call again with `job_id` + `payment_credential` to start processing. Flat price: $1.00 — see /.well-known/mpp.json for the Tempo USDC rate. Up to 300 cuts and 60 minutes of output per call; repeated phrases match their first occurrence, left to right. Outputs: role `clip-video` (the edited video), plus `clip-srt` and `clip-words` re-timed to match the edit. Source must still be in storage (72h TTL for find_clips parents, 24h elsewhere — check `expires_at` from get_job_status on the parent). Use whenever the edit is easier to describe in text than in timestamps — tightening a clip or a short segment by deleting filler words and tangents, or reordering a handful of sentences; use `extract_clip` (via clips_from_job) instead when you already know the exact start/end seconds you want. Retrying with `job_id` alone recovers the current state. A rejected edit creates no job, so show its errors to the user from the response that returned them. Failed jobs auto-refund.
  • find_clipsSTART HERE for any clip workflow on a video — `find_clips` is the canonical entry point and includes a full transcription as a free byproduct.2 findings

    Why it is in this group

    • The name "find_clips" says "find": a word for reading.
    • The description's first verb is "start": a word for a change.

    Findings

    • Info

      The input schema at properties.payment_credential.description mentions "credential".

      Matched text

      inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

      What this check looks for
    • Info

      The description is 2,013 characters long, over the 2,000 this check looks for.

      Matched text

      description ends: "...ngs. Retrying with `job_id` alone returns current state. Failed jobs auto-refund."

      What this check looks for
    Description, as the server wrote it
    START HERE for any clip workflow on a video — `find_clips` is the canonical entry point and includes a full transcription as a free byproduct. **Do not call `transcribe` first**: doing so doubles the upload, doubles the spend, and produces the same transcript. Identify ranked candidate clips in a video — what to cut for highlights, social, or testimonials. Three-call flow: (1) call with `filename` (and optional `query`) to receive {job_id, payment_challenge}; (2) pay via MPP, then call with `job_id` + `payment_credential` to receive {upload_url} (presigned PUT, 1h expiry); (3) PUT the bytes, then complete_upload(job_id), then poll get_job_status(job_id). On completion, get_job_status returns three outputs: role `clip-candidates` (JSON matching /.well-known/weftly-clips-v1.schema.json — includes `source_job_id` and `source_expires_at`), role `transcript` (SRT, free byproduct), role `transcript-words` (JSON matching /.well-known/weftly-transcript-v2.schema.json, free byproduct). Each candidate carries `transcript_text` — the full text of what's in the clip — so callers can preview content before paying for clips_from_job. Optional `query` parameter switches to query mode (e.g., "they discuss pricing", "the part about hiring") with the same output shape; the `mode` field in clip-candidates.json indicates which mode produced the result. Flat price: $2.00 video — see /.well-known/mpp.json. **Source-reuse contract:** the source video stays in storage for 72h after find_clips completes. Hand the find_clips `job_id` (also returned as `source_job_id` in the candidates JSON) to `clips_from_job` as its `source_job_id` — within those 72h it cuts directly from the stored source: no re-upload, no re-transcribe, just $0.50 per cut (more for a multi-clip `output: "files"` batch). Pass the same `source_job_id` to as many `clips_from_job` calls as you need. Use for interviews, podcasts, sales calls, all-hands recordings. Retrying with `job_id` alone returns current state. Failed jobs auto-refund.
  • mpp_smoke_testSmoke-test the MPP payment plumbing end-to-end via this MCP server, for $0.01 USDC.1 finding

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.

    Findings

    • Info

      The input schema at properties.payment_credential.description mentions "credential".

      Matched text

      inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

      What this check looks for
    Description, as the server wrote it
    Smoke-test the MPP payment plumbing end-to-end via this MCP server, for $0.01 USDC. Two-call flow: (1) call with no arguments to receive an MPP `payment_challenge`; (2) pay via MPP and call again with `payment_credential` set to the resulting Authorization header value (e.g. "Payment eyJ...") to receive {paid: true, timestamp, receipt_ref, payment_method}. Uses the exact same `createPayToAddress` + `createMppHandler` verification path as paid product tools (transcribe, summarize), so a green run here means real paid calls will work too. Stateless — no job is created, no database row written. Use this whenever you want to confirm a wallet, the MCP transport, the worker, and the production payment middleware are all healthy without paying a transcribe price. Cost: $0.01 USDC per attempt.
  • transcribeTranscribe audio or video to text, including per-word timestamps for precise editing.1 finding

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.

    Findings

    • Info

      The input schema at properties.payment_credential.description mentions "credential".

      Matched text

      inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

      What this check looks for
    Description, as the server wrote it
    Transcribe audio or video to text, including per-word timestamps for precise editing. Three-call flow: (1) call with `filename` to receive {job_id, payment_challenge}; (2) pay via MPP, then call with `job_id` + `payment_credential` to receive {upload_url} (presigned PUT, 1h expiry); (3) PUT the bytes, then complete_upload(job_id), then poll get_job_status(job_id). On completion, get_job_status returns two outputs: role `transcript` (SRT) and role `transcript-words` (JSON matching /.well-known/weftly-transcript-v2.schema.json, with segment-level and per-word timestamps). For other formats, pass `format=srt|txt|vtt|json|words|edit` to get_job_status to receive content inline — `txt` and `vtt` are derived from SRT, `json` is v1 (segments only), `words` is v2 (segments + words), `edit` is a plain-text "[NNNN] words..." paragraph list for editing by hand. Flat price: audio $0.50, video $1.00 — see /.well-known/mpp.json for the authoritative table. Use for podcasts, interviews, meetings, lectures, and especially for creating clips, multicamera edits, or edit-video-from-transcript where word boundaries matter. Retrying any call with `job_id` alone returns current state (idempotent). Failed jobs auto-refund.
Only reads 3Claude Code: allow
  • clips_from_videoFind clips in a video AND cut up to 5 of them, under ONE payment.1 finding

    Why it is in this group

    • The description's first verb is "find": a word for reading.

    Findings

    • Info

      The description is 2,641 characters long, over the 2,000 this check looks for.

      Matched text

      description ends: "...se` to render them without. `orientation: "horizontal"` clips never get captions."

      What this check looks for
    Description, as the server wrote it
    Find clips in a video AND cut up to 5 of them, under ONE payment. This is the alternative to calling find_clips and then clips_from_job yourself — prefer it whenever the user wants clips delivered end-to-end from a video they have not yet uploaded. CARD PAYMENT ONLY — this chain authorizes a Stripe hold (up to $4.50) before the final price is known (the total depends on how many clips are found and delivered), a shape MPP push settlement cannot express. A caller with no card-checkout capability (a wallet-only MPP agent) should NOT call this tool — call find_clips then clips_from_job instead, paying per step in USDC. Two-call flow: (1) call with `filename` and `content_type` (video only) — and an optional `query` to switch clip discovery from "best clips" to matching specific content (e.g. "the part about pricing") — to receive {job_id, status: "awaiting_payment", checkout_url}; (2) once the user says they have authorized payment, call again with the SAME `job_id` (no other fields needed) to recover state — this returns the same checkout_url if still unauthorized, or an upload step once the card hold is authorized (the client performs the upload, never you). Retrying with a NEW call instead of the same `job_id` authorizes a SECOND card hold for the same video — always resume with `job_id`, exactly like every other job-creating tool here. The card hold authorizes the worst case (one $2.00 find_clips analysis plus up to 5 × $0.50 clips), not a charge — the customer is charged once, at the end, for exactly what was delivered (fewer clips than the maximum is normal, not a failure). Clips are auto-selected by score and delivered as a `clips-manifest` output alongside the transcript and clip candidates on the same job. Poll with get_job_status(job_id) for the transcript and candidates; the clips themselves land as the job progresses through its chained stages. Set `orientation` to choose the shape: `vertical` (the default) cuts 9:16 clips for TikTok, Reels and Shorts; `horizontal` cuts 16:9 clips for YouTube or a website embed. `horizontal` CUTS the clips and hands them back — it does not upload or publish anything to YouTube; publishing is publish_to_youtube, a separate job the user has to ask for. Pick from what the user says they want the clips FOR, and if that is genuinely ambiguous, ask rather than guessing — the two produce different files at the same price. `orientation: "vertical"` clips are burned with word-level captions by default (center-third placement, uppercase, one short line per card); pass `captions: false` to render them without. `orientation: "horizontal"` clips never get captions.
  • get_job_statusCheck the status of a transcribe or summarize job.1 finding

    Why it is in this group

    • The name "get_job_status" says "get": a word for reading.

    Findings

    • Info

      The description is 2,404 characters long, over the 2,000 this check looks for.

      Matched text

      description ends: "...allenge (status "awaiting_payment") or the upload URL (status "awaiting_upload")."

      What this check looks for
    Description, as the server wrote it
    Check the status of a transcribe or summarize job. Returns the current state and, when completed, an `outputs` array. Each output has either `content` (returned inline) or a presigned, time-limited (1 hour) `download_url`. Small text outputs (e.g. `transcript` SRT, `clip-candidates`, `summary`) come inline as `content`; larger outputs — `transcript-words` JSON for any non-trivial recording, plus video outputs like `clip-video` / `clip-vertical-video` — come as a `download_url` to fetch when needed. Optionally pass `format` (srt, txt, vtt, json, words, edit) to get the transcript content inline in the top-level `transcript` field — `txt` and `vtt` are derived from the stored SRT; `json` is v1 (segments only); `words` is v2 (segments + per-word timestamps matching /.well-known/weftly-transcript-v2.schema.json); `edit` is a plain-text "[NNNN] words..." paragraph list, one line per paragraph, for editing by hand — send the edited text to edit_from_transcript to cut a re-timed video from it. Poll this periodically after calling complete_upload — wait at least 60 seconds between checks. For files under 10 minutes, jobs usually complete within 1-2 minutes. For long files (1hr+), expect 10-30 minutes. Derivative jobs (`extract_clip`, `extract_vertical_clip`, `publish_youtube`, `clips_vertical`, `clips_horizontal`, `edit_from_transcript`) have no upload step and no `awaiting_upload`/`awaiting_complete_upload` states — a paid derivative job reports `processing` once its parent source is confirmed still in storage, or a terminal `source_expired` if the parent source has expired: stop polling, and re-run the parent job named in `source_job_id` to get a fresh source before retrying. `publish_youtube` is the one exception: its upload starts by itself as soon as payment settles, so a paid job goes straight to `publishing`. If it reports `awaiting_trigger` instead, the upload did not start — almost always because the YouTube account is not connected yet; connect it and the publish can be resumed. A completed `publish_youtube` job's `outputs` array carries a `youtube_url`-roled entry with a `url` field pointing straight at the published video, instead of a `download_url`. Also use this to recover from lost state: if the original challenge was lost, call get_job_status(job_id) to retrieve a fresh challenge (status "awaiting_payment") or the upload URL (status "awaiting_upload").
  • summarizeSummarize an audio or video file — returns both a text summary AND the full transcript (with per-word timestamps).Reads private data1 finding

    Why it is in this group

    • The name "summarize" says "summarize": a word for reading.

    What it can reach

    • private-dataThe description's first sentence says "summarize" and "file": it reads files.

    Findings

    • Info

      The input schema at properties.payment_credential.description mentions "credential".

      Matched text

      inputSchema.properties.payment_credential.description: "MPP payment credential (full Authorization header value, e.g...."

      What this check looks for
    Description, as the server wrote it
    Summarize an audio or video file — returns both a text summary AND the full transcript (with per-word timestamps). Do not also call transcribe on the same file. Three-call flow: (1) call with `filename` to receive {job_id, payment_challenge}; (2) pay via MPP, then call with `job_id` + `payment_credential` to receive {upload_url} (presigned PUT, 1h expiry); (3) PUT the bytes, then complete_upload(job_id), then poll get_job_status(job_id). On completion, get_job_status returns three outputs: role `summary` (plain text), role `transcript` (SRT), and role `transcript-words` (JSON matching /.well-known/weftly-transcript-v2.schema.json, with segment-level and per-word timestamps). For other formats, pass `format=srt|txt|vtt|json|words|edit` to get_job_status to receive transcript content inline — `txt` and `vtt` are derived from SRT, `json` is v1 (segments only), `words` is v2 (segments + words), `edit` is a plain-text "[NNNN] words..." paragraph list for editing by hand. Flat price: audio $0.75, video $1.25 — see /.well-known/mpp.json for the authoritative table. Use for meetings, long-form interviews, lectures, and podcast episodes; the `words` output additionally supports creating clips, multicamera edits, or edit-video-from-transcript. Retrying any call with `job_id` alone returns current state (idempotent). Failed jobs auto-refund.

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Exfil surface

Which tools read private data, which read text someone else can write, and which can send data out. One of each is a path a prompt injection can use.

No private-data, untrusted-input, outbound path in this server alone: no tool is tagged untrusted-input or outbound.

Reads private data1
Reads files, mail, messages, databases, secrets, calendars or repositories.
Reads text others write0
Brings in text someone else can write: web pages, inbound email, messages, issues and comments.
Can send data out0
Can carry data to people or systems: it sends, posts or publishes, or takes a recipient, channel or URL.

Other servers in the same agent add their own tools to these paths. Audit your whole setup to see them together.

Remote posture

What anyone on the internet sees at the remote endpoint: an anonymous initialize and tools/list, and the public OAuth metadata.

Looked at Oct 22, 2026, 14:21 UTC, unchanged since Oct 22, 2026. No credentials were sent and no tool was called. What is looked at.

Reachable
yes
HTTP status of an anonymous initialize
200
tools/list served without credentials
yes
Tools that change things, listed without credentials
6
Protocol version
2025-06-18
WWW-Authenticate on 401
not observed
resource_metadata in WWW-Authenticate
none
RFC 9728 protected resource metadata
none
Authorization servers
none
Legacy HTTP+SSE transport
no
Dynamic client registration
not observed
Client ID metadata documents
not observed
  • WarnThe whole server

    The endpoint served tools/list without credentials, and the list has 6 tools that change things (6 write). Whether a call also works without credentials was not tested: tools are never called.

    Matched text

    https://api.weftly.ai/mcp: tools/list returned 9 tools to an anonymous client, including transcribe (write), find_clips (write), clips_from_job (write), edit_from_transcript (write), complete_upload (write) and 1 more

    What this check looks for

Install

Pinned to version 0.35.3. Values in angle brackets are yours to fill in.

claude mcp add --transport http weftly https://api.weftly.ai/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change or a way out, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__weftly__summarize",
      "mcp__weftly__get_job_status",
      "mcp__weftly__clips_from_video"
    ],
    "ask": [
      "mcp__weftly__transcribe",
      "mcp__weftly__find_clips",
      "mcp__weftly__clips_from_job",
      "mcp__weftly__edit_from_transcript",
      "mcp__weftly__complete_upload",
      "mcp__weftly__mpp_smoke_test"
    ],
    "deny": []
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. A read that can send data out (it takes a URL, say) asks first too. It assumes the server is installed as weftly. Review it before you use it.

Capability tags behind 1 rule
  • mcp__weftly__summarize private-data