# Weftly (remote · api.weftly.ai)

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

- Trust score: 62/100 (medium)
- Change this week: +2
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `api.weftly.ai`: 62/100 (this document), [markdown](https://verifymcp.io/servers/ai-weftly-weftly/api.md), [page](https://verifymcp.io/servers/ai-weftly-weftly/api)

## Channel facts

- Endpoint: `https://api.weftly.ai/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `0.25.4`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Endpoint Security**: 46/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation not fully verified: no authorisation is required to call this server, and 11 tool(s) never declared a destructiveHint. The MCP spec treats an absent hint as destructive by default, so we cannot call this surface safe.
  - HTTPS check failed: the endpoint is reachable over plaintext HTTP.
  - HSTS check failed: the Strict-Transport-Security header is absent.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 72/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 5733 tokens (~441/item across 13 items; 11 tools + 2 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.
  - Supports UI / widget rendering.

## Install

### Claude

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

### Codex

```toml
[mcp_servers.ai-weftly-weftly]
url = "https://api.weftly.ai/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ai-weftly-weftly": {
      "type": "remote",
      "url": "https://api.weftly.ai/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add ai-weftly-weftly --url https://api.weftly.ai/mcp --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  ai-weftly-weftly:
    url: "https://api.weftly.ai/mcp"
```

### Other

```json
{
  "mcpServers": {
    "ai-weftly-weftly": {
      "type": "http",
      "url": "https://api.weftly.ai/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 62, +1)

No change was recorded against any check on this day. Stability & Change Management went from 23 to 27. That category is still filling its 30-day observation window: 7 days of observed history at the previous scan, 8 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-08-01 (score 61, +1)

No change was recorded against any check on this day. Stability & Change Management went from 17 to 20. That category is still filling its 30-day observation window: 5 days of observed history at the previous scan, 6 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-31 (score 60, −2)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-30 (score 62, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-29 (score 62, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-28 (score 61, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 60, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 60)

First indexed and scored.

## MCP tools (11)

### `transcribe` (~467 tokens)

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` 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). 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.

Input parameters:

- `filename` (string): Filename with extension (e.g. "podcast.mp3"). Required on the first call — used to infer media type (audio vs video) and label outputs. Supported extensions: mp3, wav, m4a, ogg, flac, mp4, mov, webm,…
- `job_id` (string): Job ID returned from a previous call. Include along with payment_credential to confirm payment and receive the presigned upload URL. Also include alone to recover the current challenge/state if the o…
- `payment_credential` (string): MPP payment credential (full Authorization header value, e.g. "Payment eyJ...") obtained by paying the challenge returned from the first call. Include with job_id to verify payment and receive the up…

### `summarize` (~498 tokens)

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` 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). 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.

Input parameters:

- `filename` (string): Filename with extension (e.g. "podcast.mp3"). Required on the first call — used to infer media type (audio vs video) and label outputs. Supported extensions: mp3, wav, m4a, ogg, flac, mp4, mov, webm,…
- `job_id` (string): Job ID returned from a previous call. Include along with payment_credential to confirm payment and receive the presigned upload URL. Also include alone to recover the current challenge/state if the o…
- `payment_credential` (string): MPP payment credential (full Authorization header value, e.g. "Payment eyJ...") obtained by paying the challenge returned from the first call. Include with job_id to verify payment and receive the up…

### `find_clips` (~730 tokens)

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 extract_clip. 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 `extract_clip` or `extract_vertical_clip` as their `source_job_id` — within those 72h they cut directly from the stored source: no re-upload, no re-transcribe, just $0.50 per cut. Pass the same `source_job_id` to as many extract 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.

Input parameters:

- `filename` (string): Filename with extension (e.g. "podcast.mp3"). Required on the first call — used to infer media type (audio vs video) and label outputs. Supported extensions: mp3, wav, m4a, ogg, flac, mp4, mov, webm,…
- `job_id` (string): Job ID returned from a previous call. Include along with payment_credential to confirm payment and receive the presigned upload URL. Also include alone to recover the current challenge/state if the o…
- `payment_credential` (string): MPP payment credential (full Authorization header value, e.g. "Payment eyJ...") obtained by paying the challenge returned from the first call. Include with job_id to verify payment and receive the up…
- `query` (string): Optional. Switches the analyzer from "best clips" discovery mode to query mode — finds segments matching this content (e.g., "they discuss pricing", "the part about hiring"). Same output shape either…

### `extract_clip` (~702 tokens)

Cut and assemble a clip 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. Pass one segment for a simple cut, or multiple non-contiguous segments to compose a single mp4 highlight reel — same flat $0.50 either way. Two-call flow: (1) call with `source_job_id` + `segments` (ordered array of `{start, end, label?}` in source seconds, total duration capped at 30 minutes) to receive {job_id, payment_challenge}; (2) pay via MPP and call with `job_id` + `payment_credential` to start processing. No upload step. Poll get_job_status(job_id) for completion; outputs are role `clip-video` (the assembled .mp4, frame-accurate boundaries with 15ms audio fades at segment joins; audio loudness-normalized to -14 LUFS / -1.5 dBTP for clean, consistent playback) and — when `include_transcript: true` (default) — roles `clip-srt` + `clip-words` (transcripts stitched and time-shifted to match the assembled video). Set `include_transcript: false` to skip transcript outputs. 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 extract_clip calls against one parent are independent paid jobs. Failed jobs auto-refund.

Input parameters:

- `include_transcript` (boolean): Default true. When true, the pipeline writes clip-srt + clip-words outputs stitched to match the assembled video. Set false to skip and just receive the .mp4.
- `job_id` (string): Job ID returned from a previous extract_clip call. Include along with payment_credential to confirm payment and trigger processing. Also include alone to recover the current state.
- `payment_credential` (string): MPP payment credential (full Authorization header value, e.g. "Payment eyJ..."). extract_clip accepts Tempo USDC and Stripe SPT — see the challenge's WWW-Authenticate header or /.well-known/mpp.json…
- `segments` (array): Ordered array of source-relative segments to cut and concatenate into the output. Single segment for a simple cut; multiple segments compose a single mp4 from non-contiguous moments — same flat $0.50…
- `source_job_id` (string): Job ID of any prior video job (find_clips, summarize, or video transcribe). Possessing this id is the capability — extract_clip is not session-bound, so a user can come back from a different session…
- `title` (string): Optional title for the assembled clip. Surfaces in get_job_status and download filenames; doesn't affect the cut itself.

### `extract_vertical_clip` (~1336 tokens)

Cut a 9:16 vertical clip from any prior video job (find_clips, summarize, or video transcribe), suitable for direct upload to TikTok, Instagram Reels, or YouTube Shorts. Default output is 1080×1920 H.264 / AAC `.mp4` with center-cropped framing; audio loudness-normalized to -14 LUFS / -1.5 dBTP for short-form social. Single-segment only; clip duration must be between 1 and 90 seconds (Instagram Reels max). Operates on a parent job — possessing the parent `source_job_id` is the capability, no upload step. Two-call flow: (1) call with `source_job_id` + `start` + `end` (in source seconds) to receive {job_id, payment_challenge}; (2) pay via MPP and call with `job_id` + `payment_credential` to start processing. Poll get_job_status(job_id) for completion; output is role `clip-vertical-video` (the `.mp4`). Flat price: $0.50 per clip. Payment: pay by credit card via the Stripe Checkout link (open the returned `payment_url` in any browser) or Tempo USDC via mppx. Optional `profile` parameter selects the encoding profile (default `tiktok-primary`). Allowed values: `tiktok-primary` (1080×1920, fast preset, CRF 22), `tiktok-primary-720p` (720×1280, CBR 3 Mbps — half-resolution mobile-optimized, ~40% faster wall time), `instagram-reels` (1080×1920, slow preset, CBR 4 Mbps), `instagram-stories` (same encode shape as instagram-reels). All four profiles loudness-normalize identically. Optional `subject` parameter controls reframing (default `center`, preserves today's behavior): `auto` locks onto the longest-tracked face from the parent's subjects-sidecar (or runs inline detection if the parent has none); `subject_id` (with `subject_id` param naming a face_N from the sidecar) locks onto a specific subject; `follow` switches crop between active speakers across the clip using the sidecar's active_speaker_timeline; `manual` accepts caller-supplied framing via `subject_box: {x, y, w, h}` (source pixels) or `subject_x_offset` (direct crop x). Sidecar shape at /.well-known/weftly-subjec…

Input parameters:

- `end` (number): Source-relative end time in seconds (must be > start, and end - start ∈ [1, 90]). Required on the first call.
- `job_id` (string): Job ID returned from a previous extract_vertical_clip call. Include along with payment_credential to confirm payment and trigger processing. Also include alone to recover the current state.
- `payment_credential` (string): MPP payment credential (full Authorization header value, e.g. "Payment eyJ..."). extract_vertical_clip accepts Tempo USDC and Stripe SPT — see the challenge's WWW-Authenticate header or /.well-known/…
- `profile` (string): Optional encoding profile. Default: tiktok-primary (1080×1920 H.264 fast preset, CRF 22, 6 Mbps cap). tiktok-primary-720p: 720×1280, CBR 3 Mbps — half-resolution mobile-optimized, ~40% faster wall ti…
- `source_job_id` (string): Job ID of any prior video job (find_clips, summarize, or video transcribe). Possessing this id is the capability — extract_vertical_clip is not session-bound, so a user can come back from a different…
- `start` (number): Source-relative start time in seconds. Required on the first call.
- `subject` (string): Optional reframing strategy. Default: "center" (hardcoded center crop, today's behavior). "auto": lock onto the longest-tracked face from the parent find_clips job's subjects-sidecar (or run inline d…
- `subject_box` (object): For subject="manual" — bounding box of the subject in source pixels. Crop centers on the box center.
- `subject_id` (string): Required when subject="subject_id". Subject id from the parent's subjects-sidecar (e.g. "face_0").
- `subject_x_offset` (number): For subject="manual" — direct crop x-offset in source pixels (alternative to subject_box).
- `t_ref` (number): For subject="manual" with subject_box — source-seconds timestamp the box applies to. Informational in v1.
- `title` (string): Optional title for the assembled clip. Surfaces in get_job_status and download filenames; doesn't affect the cut itself.

### `complete_upload` (~89 tokens)

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.

Input parameters:

- `job_id` (string, required): The job_id returned from a previous transcribe or summarize call.

### `get_job_status` (~437 tokens)

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) 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). 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.

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").

Input parameters:

- `format` (string): When the job is completed, return the transcript inline in this format instead of only a download URL. Options: "srt" (SubRip with timestamps), "txt" (plain text — no timestamps), "vtt" (WebVTT), "js…
- `job_id` (string, required): The job_id returned from a previous transcribe or summarize call.

### `mpp_smoke_test` (~256 tokens)

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.

Input parameters:

- `payment_credential` (string): MPP payment credential (full Authorization header value, e.g. "Payment eyJ...") obtained by paying the challenge returned from the first call. Include to verify payment and receive {paid: true}. Omit…

### `publish_to_youtube` (~265 tokens)

Publish an existing video from a transcribe or summarize job to YouTube. Creates a paid publish job (flat $1.75 price) and stores the OAuth token. Captions are auto-generated from the session transcript if available. Workflow: create_job → pay → trigger_youtube_publish → poll get_youtube_publish_status. Requires a YouTube OAuth2 access token obtained independently via Google OAuth (scope: youtube.upload).

Input parameters:

- `access_token` (string, required): YouTube OAuth2 access token — the caller is responsible for obtaining this via Google OAuth
- `description` (string): YouTube video description (max 5000 characters)
- `refresh_token` (string): YouTube OAuth2 refresh token — if provided, the Workflow will refresh the access token automatically before uploading
- `session_token` (string, required): Session token from create_session, create_transcript, or create_summary
- `source_job_id` (string, required): Job ID of an existing transcribe or summarize job in this session whose video to publish. The Workflow will auto-generate captions if no transcript is found.
- `title` (string, required): YouTube video title (max 100 characters)
- `visibility` (string, required): YouTube video visibility: "private" (default), "unlisted", or "public"

### `trigger_youtube_publish` (~84 tokens)

Start the YouTube upload after payment is confirmed. Call this after publish_to_youtube once payment_status is "paid". Returns immediately — the upload runs as a durable Workflow in the background. Poll get_youtube_publish_status to track progress.

Input parameters:

- `job_id` (string, required): Job ID returned by publish_to_youtube
- `session_token` (string, required): Session token

### `get_youtube_publish_status` (~87 tokens)

Check the status of a YouTube publish job. Poll periodically after trigger_youtube_publish — the upload takes 1-10 minutes depending on video size. Returns status (pending, publishing, completed, failed) and the youtube_video_url once complete.

Input parameters:

- `job_id` (string, required): Job ID returned by publish_to_youtube
- `session_token` (string, required): Session token

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/ai-weftly-weftly/api#diagnostics

## Score history

- 2026-08-03: 62
- 2026-08-02: 61
- 2026-08-01: 61
- 2026-07-31: 60
- 2026-07-30: 62
- 2026-07-29: 62
- 2026-07-28: 61
- 2026-07-27: 60
- 2026-07-26: 60

## Links

- Remote endpoint: https://api.weftly.ai/mcp
- Repository: https://github.com/woven-record-media/weftly-monorepo
- Website: https://weftly.ai/
- Changelog RSS feed: https://verifymcp.io/servers/ai-weftly-weftly/api/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/ai-weftly-weftly/api/changelog.json
- HTML version of this page: https://verifymcp.io/servers/ai-weftly-weftly/api
