plex-media-server-mcp
v1.0.2
Published
Safe stdio MCP tools for Plex libraries and playlists
Downloads
475
Readme
Plex Media Server MCP
plex-media-server-mcp is a local, stdio-only Model Context Protocol server for safe Plex library and playlist administration. It exposes 21 curated tools by default and one restricted raw-request tool only when explicitly enabled.
The security boundary is one configured Plex origin. The Plex token is accepted through the environment only: tools cannot supply or override the server URL, token, or authentication headers. stdout is reserved for MCP protocol messages; startup errors and diagnostics use stderr and redact the token.
Requirements
- Node.js 18.18 or newer
- A reachable Plex Media Server HTTP(S) origin, commonly
http://127.0.0.1:32400 - A Plex authentication token with only the access needed for the intended operations
- An MCP host with stdio server support
Install and run
Install the executable globally:
npm install -g plex-media-server-mcp
plex-media-server-mcpOr run it without a global install:
npx plex-media-server-mcpThe process expects configuration from its environment and communicates over stdin/stdout, so it is normally started by an MCP host rather than an interactive shell.
MCP host configuration
Use this shape for Claude Desktop, Codex, or another JSON-configured stdio MCP host. Replace the placeholder values in the host configuration; never commit a real token.
{
"mcpServers": {
"plex": {
"command": "npx",
"args": ["-y", "plex-media-server-mcp"],
"env": {
"PLEX_URL": "http://127.0.0.1:32400",
"PLEX_TOKEN": "YOUR_PLEX_TOKEN",
"PLEX_CLIENT_IDENTIFIER": "plex-media-server-mcp",
"PLEX_REQUEST_TIMEOUT_MS": "30000",
"PLEX_ENABLE_RAW_REQUEST": "false"
}
}
}
}Environment variables
| Variable | Required | Default | Meaning |
| --- | --- | --- | --- |
| PLEX_URL | Yes | None | Absolute http or https origin for one Plex server. Paths, credentials, query strings, and fragments are rejected. |
| PLEX_TOKEN | Yes | None | Plex token sent only as the X-Plex-Token request header. |
| PLEX_CLIENT_IDENTIFIER | No | plex-media-server-mcp | Stable identifier sent to Plex for this MCP client. |
| PLEX_REQUEST_TIMEOUT_MS | No | 30000 | Positive integer request timeout in milliseconds. |
| PLEX_ENABLE_RAW_REQUEST | No | false | Set exactly to true to register plex_raw_request. |
Tool reference
Parameters marked with ? are optional. Object fields accept string, finite number, boolean, or arrays of those scalar values unless stated otherwise.
Status
plex_server_status()— verify connectivity and return the Plex root identity response.
Libraries
library_list_sections()— list configured library sections.library_get_section(sectionId, includeDetails?)— get one section.library_create_section(name, type, agent, language, scanner?, locations?, preferences?)— create a section.library_update_section(sectionId, name?, agent, language?, scanner?, locations?, preferences?)— update a section;agentis required by the Plex contract.library_delete_section(sectionId, asynchronous?, confirm)— permanently delete a section.library_list_items(sectionId, type?, filters?, sort?, offset?, limit?, includeFields?)— browse section items;offsetandlimitmap to Plex pagination headers.library_get_metadata(ids)— get one or more metadata records;idsis a non-empty string array.library_update_metadata(ids, fields)— update metadata using a non-empty query-field object.library_delete_metadata(ids, proxy?, confirm)— permanently delete metadata records.library_refresh(sectionId?, force?, path?)— refresh all sections or one section;pathrequiressectionId.library_empty_trash(sectionId, confirm)— permanently empty a section's trash.
Playlists
playlist_list(playlistType?, smart?)— list playlists;playlistTypeisaudio,video, orphoto.playlist_get(playlistId)— get one playlist by non-negative numeric ID.playlist_create(uri?, playQueueId?, fields?)— create a playlist from a URI, play queue, or query metadata.playlist_update(playlistId, fields)— update a playlist using a non-empty query-field object.playlist_delete(playlistId, confirm)— permanently delete a playlist.playlist_list_items(playlistId, types?, offset?, limit?)— list playlist items with optional media types and pagination.playlist_add_items(playlistId, uri?, playQueueId?)— add items; eitheruriorplayQueueIdis required.playlist_clear_items(playlistId, confirm)— permanently clear all playlist items.playlist_move_item(playlistId, playlistItemId, after?)— move an item to the beginning or after another item.
Playlist fields are intentionally open query metadata because the Plex OpenAPI contract omits editable playlist fields. Reserved authentication and curated parameter names are still rejected.
Tool result compatibility
Successful tools return the same complete Plex data in two forms: structuredContent for hosts that support structured MCP results, and one text block containing the summary followed by a newline and compact JSON for hosts that read text content only. Large listings therefore appear in both channels; use pagination to control result size.
Restricted raw request
When PLEX_ENABLE_RAW_REQUEST=true, the server additionally registers:
plex_raw_request(method, path, query?, body?, confirm?)— sendGET,POST,PUT,PATCH, orDELETEto a validated root-relative path.
Raw requests always stay on the configured PLEX_URL origin and always use the configured authentication headers. Schemes, hosts, credentials, protocol-relative paths, backslashes, and unsafe dot segments are rejected. A supplied body is sent as JSON.
query accepts either an object of scalar/repeated scalar values or an application/x-www-form-urlencoded string, with or without one leading ?. Form-string values remain strings, duplicate keys are preserved as repeated parameters, + decodes as a space, and percent escapes are decoded then canonically re-encoded. Reserved Plex authentication and prototype-related keys are rejected in either form.
The form string and query object below produce the same repeated type parameters:
{ "method": "GET", "path": "/library/sections/7/collections", "query": "?type=1&type=4&title=Road+Trip" }
{ "method": "GET", "path": "/library/sections/7/collections", "query": { "type": [1, 4], "title": "Road Trip" } }Confirmation behavior
Every destructive curated tool requires the literal boolean confirm: true before it sends a request. This applies to section deletion, metadata deletion, emptying trash, playlist deletion, and clearing playlist items. DELETE through plex_raw_request also requires confirm: true. Missing or false confirmation returns an MCP tool error without contacting Plex.
Troubleshooting
PLEX_URL is requiredorPLEX_TOKEN is required: add the missing value to the MCP host'senvobject, then restart the server.PLEX_URL must be an absolute HTTP(S) origin: use only the origin, such ashttp://127.0.0.1:32400, without a trailing API path or embedded credentials.- Timeout errors: confirm Plex is reachable from the MCP host and, if needed, increase
PLEX_REQUEST_TIMEOUT_MS. - Authentication or permission errors: create or retrieve a valid Plex token and verify the token can perform the requested operation directly against that server.
plex_raw_requestis not listed: setPLEX_ENABLE_RAW_REQUESTexactly totrueand restart the MCP server.- Protocol/JSON errors from the host: ensure wrappers and launch scripts do not write banners or logs to stdout.
Security
- Treat
PLEX_TOKENas a secret. Keep tokens environment-only; do not place them in tool arguments, source files, logs, issue reports, or committed configuration. - Prefer loopback or a trusted private network, HTTPS where appropriate, and a least-privilege Plex token.
- Review every destructive call before setting
confirm: true. - Leave raw access disabled unless a curated tool cannot perform the operation, and validate the requested path and effect before use.
- Tool errors and startup errors are sanitized, but host environment storage and operating-system process access remain part of your local trust boundary.
Development and release verification
npm ci
npm run lint
npm run typecheck
npm test
npm run build
npm run test:stdio
npm run test:package
npm pack --dry-run
npm audit --omit=devprepack builds fresh compiled output. The package allowlist is limited to dist/, this README, the MIT license, and npm's package metadata. Publishing is a separate, explicitly authorized release step; none of the commands above publishes a package.
License
MIT © 2026 Plex Media Server MCP contributors. See LICENSE.
