
Company News
Free Business Plan Upgrades for Open Source Maintainers
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.
@cyanheads/seerr-mcp-server
Advanced tools
Search Jellyseerr/Overseerr, check availability, and create guarded media requests via MCP. STDIO or Streamable HTTP.
Search Jellyseerr/Overseerr, check availability, and create guarded media requests via MCP. STDIO or Streamable HTTP.
A workflow MCP server over a self-hosted Jellyseerr / Overseerr instance — the request layer that fronts Jellyfin/Plex/Emby plus Radarr and Sonarr. The unit of work is not "download a movie"; it is search → resolve the exact TMDB-backed title → check availability and request state → create a guarded request that Radarr/Sonarr act on. Jellyseerr owns permissions, quotas, routing, and status; this server never touches Radarr/Sonarr directly.
Two properties make it safe to hand an agent:
seerr_request_media) defaults to mode: preview — it resolves the title and returns the exact payload that would be submitted without writing anything. The real request fires only on mode: request, and asks for an explicit confirmation first when the client supports elicitation.src/services/seerr/normalizers.ts) that allow-lists the fields it emits, so operator email, Plex/Jellyfin tokens and media-server IDs, and internal serviceUrl hosts never reach the model — requesters are projected to { id, displayName }. Redaction is always on; filesystem paths are the single opt-in, behind includePaths.Six tools covering the request workflow — discover (search) → confirm (get) → understand routing (service_options) → request (request_media) → track (request_status / list_requests):
| 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 with an elicited 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. |
Every status field is decoded to { raw, label } — both the numeric code Jellyseerr returns and a human label — so an agent never has to hardcode the enum mapping.
seerr_search_mediaTitle disambiguation entry point. Wraps GET /search, filters to movies and TV (people are always excluded), and decodes availability when the title is tracked.
movie / tv / all media-type filterstatus, plus status4k when 4K is enabled) for tracked titles onlylimit to cap output sizelanguage for localized titles/overviews[] with a guidance notice, not an errorseerr_get_mediaConfirm the exact title before a write. Wraps GET /movie/{id} or GET /tv/{id}, optionally a season's episodes.
seasonNumber for a per-season summary, or pass one to fetch that season's episode list (season 0 is Specials)media_not_found with a search-recovery hint (Jellyseerr's raw HTTP 500 is classified in the service layer)seerr_list_requestsReview recent requests and their lifecycle. Wraps GET /request.
filter (pending, processing, available, failed, …), mediaType, and requestedById filtersadded) or last-changed (modified), ascending or descendingtake / skip pagination; the enrichment trailer echoes the filter set the server applied{ id, displayName }includeTitles: true joins them from the media records — one lookup per distinct title on the page, so a 4K and a non-4K request for one film cost one call. Default is off, keeping the call to a single upstream read. Rows that can't be resolved keep every other field and are disclosed in the noticeseerr_request_mediaThe only mutation in the surface, and it is triple-guarded:
mode: preview (default) resolves the title and returns the exact POST /request payload that would be submitted — no write. A sloppy call shows the payload and changes nothing.mode: request triggers a ctx.elicit confirmation when the client supports it; declining cancels before submission.destructiveHint: true is the fallback signal for non-interactive clients whose approval flow reads annotations.seasons: "all" or an explicit list (e.g. [1, 2]); Specials are excluded unless the instance enables themserverId, profileId, rootFolder, languageProfileId) — omit to use Jellyseerr's defaults (recommended)duplicate_request pointing back at itseerr_service_optionsLets an agent reason about request capability and routing without a separate status tool. Fans out service + settings + version reads with Promise.allSettled, so one failed leg degrades to a disclosed notice rather than failing the call.
movie4kEnabled / series4kEnabled / partialRequestsEnabled / specialEpisodesEnabled flagsincludePaths: true| Type | Name | Description |
|---|---|---|
| Resource | seerr://request/{requestId} | Read-once summary of one request — title, decoded status + media availability + routing. Mirrors seerr_request_status. |
All request data is also reachable via tools — request enumeration is the job of seerr_list_requests (filterable, the tool-only access path), so the collection is intentionally not exposed as a resource. There are no prompts; the guarded-write workflow lives in the tool, not a prompt template.
Built on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1Jellyseerr-specific:
{ raw, label } everywhere, forward-compatible with new Jellyseerr status codesAgent-friendly output:
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 proseThis server connects to your own Jellyseerr/Overseerr instance — there is no public hosted endpoint. Add the following to your MCP client configuration file, pointing SEERR_BASE_URL at your 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
git clone https://github.com/cyanheads/seerr-mcp-server.git
cd seerr-mcp-server
bun install
cp .env.example .env
# edit .env — set SEERR_BASE_URL and SEERR_API_KEY
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 |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
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 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, stateless 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.
| 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/. |
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/mcp-server/*/definitions/index.tsIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
FAQs
Search Jellyseerr/Overseerr, check availability, and create guarded media requests via MCP. STDIO or Streamable HTTP.
We found that @cyanheads/seerr-mcp-server demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Open source maintainers are under more pressure than ever. We're raising our open source program from the Team plan to the Business plan, free.

Security News
The supply chain control that delays freshly published gems now covers lockfile generation and gem vendoring in Ruby projects.

Security News
During a UK cyber test, a Mythos 5 agent used sockpuppets, social engineering, and prompt injection to try to get a maintainer to merge malware.