# Transcriptor Mcp

> An MCP server (stdio + HTTP/SSE) that fetches video transcripts/subtitles via yt-dlp, with pagination for large responses. Supports YouTube, Twitter/X, Instagram, TikTok, Twitch, Vimeo, Facebook, Bilibili, VK, Dailymotion. Whisper fallback — transcribes audio when subtitles are unavailable (local or OpenAI API). Works with Cursor and other MCP host

- **Type:** MCP server
- **Install:** `agentstack add mcp-samson-art-transcriptor-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [samson-art](https://agentstack.voostack.com/s/samson-art)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [samson-art](https://github.com/samson-art)
- **Source:** https://github.com/samson-art/transcriptor-mcp

## Install

```sh
agentstack add mcp-samson-art-transcriptor-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Transcriptor MCP

[](https://hub.docker.com/r/artsamsonov/transcriptor-mcp)
[](https://github.com/samson-art/transcriptor-mcp/blob/main/LICENSE)

An MCP server (stdio; remote HTTP/SSE via [mcp-proxy](https://github.com/sparfenyuk/mcp-proxy)) that fetches video transcripts/subtitles via `yt-dlp`, with pagination for large responses. Supports YouTube, Twitter/X, Instagram, TikTok, Twitch, Vimeo, Facebook, Bilibili, VK, Dailymotion, Reddit. **Whisper fallback** — transcribes audio when subtitles are unavailable (local or OpenAI API). Works with Cursor and other MCP hosts.

## Overview

This repository primarily ships a **stdio MCP server** (`node dist/mcp.js`):

- **stdio**: for local usage (e.g., Cursor running a local command).
- **Remote HTTP/SSE**: expose stdio through **[mcp-proxy](https://github.com/sparfenyuk/mcp-proxy)** (e.g. VPS + Tailscale); see [MCP quick start](#mcp-quick-start) and `docker-compose.example.yml`.

It also includes an optional **REST API** (Fastify), but MCP is the primary focus.

## Supported platforms

Unlike YouTube-only tools, Transcriptor MCP works across **11 major video platforms**:

YouTube · Twitter/X · Instagram · TikTok · Twitch · Vimeo · Facebook · Bilibili · VK · Dailymotion · Reddit

All URL-based tools (`get_transcript`, `get_raw_subtitles`, `get_available_subtitles`, `get_video_info`, `get_video_chapters`, `get_playlist_transcripts`) accept video URLs from any supported platform. The `search_videos` tool is YouTube-specific (yt-dlp ytsearch).

## When to use Transcriptor MCP

Transcriptor MCP is the best choice when you need **transcripts and metadata** for AI, summarization, or content analysis — without downloading video or audio files:

- **Transcripts and subtitles** — cleaned text or raw SRT/VTT; multi-language; **Whisper fallback** when subtitles are unavailable (local or OpenAI).
- **Multi-platform** — YouTube, Twitter/X, Instagram, TikTok, Twitch, Vimeo, Facebook, Bilibili, VK, Dailymotion, Reddit.
- **Remote and production** — stdio + mcp-proxy for HTTP/SSE, optional auth at a reverse proxy, Redis cache, Prometheus metrics on the REST API.
- **No media downloads** — we focus on text and metadata only. For downloading videos or audio.

Use the sections in this README for setup, tools, and deployment patterns.

## How to connect

Choose one of these two main paths:

### 1) Local MCP (Docker)

Best when you want a fast local setup without Node on host.

```bash
docker run --rm -i artsamsonov/transcriptor-mcp:latest
```

Cursor MCP config:

```json
{
  "mcpServers": {
    "transcriptor": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "artsamsonov/transcriptor-mcp:latest"]
    }
  }
}
```

Detailed local + self-hosted HTTP/SSE instructions are in [How to connect](#how-to-connect) and [MCP quick start](#mcp-quick-start).

### 2) Remote MCP via HTTP/SSE (mcp-proxy)

Expose stdio over HTTP/SSE with [mcp-proxy](https://github.com/sparfenyuk/mcp-proxy). See [docker-compose.example.yml](docker-compose.example.yml) for a full stack (optional REST API + MCP).

After you deploy mcp-proxy (and optionally TLS or Bearer auth at a reverse proxy), point MCP clients at your endpoint, for example:

```text
https://your-host.example/mcp
```

Streamable HTTP uses `POST /mcp`; SSE uses `GET /sse`. The MCP Node process does not validate Bearer tokens — configure auth on the proxy in front of mcp-proxy if needed.

## Features

- **Multi-platform** — YouTube, Reddit, Twitter/X, Instagram, TikTok, Twitch, Vimeo, Facebook, Bilibili, VK, Dailymotion.
- **Transcripts + raw subtitles**: cleaned text or raw SRT/VTT.
- **Language support**: official subtitles with auto-generated fallback.
- **Video metadata**: extended info (title, channel, tags, thumbnails, etc.) and chapter markers.
- **Pagination**: safe for large transcripts.
- **Whisper fallback**: when subtitles are unavailable, transcribes video audio via Whisper (local self-hosted or OpenAI API); configurable via environment variables.
- **Optional Redis cache**: cache subtitles and metadata to reduce yt-dlp calls; configurable via environment variables.
- **Docker-first**: ready for local + remote deployment.
- **Production-friendly HTTP**: optional auth + allowlists for the REST API; remote MCP uses **stdio + mcp-proxy** and is usually fronted by your own reverse proxy for Bearer/TLS.
- **Prometheus**: metrics on the REST API (`GET /metrics`); MCP tool counters (`mcp_*`) are updated inside the MCP Node process but this repo no longer exposes `GET /metrics` on the MCP image.

## Self-configurable: Whisper & caching

You can enable these features independently; both are **off by default**.

- **Whisper fallback** — When native subtitles are unavailable, transcribe video audio via Whisper (local self-hosted or OpenAI API). Configure via `WHISPER_MODE`, `WHISPER_BASE_URL`, `WHISPER_API_KEY`, etc.
- **Redis caching** — Cache subtitles and metadata to reduce yt-dlp calls. Configure via `CACHE_MODE=redis` and `CACHE_REDIS_URL`.

## MCP quick start

For full setup options (local Docker and self-hosted HTTP/SSE with `mcp-proxy`), use:

- [How to connect](#how-to-connect)
- [MCP Server (stdio)](#mcp-server-stdio)

## MCP tools

| Tool                       | Purpose                          |
| -------------------------- | -------------------------------- |
| `get_transcript`           | Cleaned plain text (first chunk) |
| `get_raw_subtitles`        | Raw SRT/VTT, paginated           |
| `get_available_subtitles`  | List official/auto languages     |
| `get_video_info`           | Extended metadata                |
| `get_video_chapters`       | Chapter markers                  |
| `get_playlist_transcripts` | Batch transcripts from playlist  |
| `search_videos`            | YouTube search                   |

### MCP tool reference

All URL-based tools share the same base input:

- `url` (string, required) – Video URL from a supported platform or YouTube video ID. Supported: YouTube, Twitter/X, Instagram, TikTok, Twitch, Vimeo, Facebook, Bilibili, VK, Dailymotion, Reddit.

`get_raw_subtitles` supports pagination; `get_transcript` returns the first chunk only (no pagination input). Pagination parameters for `get_raw_subtitles`:

- `response_limit` (number, optional) – max characters per response, default `50000`, min `1000`, max `200000`.
- `next_cursor` (string, optional) – opaque offset returned from the previous page; pass it to fetch the next chunk.

Each tool returns:

- `content` – human-readable text (for MCP chat UIs).
- `structuredContent` – strongly typed JSON payload you can consume from automations or code.

#### `get_transcript`

**Purpose**: Fetch cleaned subtitles as plain text (no timestamps, HTML, or speaker metadata).

**Input**: Only `url` (video URL or ID). Type and language are auto-discovered; the tool returns the first chunk with default size (no pagination parameters).

**Structured response**:

- `videoId` – resolved YouTube ID.
- `type`, `lang` – effective subtitle type and language.
- `text` – current text chunk.
- `is_truncated` – `true` if more text is available.
- `total_length` – total length of the full transcript.
- `start_offset`, `end_offset` – character offsets of this chunk.
- `next_cursor` – present in response when truncated (omitted on the last page). Not accepted as input for this tool.

#### `get_raw_subtitles`

**Purpose**: Fetch raw subtitle file content (SRT or VTT) with pagination support.

**Extra input fields**:

- `type` – `"official"` or `"auto"`, optional.
- `lang` – subtitle language code, optional.
- `response_limit`, `next_cursor` – pagination (optional).

**Structured response**:

- `videoId`, `type`, `lang` – same semantics as above.
- `format` – `"srt"` or `"vtt"` (auto-detected from content).
- `content` – raw subtitle text for this page.
- `is_truncated`, `total_length`, `start_offset`, `end_offset`, `next_cursor` – same pagination fields as `get_transcript`.

#### `get_available_subtitles`

**Purpose**: Inspect which languages are available for a video, split into official vs auto-generated tracks.

**Input**:

- `url` – YouTube URL or video ID.

**Structured response**:

- `videoId` – resolved YouTube ID.
- `official` – sorted list of language codes with official subtitles.
- `auto` – sorted list of language codes with auto-generated subtitles.

This is useful to first discover languages and then pick `type`/`lang` for `get_raw_subtitles` (or other tools).

#### `get_video_info`

**Purpose**: Fetch extended metadata about a video (based on yt-dlp JSON output).

**Input**:

- `url` – YouTube URL or video ID.

**Structured response (key fields)**:

- `videoId` – resolved YouTube ID.
- `title`, `description`.
- `uploader`, `uploaderId`.
- `channel`, `channelId`, `channelUrl`.
- `duration` – in seconds.
- `uploadDate` – `YYYYMMDD` string if available.
- `webpageUrl`.
- `viewCount`, `likeCount`, `commentCount`.
- `tags`, `categories`.
- `liveStatus`, `isLive`, `wasLive`, `availability`.
- `thumbnail` – primary thumbnail URL.
- `thumbnails` – list of thumbnail variants `{ url, width?, height?, id? }`.

See `src/mcp-core.ts` and `src/youtube.ts` for the full JSON schema used by the MCP SDK.

#### `get_video_chapters`

**Purpose**: Get chapter markers extracted by yt-dlp.

**Input**:

- `url` – YouTube URL or video ID.

**Structured response**:

- `videoId` – resolved YouTube ID.
- `chapters` – array of `{ startTime: number; endTime: number; title: string }`.

If the video has no chapters, `chapters` is an empty array; if yt-dlp cannot fetch chapter data at all, the tool returns an MCP error instead of structured chapters.

#### `get_playlist_transcripts`

**Purpose**: Fetch cleaned transcripts for multiple videos from a playlist in one call.

**Input**:

- `url` (string, required) – Playlist URL or watch URL with `list=` (e.g. `https://www.youtube.com/playlist?list=XXX`).
- `type` – `"official"` or `"auto"`, optional.
- `lang` – Subtitle language code, optional.
- `format` – Subtitle format (`srt`, `vtt`, `ass`, `lrc`), optional.
- `playlistItems` – yt-dlp `-I` spec (e.g. `1:5`, `1,3,7`, `-1`), optional.
- `maxItems` – Max videos to process, optional.

**Structured response**:

- `results` – array of `{ videoId, text }` for each video in the playlist.

#### `search_videos`

**Purpose**: Search videos on YouTube via yt-dlp (ytsearch). Returns a list of videos with metadata.

**Input**:

- `query` (string, required) – Search query.
- `limit` (number, optional) – Max results (default 10, max 50).
- `offset` (number, optional) – Skip first N results (pagination).
- `uploadDateFilter` (string, optional) – Filter by upload date: `hour`, `today`, `week`, `month`, or `year`.
- `response_format` (string, optional) – Human-readable format: `json` (default) or `markdown`.

**Structured response**:

- `results` – array of `{ videoId, title, url, duration, uploader, viewCount, thumbnail }`.

## Requirements

- **Docker** (recommended for production)
- **Node.js** >= 20.0.0 (for local development)
- **yt-dlp** (included in Docker image)

## REST API (optional)

The repository also ships an HTTP API (Fastify).

#### Quick Docker usage

- Build the image:
  ```bash
  docker build -t transcriptor-mcp-api -f Dockerfile --target api .
  ```
- Run on the default port:
  ```bash
  docker run -p 3000:3000 transcriptor-mcp-api
  ```

For a more complete REST quick start (including docker-compose and local Node.js),
use [REST API (optional)](#rest-api-optional) and [API Documentation](#api-documentation).

#### Swagger / OpenAPI

Once the REST API is running, interactive API docs are available at:

```text
http://localhost:3000/docs
```

If you change `PORT` / `HOST`, adjust the URL accordingly, e.g. `http://:/docs`.

#### Troubleshooting: restricted / sign-in required videos

If yt-dlp is blocked by age gate, sign-in, or region restrictions, you will likely need
an authenticated `cookies.txt` file and the `COOKIES_FILE_PATH` environment variable.

The root of this repository includes a sample `[cookies.example.txt](cookies.example.txt)`
showing the expected Netscape cookies format. For a full guide on:

- exporting real cookies
- wiring them into Docker / docker-compose / local Node.js
- and keeping them secure

keep credentials local and use `COOKIES_FILE_PATH` with a non-committed cookie file.

#### Run in background

```bash
docker run -d -p 3000:3000 --name transcriptor transcriptor-mcp-api
```

### E2E smoke tests (REST API + MCP, Docker)

Before publishing Docker images, you can run a small **e2e smoke test** that:

- Starts a REST API container and checks Swagger + `POST /subtitles` with a stable YouTube video
- Optionally starts an MCP container and checks **MCP stdio** (initialize over stdin/stdout), **streamable HTTP** (`POST /mcp` with initialize), and **SSE** (`GET /sse`) against **mcp-proxy** + stdio (same stack as [docker-compose.example.yml](docker-compose.example.yml))

Run the smoke test (requires built images):

```bash
npm run build
docker build -t artsamsonov/transcriptor-mcp-api:latest -f Dockerfile --target api .
docker build -t artsamsonov/transcriptor-mcp:latest -f Dockerfile --target mcp .
npm run test:e2e:api
```

**Environment variables:**

| Variable                           | Default                                       | Description                                                                             |
| ---------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------- |
| `SMOKE_IMAGE_API`                  | —                                             | Full API image reference (overrides name/tag).                                          |
| `DOCKER_API_IMAGE` / `TAG`         | `artsamsonov/transcriptor-mcp-api`, `latest`  | API image name and tag.                                                                 |
| `SMOKE_API_URL` / `SMOKE_API_PORT` | `http://127.0.0.1:33000`, `33000`             | API base URL and port.                                                                  |
| `SMOKE_VIDEO_URL`                  | `https://www.youtube.com/watch?v=dQw4w9WgXcQ` | Video used for `/subtitles` check.                                                      |
| `SMOKE_SKIP_MCP`                   | —                                             | Set to `1` (or `true`/`yes`) to skip MCP checks.                                        |
| `SMOKE_MCP_IMAGE`                  | —                                             | Full MCP image reference (overrides name/tag).                                          |
| `DOCKER_MCP_IMAGE` / `TAG`         | `artsamsonov/transcriptor-mcp`, `latest`      | MCP image name and tag.                                                                 |
| `SMOKE_MCP_URL` / `SMOKE_MCP_PORT` | `http://127.0.0.1:4200`, `4200`               | MCP base URL and port.                                                                  |
| `SMOKE_MCP_AUTH_TOKEN`             | —                                             | If set, sent as `Authorization: Bearer` on MCP HTTP requests (for smoke against an edge that requires Bearer; the default smoke stack does not enforce it). |

Example: skip MCP and use a custom video:

```bash
SMOKE_SKIP_MCP=1 SMOKE_VIDEO_URL="https://www.youtube.com/watch?v=YOUR_ID" npm run test:e2e:api
```

#### View logs

```bash
docker logs -f transcriptor
```

#### Stop the container

```bash
docker stop transcriptor
docker rm transcriptor
```

## API Documentation

For detailed REST API endpoint documentation (request/response schemas, examples, etc.),
use the built-in Swagger UI at:

```text
http://localhost:3000/docs
```

or use [REST API (optional)](#rest-api-optional).

## MCP Server (stdio)

The MCP server runs on stdio (`dist/mcp.js`) and can be used via:

- local Docker (`docker run --rm -i artsamsonov/transcriptor-mcp:latest`)
- local Node (`node dist/mcp.js`)
- remote HTTP/SSE

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [samson-art](https://github.com/samson-art)
- **Source:** [samson-art/transcriptor-mcp](https://github.com/samson-art/transcriptor-mcp)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-samson-art-transcriptor-mcp
- Seller: https://agentstack.voostack.com/s/samson-art
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
