About seerr-mcp-server
seerr-mcp-server supports workflows for Jellyseerr and Overseerr users by searching media, confirming matches, checking availability, and creating requests. Writes default to preview and require confirmation; Jellyseerr handles request permissions and routing, while the server does not call Radarr or Sonarr directly.
Key features
- 01Search movies and TV titles
- 02Check media details, availability, and requests
- 03Filter and list recent requests
- 04Preview and confirm media requests
- 05Inspect request status and routing
- 06Review Radarr/Sonarr service options
Use cases
- 01Confirm a title match before requesting it
- 02Check existing requests to avoid duplicates
- 03Review request progress and media availability
- 04Inspect configured services and quality profiles
MCP support
Exposes 6 tools and 1 request resource to MCP clients over STDIO or Streamable HTTP.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
npx -y @cyanheads/seerr-mcp-serverSEERR_BASE_URLBase URL of the Jellyseerr/Overseerr instance, e.g. http://host:5055. No /api/v1 suffix, no trailing slash.SEERR_API_KEYSecretSeerr API key (Settings → General → API Key), sent as the X-Api-Key header.SEERR_REQUEST_TIMEOUT_MSPer-request HTTP timeout in milliseconds.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODESecretAuthentication mode to use: 'none', 'jwt', or 'oauth'.Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.
Tools
6Saved tool list · updated 2w ago
| Parameter | Type | Required | Description |
|---|---|---|---|
| page | integer | No | 1-based result page. Seerr returns ~20 results per page; use with a prior call to page through. |
| limit | integer | No | Max normalized results to return from this page (caps output size; does not change which page is fetched). |
| query | string | Yes | Title to search for, e.g. "Mulan" or "Severance". Natural-language titles are fine; Seerr matches against TMDB. |
| language | string | No | ISO 639-1 language for titles/overviews, e.g. "en" or "pt-BR". Defaults to the Seerr instance locale when omitted. |
| mediaType | enum | No | Restrict results to movies, TV shows, or both. People are always excluded — this server requests media, not actors.movie | tv | all |
Details
From the project README@cyanheads/seerr-mcp-server
Search Jellyseerr/Overseerr, check availability, and create guarded media requests via MCP. STDIO or Streamable HTTP.
Overview
Jellyseerr and Overseerr media-request workflow: search TMDB-backed titles, confirm the exact match, check availability and request state, and create a guarded request that Radarr/Sonarr act on. Jellyseerr owns permissions, quotas, routing, and status — this server never calls Radarr/Sonarr directly. Runs as a stdio process or a local Streamable HTTP server.
Tools
| Tool | Description |
|---|---|
seerr_search_media | Search movies and TV by title; returns ranked matches with TMDB ID, year, overview, and decoded availability when Jellyseerr already tracks the title. The required first step before requesting. |
seerr_get_media | Fetch exact movie/show details by TMDB ID + media type to confirm the title before a write; for TV, a per-season summary or one season's episode list. |
seerr_list_requests | List recent requests with status/type/requester filters; echoes the applied filters and decodes every numeric status. Titles are opt-in via includeTitles. |
seerr_request_media | Guarded write. Previews the request payload by default (mode: preview); creates the request only on mode: request, and only after an accepted confirmation. |
seerr_request_status | Fetch one request by ID — title, decoded request + media availability (incl. 4K), requester, routing summary, and a state-tuned next-step hint. |
seerr_service_options | Summarize configured Radarr/Sonarr services, default quality profiles, and instance capability flags (4K, partial requests, specials, media server). Filesystem paths redacted unless includePaths. |
Resources
| Resource | Description |
|---|---|
seerr://request/{requestId} | Read-once summary of one request — decoded status, media availability, requester, and routing. Mirrors seerr_request_status. |
All request data is also reachable via tools — request enumeration is the job of seerr_list_requests (the tool-only access path).
Capability reference
seerr_search_media tool
- Search titles with
mediaType: movie | tv | all; people are excluded.pageis 1–1000;limitis 1–20, default 10. - Returns TMDB matches and decoded
status/status4kfor tracked titles. Empty results return[]with a guidance notice. - Optional ISO 639-1
languageselects localized titles and overviews.
seerr_get_media tool
- Availability plus any existing open request for the title (avoids duplicate requests)
- TV: omit
seasonNumberfor a per-season summary, or pass one to fetch that season's episode list (season 0 is Specials) - A TMDB ID that doesn't resolve surfaces as a typed
media_not_foundwith a search-recovery hint (Jellyseerr's raw HTTP 500 is classified in the service layer)
seerr_list_requests tool
- Filter by lifecycle
filter,mediaType, andrequestedById; sort byaddedormodified, ascending or descending.takeis 1–100, default 20;skipselects the offset. - Returns decoded statuses, requester
{ id, displayName }, and an enrichment trailer with applied filters. includeTitles: truejoins media titles once per distinct title (default off); unresolved rows retain their data and are disclosed in the notice.
seerr_request_media tool
- Guarded write.
mode: preview(default) returns the resolved title and exactPOST /requestpayload without writing.mode: requestasks for confirmation bound to the same caller, title and payload; declined, cancelled or invalid answers returnrequest_cancelled. - TV requests require
seasons: "all"or a list such as[1, 2]; season 0 (Specials) requires special episodes to be enabled. Instance capability checks run before any POST; existing requests appear in output and duplicate rejections returnduplicate_request. - Optional routing overrides:
serverId,profileId,rootFolder,languageProfileId. Omit them to use Jellyseerr's defaults.
seerr_request_status tool
- Accepts
requestIdfromseerr_request_media'screated.requestIdorseerr_list_requests. A missing request returnsrequest_not_found. - Returns decoded
requestStatus,mediaStatus/mediaStatus4k, requester{ id, displayName }, routing (serverId,profileName,is4k), andstateGuidance. - Joins
titleon each call; it is absent when notmdbIdexists or the lookup fails.
seerr_service_options tool
- Returns instance version, media server, capability flags (
movie4kEnabled,series4kEnabled,partialRequestsEnabled,specialEpisodesEnabled), and service IDs, defaults and quality profiles. - Failed service legs retain the available results with a notice.
includePaths: trueexposes root-folder paths and free space; both are omitted by default.
seerr://request/{requestId} resource
- Accepts
requestIdfromseerr_request_mediaorseerr_list_requests; a missing request returnsrequest_not_found. - Mirrors
seerr_request_status, including redaction and a title join.titleis absent when notmdbIdexists or the lookup fails; resources take no per-read options.
Features
Built on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
HTTP requires stateful sessions for 2025-era confirmation rounds; explicit MCP_SESSION_MODE=stateless fails startup. Consent records expire after ten minutes and changed or replayed records ask again. Redemption excludes concurrent retries in one process; request creation makes one POST attempt without automatic retries. Cross-instance read-and-delete is not atomic: use shared strongly consistent filesystem, Supabase or Cloudflare D1 storage for routed retries, and account for duplicate-submission races; Cloudflare KV is unsuitable for consent records.
Seerr-specific:
- Read + guarded-request only — admin-scope endpoints (approve/decline, retry, edit/delete, media/file deletion, user/settings/sync) are excluded by design, not by API limitation
- PII/infra redaction centralized in one normalizer choke point — requesters project to
{ id, displayName }; operator email, Plex/Jellyfin tokens, andserviceUrlnever reach output; filesystem paths are opt-in viaincludePaths - Status decoding centralized in one helper — request and media statuses (including the separate 4K availability) decode to
{ raw, label }everywhere, forward-compatible with new Jellyseerr status codes - Capability validation against cached instance settings catches most bad requests before they reach the API
- A short-TTL settings cache avoids a round-trip on every preview
Agent-friendly output:
- Provenance and disclosure — searches echo the effective query; capped lists disclose truncation; a degraded service leg surfaces a notice instead of silently dropping data
- Typed, actionable errors —
media_not_found,request_not_found,seasons_required,four_k_not_enabled,duplicate_request, and more carry a recovery hint so callers can branch and retry without parsing prose
Getting started
Add the following to your MCP client configuration file, pointing SEERR_BASE_URL at your own Jellyseerr or Overseerr instance and supplying its API key.
{
"mcpServers": {
"seerr-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/seerr-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"SEERR_BASE_URL": "http://localhost:5055",
"SEERR_API_KEY": "your-api-key"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"seerr-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/seerr-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info",
"SEERR_BASE_URL": "http://localhost:5055",
"SEERR_API_KEY": "your-api-key"
}
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 SEERR_BASE_URL=http://localhost:5055 SEERR_API_KEY=your-api-key bun run start:http
# Server listens at http://localhost:3010/mcp
Prerequisites
- Bun v1.4.0 or higher (or Node.js v24+).
- A running Jellyseerr or Overseerr instance, and its API key (Settings → General → API Key).
Installation
- Clone the repository:
git clone https://github.com/cyanheads/seerr-mcp-server.git
- Navigate into the directory:
cd seerr-mcp-server
- Install dependencies:
bun install
- Configure environment:
cp .env.example .env
# edit .env — set SEERR_BASE_URL and SEERR_API_KEY
Configuration
All configuration is validated at startup via Zod schemas in src/config/server-config.ts. Key environment variables:
| Variable | Description | Default |
|---|---|---|
SEERR_BASE_URL | Required. Base URL of the Jellyseerr/Overseerr instance, e.g. http://localhost:5055. The service appends /api/v1 — no /api/v1 suffix, no trailing slash. | — |
SEERR_API_KEY | Required. Jellyseerr API key (Settings → General → API Key). Sent as the X-Api-Key header. | — |
SEERR_REQUEST_TIMEOUT_MS | Per-request HTTP timeout in milliseconds. | 15000 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for the HTTP server. | 3010 |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend. | in-memory |
MCP_SESSION_MODE | HTTP session mode; must resolve to stateful for confirmation rounds. The example and Docker image set stateful; an unset value uses auto, resolving to stateful. Explicit stateless fails startup. | auto |
MCP_REQUEST_STATE_KEY | Optional key of at least 32 bytes, shared across instances, that seals consent record IDs. | — |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
OTEL_EXPORTER_OTLP_ENDPOINT | OTLP base for traces and metrics; signal-specific endpoints override it. | — |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | Opt-in log export endpoint; the base endpoint never enables logs. | — |
LOG_TOOL_FAILURE_PAYLOADS | Opt-in failed-call arguments/result logging; redaction matches key names, so secrets in free-form values can remain. | false |
See .env.example for the full list of optional overrides.
Running the server
Local development
-
Build and run:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or bun run start:http -
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security, changelog sync bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker build -t seerr-mcp-server .
docker run --rm \
-e SEERR_BASE_URL=http://host.docker.internal:5055 \
-e SEERR_API_KEY=your-api-key \
-p 3010:3010 \
seerr-mcp-server
The Dockerfile defaults to HTTP transport, stateful session mode, and logs to /var/log/seerr-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
Project structure
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers the six tools + one resource and inits the Seerr service. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/mcp-server/resources | Resource definitions (*.resource.ts). |
src/services/seerr | Jellyseerr API client, status decoders, and the PII/infra redaction normalizers. |
tests/ | Unit and integration tests mirroring src/. |
Development guide
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
- Handlers throw, framework catches — no
try/catchin tool logic - Use
ctx.logfor request-scoped logging,ctx.statefor tenant-scoped storage - Register new tools and resources via the barrels in
src/mcp-server/*/definitions/index.ts - Wrap the Jellyseerr API: validate raw → normalize and redact to a domain type → return the output schema; never fabricate missing fields, and never let operator PII or paths reach output
Contributing
Issues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
License
Apache-2.0 — see LICENSE for details.
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.