Skip to content

cxrobx/plex-agent

Repository files navigation

plex-agent

An AI agent for your Plex media server. Ask it "why isn't the new episode of X downloading?" in Discord or from a chat widget inside Overseerr — it inspects Sonarr/Radarr queues, diagnoses stuck downloads, blocklists dead releases, triggers re-searches, and answers library questions, autonomously, with admin approval gates on destructive actions.

Built on the Claude Code CLI as the reasoning engine and FastMCP for the tool layer — each chat message becomes a claude -p subprocess call wired to a purpose-built MCP server.

User message (Discord #channel or Overseerr widget)
  → bot.py (discord.py)  or  web.py (aiohttp POST /api/chat)
    → claude -p subprocess  (--mcp-config mcp.json, per-user session ID)
      → MCP server (server.py, FastMCP)
        → Sonarr · Radarr · Plex · ffprobe · memory · Discord REST
      → response text
    → chunked Discord reply / JSON to widget

What it can do

  • Diagnose downloads: reads Sonarr/Radarr queues with error details, recognizes failure patterns (e.g. a debrid provider rejecting a release), clears + blocklists + re-searches without being told the steps.
  • Answer library questions: what's on the server, resolution/codec via ffprobe, what's coming.
  • Take requests conversationally alongside Overseerr.
  • Remember context per user across conversations (optional Supermemory integration).
  • Ask permission first: destructive actions post an approval embed to an admin channel and wait for a ✅/❌ reaction (5-minute timeout). On the web surface, an HMAC-verified identity token lets the admin's own requests auto-approve.

Surfaces

Surface Entry point Auth
Discord bot bot.py, replies in one configured channel Discord identity
Web widget static/chat.html in an iframe (e.g. floating button injected into Overseerr via static/widget-inject.js) HMAC-signed identity token minted by a small reverse-proxy worker that verifies the Overseerr session — see PLEXBOT_AUTH_SECRET in .env.example

The widget is iframe-only by design: chat.js refuses to render unless embedded by an origin in ALLOWED_PARENT_ORIGINS (edit that list at the top of static/chat.js).

Setup

cp .env.example .env      # fill in Discord/Sonarr/Radarr/Plex credentials
docker compose up -d --build
docker exec -it plex-agent claude login   # one-time Claude auth inside the container

The container bundles Node 22 + Python + ffmpeg + the Claude Code CLI and runs as a non-root user. Web API listens on :8080 inside the container.

Running outside Docker:

pip install -e . && python -m plex_agent.bot

Configuration

All config is env-driven — see .env.example. Required: Discord bot token + channel IDs, Sonarr/Radarr/Plex URLs + API keys. Optional: Supermemory (per-user long-term memory), PLEXBOT_AUTH_SECRET (web identity), WEB_ADMIN_USER_ID.

Agent behavior lives in system-prompt.md — edit it to teach the agent your stack's quirks (it ships with patterns for a Real-Debrid + SABnzbd setup as a worked example). {{ADMIN_DISCORD_ID}} is substituted from the environment at runtime.

Sessions & safety

  • Deterministic session per user (uuid5 of the user ID) so conversations resume; !reset starts fresh. Web and Discord surfaces are namespaced separately.
  • Requester identity flows to the MCP server via env vars; admin approval is short-circuited only when the verified requester is the admin.
  • A circuit breaker stops runaway Claude calls; replies are chunked to Discord's 2000-char limit.

Gotchas (learned the hard way)

  • docker compose restart does not reload .env — use down && up.
  • The Claude Code CLI needs Node 22+ (empty output on Node 20).
  • --session-id must be a valid UUID and only works for new sessions — resume existing ones with --resume.

License

MIT

About

AI agent for your Plex server — Discord bot + Overseerr chat widget that diagnoses stuck downloads and manages Sonarr/Radarr, built on the Claude Code CLI + MCP

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors