com.qencode/qencode
Create amazing video experiences with the Qencode API, straight from your AI assistant.
Open source Repository Open in the app JSON README (API)
About
Create amazing video experiences with the Qencode API, straight from your AI assistant.
Details
- Kind
- MCP servers
- Topic
- No topic detected
- Publisher
- com.qencode
- Origin
- official
- Category
- ferramentas
- Transport
- http
- Version
- 1.1.0
- Last push
- 2026-08-12T17:04:08Z
- Repository state
- ativo
- Language
- Python
- License
- MIT
- Added
- 2026-08-29 03:01:20
- Updated
- 2026-08-29 03:01:20
- Origin id
com.qencode/qencode
README
# qencode-mcp
Model Context Protocol (MCP) server for the [Qencode Transcoding API](https://docs.qencode.com/api-reference/transcoding).
Connect any MCP-compatible AI client — Claude, Cursor, ChatGPT, Grok, Gemini — to your Qencode account and let it submit, monitor, and reason about transcoding jobs on your behalf.
## Quick example
Once your client is connected (see [Connect a client](#connect-a-client)), ask your agent in plain English:
> Transcode `https://example.com/input.mp4` as an HLS ladder at 1080/720/540/360. Put it in my R2 bucket `videos/demo/`.
The agent picks the `hls_abr` recipe, fills in the per-rendition encoding params, submits via `start_encode2_raw`, and polls until the job is done.
## Prerequisites
- A **Qencode portal account** with at least one project — sign in at the portal for your environment: <https://portal.qencode.com> (production) or <https://portal-qa.qencode.com> (QA). You select the project during the OAuth consent step.
- An **MCP-compatible client** (Claude, Cursor, ChatGPT, Grok, Gemini, or any custom client).
There are no API keys to copy into client config — authentication is browser-based OAuth.
## How it works
The connector uses standard OAuth 2.1 — no API keys in client config. On first use, your client opens a browser, you sign in to your Qencode portal account, pick a project, and approve the requested scopes. The client stores the token; subsequent calls are silent until the token expires.
**Scopes the client should request at authorize time** (published via Protected Resource Metadata):
| Scope | Purpose |
| ----- | ------- |
| `openid` | OIDC identity |
| `profile` | Display name |
| `email` | Account email |
| `offline_access` | Refresh token |
| `transcoding:read` | `get_job_status`, `wait_for_job`, docs tools |
| `transcoding:write` | `transcode_video`, `start_encode2_raw` |
The RS enforces `transcoding:read` and `transcoding:write` on access tokens at the transport layer.
Your Qencode API keys never leave the portal. The MCP server derives a short-lived session token per request via an internal portal endpoint.
## Environments
The same connector is deployed in two environments. Each has its own domains, accounts, projects, and credentials — sign in to the portal that matches the endpoint you connect to.
| Role | Production | QA (testing) |
| --- | --- | --- |
| MCP endpoint (connect here) | `https://mcp.qencode.com/mcp` | `https://mcp-qa.qencode.com/mcp` |
| Portal (sign in / projects) | `https://portal.qencode.com` | `https://portal-qa.qencode.com` |
| Authorization server | `https://auth.qencode.com` | `https://auth-qa.qencode.com` |
| Qencode API | `https://api.qencode.com` | `https://api-qa.qencode.com` |
The instructions below use the **production** endpoint. To test against QA, swap in the QA URL and sign in at the QA portal.
## Connect a client
**Endpoint:** `https://mcp.qencode.com/mcp` — same for every client below. Sign in to your Qencode account when the browser opens and approve access.
> **QA (internal testing):** use `https://mcp-qa.qencode.com/mcp` and sign in at the QA portal instead.
| Client | Where to add it | MCP URL / config |
| --- | --- | --- |
| **Claude** (chat) | Message box → **+** → Connectors → Add connector | `https://mcp.qencode.com/mcp` |
| **Claude Code** | Terminal | `claude mcp add --transport http qencode https://mcp.qencode.com/mcp` |
| **ChatGPT** | Apps → search **Qencode** → Connect; or Developer Mode → Build app | Connector URL: `https://mcp.qencode.com/mcp` |
| **Gemini** | `~/.gemini/settings.json` → `mcpServers` | `"httpUrl": "https://mcp.qencode.com/mcp"` — then `/mcp auth qencode` in the CLI |
| **Cursor** | Settings → Tools & MCP → New MCP Server (or `~/.cursor/mcp.json`) | `"url": "https://mcp.qencode.com/mcp"` — restart Cursor after saving |
**Cursor** (`mcp.json`):
```json
{
"mcpServers": {
"qencode": { "url": "https://mcp.qencode.com/mcp" }
}
}
```
**Gemini** (`settings.json`):
```json
{
"mcpServers": {
"qencode": {
"httpUrl": "https://mcp.qencode.com/mcp",
"timeout": 30000,
"trust": false
}
}
}
```
Tip: sign in to [portal.qencode.com](https://portal.qencode.com) in your browser before connecting — OAuth goes smoother.
## What the connector exposes
### Tools
**Transcoding & jobs**
| Tool | Description |
| ---- | ----------- |
| `transcode_video` | Submit a job from a source URL to one or more outputs. Convenience wrapper — auto-injects `encoder_version: 2` (or `1` for VMAF) when omitted. |
| `start_encode2_raw` | Escape hatch — submit a job with the full `query` JSON exactly as the [Qencode API](https://docs.qencode.com/api-reference/transcoding/#start_encode2___query__attributes--format__attributes) expects. |
| `get_job_status` | One-shot status snapshot by `task_token`. |
| `get_job_status_detailed` | Full, authoritative job status, including per-rendition progress and output details. |
| `wait_for_job` | Poll until terminal state, timeout, or internal poll cap. Do not call in parallel with other tools in the same client batch. |
| `search_qencode_docs` | Search the built-in knowledge base of recipes and reference docs. |
| `fetch_qencode_doc` | Fetch the full content of a knowledge-base resource by `qencode://` URI (tool-based counterpart to `resources/read`). |
**Media Storage**
Bucket management and ingest for Qencode Media Storage. These ride the same OAuth grant as the transcoding tools — no extra scope and no re-consent.
| Tool | Description |
| ---- | ----------- |
| `list_buckets` | List the Media Storage buckets available to the account. |
| `create_bucket` | Create a new bucket. Called only on an explicit request — not to satisfy a missing `destination`. |
| `list_objects` | Browse the contents of a bucket. |
| `get_download_url` | Return a time-limited download URL for an existing object. |
| `download_url_to_bucket` | Server-side copy of a public URL into a bucket (ingest, no transcoding). |
### Resources
The server ships a knowledge base of recipes and reference docs, exposed as MCP resources so the agent can fetch only what it needs. Notable URIs:
- `qencode://docs/best-practices` — composition defaults the agent applies automatically
- `qencode://docs/storage` — destination compatibility matrix (Qencode S3, R2, AWS S3, Azure, B2, FTP/SFTP)
- `qencode://docs/error-codes` — error code → cause → fix
- `qencode://docs/gotchas` — non-obvious API quirks
- `qencode://schema/digest` — full attribute reference for `start_encode2`
- `qencode://recipe/<slug>` — one per feature flow: `hls_abr`, `mp4_ladder`, `audio_outputs`, `thumbnails`, `speech_to_text`, `subtitles`, `stitching`, `drm_widevine_ezdrm`, `drm_fairplay_ezdrm`, `drm_playready_ezdrm`, `drm_aes128`, `drm_buydrm`, `drm_expressplay`, `codec_av1`, `per_title_encoding`, `incremental_abr`, `refresh_abr_playlist`, `callbacks`, `reliability`, `video_metadata`
Use `search_qencode_docs` to discover the right recipe URI for a goal.
### Prompts (slash commands)
In clients that surface MCP prompts, **21** one-shot templates are available. Each tells the agent to read the matching `qencode://recipe/...` resource and submit via `start_encode2_raw`.
**ABR / packaging:** `encode_hls_abr`, `encode_dash_abr`, `encode_mp4_ladder`, `encode_incremental_rung`, `encode_refreshing_playlist`
**Codecs / quality:** `encode_av1`, `tune_per_title`
**Audio / images / text:** `extract_audio`, `generate_thumbnails`, `transcribe`, `add_subtitles`
**Probe / stitch:** `get_video_metadata`, `stitch_videos`
**Production hooks:** `enable_callbacks`, `enable_reliability`
**DRM:** `encode_aes128_hls`, `encode_widevine_ezdrm`, `encode_playready_ezdrm`, `encode_fairplay_ezdrm`, `encode_drm_buydrm`, `encode_drm_expressplay`
### Source URL rules
`transcode_video` and `start_encode2_raw` accept `source` values with schemes `https://`, `http://`, `s3://`, or `tus:`. FTP/SFTP and private/metadata URLs are rejected at the tool boundary (SSRF defence). See `docs/security/THREAT_MODEL.md` for limitations.
## Security
Authentication is OAuth 2.1 only — there is no static-API-key mode. Your Qencode API keys never leave the portal; the server derives a fresh, short-lived session token per request via an internal portal endpoint. Source URLs are validated at the tool boundary (SSRF defence — see [Source URL rules](#source-url-rules)).
Full threat model and adversarial test coverage: [`docs/security/THREAT_MODEL.md`](docs/security/THREAT_MODEL.md).
## Development
```bash
uv venv && uv pip install -e ".[dev]"
NO_NETWORK=1 pytest -q # offline L1 + L2 + L5 (~540 tests)
pytest -m protocol # MCP wire conformance only
pytest -m unit # per-tool logic (FakeQencode)
pytest -m security # OWASP MCP Top 10 adversarial suite
```
Protocol tests run fully offline (mocked Authorization Server, portal, and Qencode API). **CI** is the Jenkins job `mcp_automated_tests` (`Jenkinsfile.manual`): manual checkboxes for any layer, nightly L3 cron, weekly L4 cron.
### Supported MCP protocol versions
Clients negotiate a version at `initialize`. This server targets **[MCP 2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25)** as the primary version. CI also runs conformance tests against **2025-06-18** because JSON-RPC batching behavior differs between earlier revisions. We do not claim support for **2025-03-26** or older wire semantics beyond what the underlying SDK negotiates.
| Version | Support | Notes |
| ----------- | -------------- | ------------------------------------------ |
| 2025-11-25 | Primary | Streamable HTTP, resumable SSE where used |
| 2025-06-18 | CI matrix | Regression guard for mid-2025 clients |
| 2025-03-26 | Not targeted | Batching semantics differ from 2025-06-18 |
### More docs
- Local server / env vars: [`docs/local-development.md`](docs/local-development.md)
- Test layers (L1–L5): [`docs/testing.md`](docs/testing.md) and [`tests/README.md`](tests/README.md)
- L3 against live QA / PROD: [`tests/integration/README.md`](tests/integration/README.md)
- L4 agent evals: [`evals/README.md`](evals/README.md)
- Pre-release gate: [`docs/release-checklist.md`](docs/release-checklist.md)
## Versioning policy
The connector follows [SemVer](https://semver.org/) applied to the **MCP surface** — tools, prompts, resources, OAuth scopes, and supported protocol versions. Qencode HTTP API changes are out of scope (they are the API's own concern, not the connector's).
- **MAJOR** — a breaking surface change: a tool/prompt/resource is removed or renamed, a previously optional argument becomes required, an OAuth scope is added or tightened in a way that forces re-consent, or a supported MCP protocol version is dropped.
- **MINOR** — a backward-compatible addition: a new tool/prompt/resource, a new optional argument, or a newly supported protocol version.
- **PATCH** — no change to the surface shape: tool/prompt description rewordings, knowledge-base/doc updates, and bug fixes.
Surface changes are guarded by snapshot tests under [`tests/protocol/`](tests/protocol). When you change the surface, regenerate the snapshots (`python scripts/regen_tools_snapshot.py`) and bump the version in the **same** PR: `pyproject.toml`, `src/qencode_mcp/__init__.py`, `server.json`, and a new `CHANGELOG.md` entry must all agree.
## Links
- Changelog: [`CHANGELOG.md`](CHANGELOG.md)
- OAuth 2.1 authorization-server spec: [`docs/oauth-spec.md`](docs/oauth-spec.md)
- Qencode portal: <https://portal.qencode.com> (production) · <https://portal-qa.qencode.com> (QA)
- Qencode API reference: <https://docs.qencode.com/api-reference/transcoding>