plex-mcp
Enables browsing and searching your Plex Media Server libraries, including recently added items, on-deck content, and detailed item metadata.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@plex-mcpsearch for 'Star Wars'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
plex-mcp
An MCP server for Plex Media Server, packaged as a Docker container. Lets an MCP client (Claude Desktop, etc.) browse and search your Plex libraries.
Tools
Tool | Description |
| List all libraries (sections) on the server |
| Search across all libraries |
| Recently added items, optionally per-section |
| Items "on deck" (partially watched / next up) |
| Metadata for one item by rating key. Pass |
| List items in a library section (paged, optional type filter, optional sparse |
| Children of an item (show→seasons, season→episodes, artist→albums) |
| Currently-playing sessions on the server |
| Playback history entries (paged, most recent first) |
| Mark an item as watched (reversible) |
| Mark an item as unwatched (reversible) |
| List all playlists (regular + smart) |
| List a playlist's contents |
| Create a regular playlist seeded with one item |
| Append an item to a regular playlist |
| Remove an item by |
| Delete a playlist (metadata only — media untouched) |
| Plex's curated server-wide hubs (Continue Watching, Recently Released, etc.) |
| Curated hubs scoped to one library section |
| Plex's curated "related" hubs for an item (provenance-grouped) |
| Algorithmic similar items for an item (flat list) |
| Re-pull metadata for an item from its current agent (optional |
| List candidate matches for an item (TMDB / TVDB / etc.); optional title/year/agent/language overrides |
| Apply a chosen match ( |
| Override scalar metadata fields (title, summary, year, etc.) with field-level locking |
| Detach an item from its agent binding (back to unmatched state); locked fields survive |
| Trigger a metadata refresh for an entire library section (incremental or deep) |
| Split a Plex item back into its constituent media variants as N separate items |
| Merge other items INTO a target item (sources absorbed; target survives) |
| Fetch poster/art/banner/clearLogo bytes for an item as an MCP image content block (so vision-capable clients can actually see the picture); optional max_width/max_height routes through Plex's transcoder |
| Same input surface as |
Related MCP server: Plex Assistant MCP
Configuration
Two environment variables, both required:
Var | Example | Notes |
|
| Base URL of your Plex server |
| (see below) | Plex auth token |
To find your Plex token, see Plex's Finding an authentication token guide.
Plex on the same host as the container? Use
PLEX_URL=http://host.docker.internal:32400. The compose file mapshost.docker.internalto the Docker host gateway viaextra_hosts, so the container can reach a Plex server running on the host. The host's own hostname (e.g.my-nas) won't resolve from inside the container without that mapping.
Transport modes
Mode | When to use | How to start |
stdio (default) | Direct invocation by Claude Desktop / MCP clients |
|
Streamable HTTP | Long-lived deployment (Portainer, Compose, k8s) | Set |
In HTTP mode the server exposes:
POST/GET/DELETE /mcp— MCP Streamable HTTP endpoint (per spec)GET /health— liveness probe (used by docker healthcheck)
HTTP mode has no caller authentication — TLS (below) encrypts traffic but doesn't identify the caller. Bind only to a private network. Rely on host firewall or LAN isolation. Don't expose to the public internet without adding bearer-token auth first.
Enabling HTTPS
HTTPS is opt-in. Resolution order at startup:
Bring-your-own cert — set both
MCP_TLS_CERT_FILEandMCP_TLS_KEY_FILEto PEM file paths. Use this when terminating Let's Encrypt or an internal CA. The server reads them at startup; restart the container to pick up renewed files.Self-managed cert (recommended for LAN-only setups) — set
MCP_TLS=auto. The server generates an ECDSA P-256 self-signed cert on first start, writes it toMCP_TLS_DIR(default/data/certs), and reuses it on subsequent starts. When the cert is within 30 days of expiry it's regenerated automatically.Otherwise the server stays on plain HTTP (today's default).
Var | Default | Notes |
| unset |
|
|
| Where |
|
| Subject Alternative Names. Comma-separated |
| first DNS SAN, else | Certificate common name. |
|
| Validity period. Cert rotates when <30 days remain. |
| unset | BYO cert (PEM). Overrides |
| unset | BYO key (PEM). |
On startup the server logs the cert's SHA-256 fingerprint and
notAfter. Pin the fingerprint client-side, or trust the cert in
your OS keystore for browsers and CLI tools.
When TLS is on, the compose healthcheck needs the
--no-check-certificate flag — update the test: line to
["CMD", "wget", "--no-check-certificate", "-q", "-O-", "https://localhost:3000/health"].
Pointing mcp-remote at an HTTPS endpoint
For a self-signed cert, either pin the cert file via Node's CA bundle or skip verification on the client (LAN-only):
# Trust the server's self-signed cert (preferred):
NODE_EXTRA_CA_CERTS=./server.crt \
npx -y mcp-remote https://nas.local:3443/mcp
# Or skip verification for quick testing (LAN-only):
NODE_TLS_REJECT_UNAUTHORIZED=0 \
npx -y mcp-remote https://nas.local:3443/mcpReverse-proxy alternative
In-process TLS is convenient when you don't already run an ingress
controller. If you have Caddy, Traefik, or nginx in front of your
home services, the more idiomatic pattern is to terminate TLS at
the proxy (with automatic Let's Encrypt) and keep plex-mcp on
plain HTTP behind it. The two approaches are interchangeable — pick
whichever matches your existing setup.
Run with Docker (stdio, on demand)
docker build -t plex-mcp .
docker run -i --rm \
-e PLEX_URL=http://192.168.1.50:32400 \
-e PLEX_TOKEN=your-token \
plex-mcpRun with Docker Compose (HTTP, long-lived)
The compose file pulls ghcr.io/carldog/plex-mcp:latest (multi-arch:
linux/amd64 + linux/arm64), published by CI on every push to main.
# Required env vars (or use a .env file):
export PLEX_URL=http://192.168.1.50:32400
export PLEX_TOKEN=your-token
export HOST_PORT=3001 # optional, defaults to 3001
docker compose upThe MCP endpoint will be at http://<host>:${HOST_PORT}/mcp.
To rebuild from source instead of pulling:
docker build -t ghcr.io/carldog/plex-mcp:latest .
docker compose upDeploy via Portainer (Stack from Git)
In Portainer, Stacks → Add Stack → Repository.
Repository URL:
https://github.com/CarlDog/plex-mcpCompose path:
docker-compose.ymlEnvironment variables: set
PLEX_URL,PLEX_TOKEN, optionallyHOST_PORT.Deploy. Healthcheck reaches green within ~10 seconds.
Use with Claude Desktop
stdio (local invocation)
{
"mcpServers": {
"plex": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "PLEX_URL", "-e", "PLEX_TOKEN",
"plex-mcp"
],
"env": {
"PLEX_URL": "http://192.168.1.50:32400",
"PLEX_TOKEN": "your-token"
}
}
}
}HTTP (remote MCP server)
{
"mcpServers": {
"plex": {
"url": "http://nas.local:3001/mcp"
}
}
}(Requires Claude Desktop or a client that supports remote MCP HTTP.)
Local development
npm install
cp .env.example .env # then edit
PLEX_URL=... PLEX_TOKEN=... npm run dev # stdio
MCP_PORT=3000 PLEX_URL=... PLEX_TOKEN=... npm run dev # HTTPLogging
The server emits structured logs to stderr (stdout is the MCP wire protocol in stdio mode and must not be polluted). Format:
2026-04-29T15:30:00.000Z INFO [tool:plex_browse] invoke section_id=7 type=show limit=2
2026-04-29T15:30:00.337Z INFO [tool:plex_browse] ok ms=337Configure verbosity via the LOG_LEVEL env var (default info):
Level | Shows |
| Errors only |
| + 4xx Plex responses |
| + Tool invocations and completions |
| + Every Plex API call with method, path, status, ms |
| (reserved) |
Container logs are captured by Docker's json-file driver and
rotated automatically (10MB × 3 files = ~30MB cap; oldest deleted
on rotation). View with docker logs plex-mcp or docker logs -f.
Security
The container runs as a non-root user (
plexmcp).The Plex token is passed via env var — never bake it into the image.
A
.githooks/pre-commitruns gitleaks on every commit. Activate it once per clone:git config core.hooksPath .githooks
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/CarlDog/plex-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server