Homelab Haven

Self-Hosted Media Stack, Part 8: Give Claude Real Access to Your Library

August 6, 20265 min read

Part 8 of Media Stack from Scratch. Everything here assumes Sonarr and Radarr from Part 2 are up and you've still got their API keys noted down.

Seven parts built a stack that runs itself. This part gives an AI assistant a way to talk to it — "what's downloading right now," "add this show," "why hasn't episode 4 imported yet" — answered in plain language instead of you opening Sonarr's UI and hunting through the queue. The mechanism is MCP (Model Context Protocol): a small standard that lets an AI client like Claude connect to a server exposing a set of "tools" — in this case, Sonarr and Radarr's own REST APIs, wrapped so an AI can call them directly.

Summary

  • You already have everything this needs: Sonarr and Radarr's API keys from Part 2.
  • One ready-made MCP server (mcp-arr-server) speaks Sonarr and Radarr's API — no custom code, one config block.
  • claude mcp list showing "✔ Connected" is not proof the tools loaded — a missing or empty API key still shows a green check. This is the trap that costs the most time.
  • A new MCP server needs Claude itself restarted, not just reconfigured.
  • The API key this uses is all-or-nothing — full read/write, no read-only mode. Treat it like any other credential: it stays off the public internet.

What MCP actually is, in one paragraph

An MCP server is a small program that exposes a fixed set of tools — named actions with typed inputs — that an AI client can call. Point Claude at one, and it can call get_series, add_movie, get_queue, or whatever that server defines, the same way it can read a file or run a search. The server does the actual HTTP call to Sonarr/Radarr; Claude just decides when to call which tool based on what you asked in plain language.

You don't write this server yourself for something as common as Sonarr/Radarr — one already exists.

Wiring up mcp-arr-server

This is the exact config block for both Sonarr and Radarr at once — one MCP server, both apps, using the API keys you already noted in Part 2 (Settings → General → API Key in each app):

{
  "mcpServers": {
    "arr": {
      "command": "npx",
      "args": ["-y", "mcp-arr-server"],
      "env": {
        "SONARR_URL": "http://localhost:8989",
        "SONARR_API_KEY": "your-sonarr-api-key",
        "RADARR_URL": "http://localhost:7878",
        "RADARR_API_KEY": "your-radarr-api-key"
      }
    }
  }
}

Where this block goes depends on which Claude you're using:

  • Claude Desktop: claude_desktop_config.json (Settings → Developer → Edit Config opens it directly).
  • Claude Code: .mcp.json in your project root, or claude mcp add from the CLI if you'd rather not hand-edit JSON.

npx -y mcp-arr-server means Claude launches the server itself, on demand, the first time it's needed — no container to run, no port to publish. If Sonarr/Radarr are themselves behind Tailscale rather than on localhost, point the URLs at their tailnet addresses instead.

The trap: a green checkmark that lies

This is worth stating plainly because it's the single most time-wasting failure mode: claude mcp list reporting a server as "✔ Connected" only proves the process started — it says nothing about whether the tools inside it actually work. An empty or wrong API key doesn't stop the server from launching; it just makes every tool call fail once Claude actually tries to use one, with no earlier warning.

If Claude reports it has no arr-related tools available, or every request errors, don't trust the green check — go straight to the actual API keys and confirm they're current in both the config and in Sonarr/Radarr's own settings.

The trap: reconfiguring isn't enough — restart Claude itself

Editing the MCP config while Claude is already running doesn't do anything on its own. The client's connection to each MCP server is established once, at startup — adding a new server, or fixing a broken one, needs Claude Desktop or Claude Code restarted, not just the config file resaved. This one's easy to miss because nothing errors — Claude just keeps behaving as if the new server doesn't exist, for as long as you keep the same session open.

The trap: this API key is all-or-nothing

Sonarr and Radarr's API keys don't have a read-only mode — the key that lets Claude look up what's downloading is the exact same key that lets it delete a series or change your quality profiles. That's not a flaw specific to MCP; it's just how these apps' APIs have always worked, and it's worth being deliberate about now that something else is calling it on your behalf:

  • Keep it off the public internet the same way you would any other credential — Tailscale-only is the right default for anything this capable, never a public Cloudflare route.
  • If you ever need to hand access to more than one device or person, a shared, centrally-managed MCP endpoint (bearer-auth in front of it, one gateway aggregating several backends) is the natural next step up from per-device local config — a genuinely more advanced setup, and a fair "Part 9" if there's appetite for it, not something to reach for on day one.

What this actually looks like in use

With the config above and Claude restarted, you can ask things like:

  • "What's currently downloading?" — Claude calls the queue endpoint on both apps and summarizes it.
  • "Add [show] to Sonarr, 1080p profile" — a real add, using the profile you set up in Part 2.
  • "Why is [episode] stuck?" — Claude can check the queue and recent history and give you an actual answer instead of you clicking through Sonarr's UI to find it.

None of this replaces the stack from Parts 1–7 — it's a different way of talking to the same thing that was already running.

Checkpoint

  • mcp-arr-server configured with both apps' real API keys and URLs
  • Claude restarted after adding it (not just the config file saved)
  • Confirmed actual tool calls work — not just a green "Connected" status
  • The key treated like any other credential: no public exposure

Previous: Part 7 — Profilarr. Start of the series: Part 1 — the map.

If this saved you some time, a coffee keeps the lights on and the posts coming.

☕ Buy me a coffee