Skip to main content
Glama
CarlDog
by CarlDog

plex-mcp

code confidence · claude-opus-4-8[1m] · 2026-07-07 · подробности

MCP-сервер для Plex Media Server, упакованный в Docker-контейнер. Позволяет MCP-клиенту (Claude Desktop и т. д.) просматривать и искать в ваших библиотеках Plex.

Инструменты

Tool

Описание

plex_list_libraries

Список всех библиотек (разделов) на сервере

plex_search

Поиск по всем библиотекам

plex_hub_search

Поиск через эндпоинт hub-search в Plex, включая коллекции (в отличие от plex_search)

plex_recently_added

Недавно добавленные элементы, опционально по разделам

plex_on_deck

Элементы «on deck» (частично просмотренные / следующие); опциональный section_id ограничивает одну секцию библиотеки

plex_get_item

Метаданные для элемента по rating key. Передайте minimal=true, чтобы убрать громоздкие массивы актёров/съёмочной группы/изображений (~80% уменьшение размера для фильмов с большим актёрским составом) с сохранением информации о дорожках субтитров; передайте fields=[...] для явной проекции

plex_browse

Список элементов в секции библиотеки (постранично, опциональный фильтр по типу, опциональный фильтр по названию коллекции, опциональная разреженная fields проекция)

plex_list_collections

Список коллекций в секции библиотеки (тонкая обёртка над типом коллекции из plex_browse)

plex_get_children

Дочерние элементы элемента (сериал→сезоны, сезон→эпизоды, артист→альбомы)

plex_now_playing

Текущие сеансы воспроизведения на сервере

plex_history

Записи истории воспроизведения (постранично, сначала новые)

plex_mark_watched

Отметить элемент как просмотренный (обратимо)

plex_mark_unwatched

Отметить элемент как непросмотренный (обратимо)

plex_rate_item

Установить пользовательскую рейтинговую оценку элемента от 0 до 10; опустите rating, чтобы вернуть его к неоценённому состоянию

plex_list_playlists

Список всех плейлистов (обычные + умные)

plex_get_playlist_items

Список содержимого плейлиста

plex_create_playlist

Создать обычный плейлист, начинающийся с одного элемента

plex_add_to_playlist

Добавить элемент в конец обычного плейлиста

plex_remove_from_playlist

Удалить элемент по playlistItemID

plex_delete_playlist

Удалить плейлист (только метаданные — медиа не затрагивается)

plex_hubs

Курируемые Plex серверные хабы (Continue Watching, Recently Released и т.д.)

plex_section_hubs

Курируемые хабы, ограниченные одной секцией библиотеки

plex_related

Курируемые Plex хабы «похожие» для элемента (сгруппированные по источнику)

plex_similar

Алгоритмическая рекомендательная аналога для элемента (плоский список)

plex_refresh_metadata

Повторно получить метаданные для элемента из его текущего агента (опционально force)

plex_get_matches

Список возможных совпадений для элемента (TMDB / TVDB / и т.д.); опциональные переопределения title/year/agent/language

plex_apply_match

Применить выбранное совпадение (guid/name) к элементу; перезаписывает привязку агента

plex_edit_metadata

Переопределить скалярные поля метаданных (title, summary, year и т.д.) с блокировкой на уровне полей

plex_unmatch

Отвязать элемент от привязки агента (вернуть в состояние без совпадения); заблокированные поля сохраняются

plex_refresh_section

Запустить обновление метаданных для целой секции библиотеки (инкрементальное или полное)

plex_split_item

Разделить элемент Plex обратно на составляющие его медиа-варианты как N отдельных элементов

plex_merge_items

Объединить другие элементы в целевой элемент (исходные поглощаются; целевой сохраняется)

plex_get_image

Получить байты постера/арта/баннера/clearLogo для элемента как MCP-блок изображения (чтобы клиенты со зрительными возможностями могли видеть картинку); опциональные max_width/max_height направляются через транскодер Plex

plex_save_image

Та же входная поверхность, что у plex_get_image, но ЗАПИСЫВАЕТ байты на диск в MCP_IMAGE_SAVE_DIR (по умолчанию /data/images/) и возвращает путь + размер. Примонтируйте bind-mount хост-каталога в этот путь, чтобы связать его с последующим конвейером (ImageMagick, consumer filesystem-mcp и т.д.) без визуальной отрисовки.

plex_download_logs

Получить собственный пакет диагностических журналов Plex Media Server (ZIP) и записать его на диск в MCP_LOG_SAVE_DIR (по умолчанию /data/logs/)

plex_list_posters

Список всех кандидатов на постер для элемента (предоставленные агентом, локально отсканированные, ранее загруженные), включая тот, который сейчас активен

plex_set_poster

Выбрать существующего кандидата в постеры как активного по его собственному poster_rating_key из plex_list_posters (не имеет обратного)

plex_upload_poster

Добавить новый постер с внешнего URL (Plex его загружает) или локального файла в MCP_IMAGE_SAVE_DIR. По умолчанию автоматически выбирает его; select=false добавляет его без изменения текущего отображаемого постера

Related MCP server: Plex Assistant MCP

Конфигурация

Две переменные окружения, обе обязательные:

Var

Example

Notes

PLEX_URL

http://192.168.1.50:32400

Базовый URL вашего Plex-сервера

PLEX_TOKEN

(см. ниже)

Токен аутентификации Plex

Чтобы найти токен Plex, см. руководство Plex Поиск токена аутентификации.

Необязательные переменные окружения

У всех есть рабочие значения по умолчанию; задавайте их только для переопределения.

Var

Default

Notes

MCP_FETCH_TIMEOUT_MS

30000

Таймаут для каждого исходящего запроса к Plex, кроме загрузки логов

MCP_IMAGE_MAX_BYTES

4194304 (4 MiB)

Максимальный размер для plex_get_image/plex_save_image

MCP_LOG_MAX_BYTES

52428800 (50 MiB)

Максимальный размер для plex_download_logs

MCP_LOG_FETCH_TIMEOUT_MS

120000 (2 мин)

Таймаут для plex_download_logs — отдельно от MCP_FETCH_TIMEOUT_MS, поскольку ZIP-архив логов имеет иной профиль размера/задержки

MCP_SESSION_IDLE_TIMEOUT_MS

3600000 (1 ч)

Вытесняет MCP-сессию в HTTP-режиме после такого периода бездействия

LOG_LEVEL, MCP_ALLOWED_HOSTS/MCP_ALLOWED_ORIGINS и HOST_IMAGE_DIR/HOST_LOG_DIR описаны в отдельных разделах ниже (журналирование, усиление HTTP-транспорта, развертывание в Portainer), поскольку каждому из них нужно больше, чем однострочное примечание.

Plex на том же хосте, что и контейнер? Используйте PLEX_URL=http://host.docker.internal:32400. В compose-файле host.docker.internal сопоставляется со шлюзом хоста Docker через extra_hosts, поэтому контейнер может обратиться к серверу Plex, работающему на хосте. Собственное имя хоста (например, my-nas) не будет резолвиться из контейнера без такого сопоставления.

Режимы транспорта

Mode

Когда использовать

Как запустить

stdio (по умолчанию)

Прямой вызов из Claude Desktop / MCP-клиентов

docker run -i --rm ... plex-mcp (без MCP_PORT)

Streamable HTTP

Долгоживущее развертывание (Portainer, Compose, k8s)

Задайте MCP_PORT=3000 (уже сделано в docker-compose.yml)

В HTTP-режиме сервер предоставляет:

  • POST/GET/DELETE /mcp — конечная точка MCP Streamable HTTP (по спецификации)

  • GET /health — проверка живости (используется docker healthcheck)

В HTTP-режиме нет аутентификации вызывающей стороны — TLS (см. ниже) шифрует трафик, но не идентифицирует вызывающего. Привязывайте только к частной сети. Полагайтесь на межсетевой экран хоста или изоляцию LAN. Не открывайте доступ в публичный интернет без добавления авторизации через bearer-токен.

Включение HTTPS

HTTPS включается по желанию. Порядок разрешения при запуске:

  1. Свой сертификат — задайте и MCP_TLS_CERT_FILE, и MCP_TLS_KEY_FILE, указав пути к PEM-файлам. Используйте этот вариант при завершении TLS для Let's Encrypt или внутреннего УЦ. Сервер читает их при запуске; перезапустите контейнер, чтобы подхватить обновленные файлы.

  2. Самоуправляемый сертификат (рекомендуется для настроек только в LAN) — задайте MCP_TLS=auto. Сервер генерирует самоподписанный сертификат ECDSA P-256 при первом запуске, записывает его в MCP_TLS_DIR (по умолчанию /data/certs) и использует его повторно при последующих запусках. Когда до истечения срока действия сертификата останется менее 30 дней, он автоматически пересоздается.

  3. В противном случае сервер остается на обычном HTTP (текущее поведение по умолчанию).

Var

Default

Notes

MCP_TLS

не задано

auto / true / on / 1 для включения самоуправляемого режима

MCP_TLS_DIR

/data/certs

Где находятся server.crt / server.key. Смонтируйте том для сохранения.

MCP_TLS_SAN

DNS:localhost,IP:127.0.0.1

Имена субъектов (SAN). Разделенные запятыми записи DNS: / IP:.

MCP_TLS_CN

первый DNS SAN, иначе plex-mcp

Общее имя сертификата.

MCP_TLS_DAYS

365

Срок действия. Сертификат ротируется, когда остается <30 дней.

MCP_TLS_CERT_FILE

не задано

Свой сертификат (PEM). Переопределяет MCP_TLS=auto, если задан вместе с ключом.

MCP_TLS_KEY_FILE

не задано

Свой ключ (PEM).

При запуске сервер логирует SHA-256 отпечаток сертификата и notAfter. Закрепите отпечаток на стороне клиента или доверьтесь сертификату в хранилище ключей ОС для браузеров и CLI-инструментов.

Когда TLS включен, healthcheck в compose требует флаг --no-check-certificate — обновите строку test: до ["CMD", "wget", "--no-check-certificate", "-q", "-O-", "https://localhost:3000/health"].

Настройка mcp-remote на HTTPS-конечную точку

Для самоподписанного сертификата либо закрепите файл сертификата через CA-бандл Node, либо отключите проверку на клиенте (только для LAN):

# 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/mcp

Альтернатива через обратный прокси

Встроенный TLS удобен, если у вас уже нет контроллера входящего трафика. Если перед вашими домашними сервисами стоит Caddy, Traefik или nginx, более идиоматичный подход — завершать TLS на прокси (с автоматическим Let's Encrypt), а plex-mcp оставлять на обычном HTTP за ним. Оба подхода взаимозаменяемы — выбирайте тот, который соответствует вашей существующей настройке.

Авторизация OAuth 2.1 по bearer-токену (опционально, пока практически неприменима)

Поддержка на стороне кода для защиты ресурсов OAuth 2.1 существует (согласование с ChatGPT Apps SDK, этап 2 — полный план см. в docs/CHATGPT-APPS-SDK.md), но это пока нельзя реально включить и использовать: нужен настоящий поставщик удостоверений OAuth 2.1, выпускающий токены, а для этого развертывания он не предусмотрен (это этап 3, не начат). Здесь описано для полноты, а не как инструкция.

Var

Notes

MCP_OAUTH_ISSUER

URL эмитента IdP. Установка этого параметра включает аутентификацию — если не задано (по умолчанию), аутентификация отсутствует, как и сегодня.

MCP_OAUTH_AUDIENCE

Обязательно, если задан MCP_OAUTH_ISSUER. Ожидаемое значение claim aud — должно равняться каноническому публичному URL этого сервера. Сервер отказывается запускаться, если параметр отсутствует.

MCP_OAUTH_REQUIRED_SCOPES

Через запятую. По умолчанию plex:read.

Когда включено, каждый запрос /mcp должен содержать Authorization: Bearer <jwt> — выданный настроенным IdP, с правильной аудиторией и областью. /health не затрагивается (это отдельный маршрут, и собственный healthcheck Docker не имеет возможности прикрепить bearer-токен). /.well-known/oauth-protected-resource обслуживается автоматически согласно RFC 9728.

Запуск с Docker (stdio, по требованию)

docker build -t plex-mcp .
docker run -i --rm \
  -e PLEX_URL=http://192.168.1.50:32400 \
  -e PLEX_TOKEN=your-token \
  plex-mcp

Запуск с Docker Compose (HTTP, долгоживущий)

Compose-файл тянет образ ghcr.io/carldog/plex-mcp:latest (мультиархитектурный: linux/amd64 + linux/arm64), публикуемый CI при каждом пуше в main.

# Required env vars (or use a .env file):
export PLEX_URL=http://192.168.1.50:32400
export PLEX_TOKEN=your-token
export MCP_ALLOWED_HOSTS=nas.local:3001  # required — see below
export HOST_PORT=3001  # optional, defaults to 3001

docker compose up

Конечная точка MCP будет доступна по адресу http://<host>:${HOST_PORT}/mcp.

Чтобы пересобрать из исходников вместо скачивания образа:

docker build -t ghcr.io/carldog/plex-mcp:latest .
docker compose up

Развертывание через Portainer (Stack из Git)

  1. В Portainer: Стеки → Добавить стек → Репозиторий.

  2. URL репозитория: https://github.com/CarlDog/plex-mcp

  3. Путь к Compose-файлу: docker-compose.yml

  4. Переменные окружения: задайте PLEX_URL, PLEX_TOKEN, MCP_ALLOWED_HOSTS, HOST_IMAGE_DIR и HOST_LOG_DIR — все обязательны (см. ниже); опционально HOST_PORT.

  5. Разверните. Healthcheck становится зеленым примерно через 10 секунд.

MCP_ALLOWED_HOSTS обязателен в HTTP-режиме

Список значений заголовка Host, разделенных запятыми, которые сервер принимает на /mcp — например, nas.local:3001 (должен совпадать с фактическим host:port, который использует клиент, включая проброшенный HOST_PORT). Без него сервер отказывается запускаться в HTTP-режиме, и docker compose config также завершается ошибкой, если он не задан — оба случая намеренно завершаются до запуска контейнера, а не запускаются в состоянии, незаметно лишенном защиты.

Это сделано потому, что привязка 0.0.0.0 внутри контейнера не является реальной границей доступа, в отличие от привязки к loopback на обычном хосте: страница, загруженная в браузере в любом месте LAN, может выполнить DNS-ребендинг — указав собственное имя хоста на IP этого контейнера — и использовать инструменты (включая операции записи, такие как plex_delete_playlist) в роли запутанного посредника, полностью обходя "только-LAN, без bearer-токена" как модель безопасности. Список разрешенных Host закрывает эту брешь без необходимости полной аутентификации. MCP_ALLOWED_ORIGINS (необязательно, по умолчанию пусто) делает то же самое для заголовка Origin — оставьте его незаданным, если только браузерный клиент действительно не должен вызывать этот сервер напрямую; небраузерные клиенты (мост mcp-remote, прямой fetch) никогда не отправляют заголовок Origin, поэтому пустое значение по умолчанию отвергает только ту форму запроса, которую реально отправляет DNS-ребендинговая атака.

HOST_IMAGE_DIR и HOST_LOG_DIR обязательны — относительного значения по умолчанию нет

Оба host-пути для томов заданы как ${VAR:?...} в compose-файле: запасного значения по умолчанию нет, поэтому docker compose up / повторное развертывание в Portainer быстро завершится с понятной ошибкой, если какой-либо из параметров не задан, а не запустится в нерабочем состоянии.

Раньше здесь использовалось мягкое значение по умолчанию ${VAR:-./data/images}, которое безопасно только для локального docker compose up из стабильного клона. В стеке Portainer из git это ловушка: каждое повторное развертывание клонирует репозиторий в свежую директорию для конкретного коммита (/data/compose/<stack-id>/<commit>/), где относительного пути вроде ./data/images не существует. Docker отклонял bind-mount, и контейнер оставался в состоянии created — он так и не запускался. Это также затрагивало автоматические повторные развертывания (обновление образа, git-поллинг), поэтому ранее здоровый стек падал без ручного вмешательства; единственным симптомом был контейнер в состоянии created. Из-за этого развернутый стек простоял около 10 часов 2026-07-31 — см. правило №10 в docker-deployments.md и урок для флота 2026-07-31-relative-compose-volume-defaults-break-portainer-git-stacks. Теперь compose-файл делает это требование структурным, а не просто соглашением из документации.

Задайте обе как абсолютные пути на хосте в переменных окружения стека:

  • HOST_IMAGE_DIR — каталог вывода для plex_save_image. Рекомендуется: каталог на хосте, обеспечивающий монтирование /media/_mcp-scratch для filesystem-mcp — например, /volume1/Media/_mcp-scratch на Synology NAS — так конвейер plex_search → plex_save_image → filesystem-mcp остаётся в одном общем каталоге.

  • HOST_LOG_DIR — каталог вывода для plex_download_logs, хранящийся отдельно от HOST_IMAGE_DIR, поскольку диагностический ZIP не является медиафайлом — например, /volume1/docker/plex-mcp/logs на Synology NAS (в соответствии с принятым в этом флоте правилом appdata для каждого контейнера).

Убедитесь, что оба каталога существуют на хосте до первого развёртывания: Docker не создаёт отсутствующий источник bind-mount автоматически, он просто отказывается запускать контейнер.

Использование с Claude Desktop

stdio (локальный вызов)

{
  "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 (удалённый MCP-сервер)

{
  "mcpServers": {
    "plex": {
      "url": "http://nas.local:3001/mcp"
    }
  }
}

(Требуется Claude Desktop или клиент, поддерживающий удалённый MCP по HTTP.)

Локальная разработка

npm install
cp .env.example .env  # then edit
PLEX_URL=... PLEX_TOKEN=... npm run dev               # stdio
MCP_PORT=3000 MCP_ALLOWED_HOSTS=localhost:3000 PLEX_URL=... PLEX_TOKEN=... npm run dev # HTTP

Логирование

Сервер отправляет структурированные логи в stderr (в stdio-режиме stdout — это транспорт для протокола MCP, и его нельзя засорять). Формат:

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=337

Настройте детализацию через переменную окружения LOG_LEVEL (по умолчанию info):

| error | Только ошибки | | warn | + Ответы Plex с кодом ошибки 4xx | | info (по умолчанию) | + Вызовы и завершения инструментов | | debug | + каждый вызов Plex API с методом, путём, статусом, ms | | trace | (зарезервировано) | | Level | Shows |

| ---------------- | --------------------------------------------------- | | error | Errors only | | warn | + 4xx Plex responses | | info (default) | + Tool invocations and completions | | debug | + Every Plex API call with method, path, status, ms | | trace | (reserved) |

Logging

Container logs are collected by Docker's json-file and rotated automatically (10MB × 3 files = ~30MB cap; oldest deleted on rotation). View with docker ls or docker ps.

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-commit runs gitleaks on every commit. Activate it once per clone: git config core.hooksPath .githooks

Each section and definition has been translated, keeping all technical identifiers (HOST_IMAGE_DIR, HOST_LOG_DIR, plex_save_image, filesystem-mcp, /media/_mcp-scratch, /volume1/Media/_mcp-scratch, Synology NAS, plex_download_logs, /volume1/docker/plex-mcp/logs, Claude Desktop, stdio, GXP5, GXP6, GXP7, GXP8, LOG_LEVEL, etc.) unchanged. The list structure, tables, and markdown emphasis are preserved. This translation replaces the English source and returns only the Russian text as output.* HOST_IMAGE_DIR — каталог вывода для plex_save_image. Рекомендуется: каталог на хосте, обеспечивающий монтирование /media/_mcp-scratch для filesystem-mcp — например, /volume1/Media/_mcp-scratch на Synology NAS — так конвейер plex_search → plex_save_image → filesystem-mcp остаётся в одном общем каталоге.

  • HOST_LOG_DIR — каталог вывода для plex_download_logs, хранящийся отдельно от HOST_IMAGE_DIR, поскольку диагностический ZIP не является медиафайлом — например, /volume1/docker/plex-mcp/logs на Synology NAS (в соответствии с принятым в этом флоте правилом хранения данных контейнеров).

Убедитесь, что оба каталога существуют на хосте до первого развёртывания: Docker не может автоматически создать отсутствующий bind-mount источник, он просто откажется запускать контейнер.

Использование с Claude Desktop

stdio (локальная отправка)

{
  "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 (удалённый MCP-сервер)

{
  "mcpServers": {
    "plex": {
      "url": "http://nas.local:3001/mcp"
    }
  }
}

(Требуется Claude Desktop или клиент, поддерживающий удалённый MCP по HTTP.)

Локальная разработка

npm install
cp .env.example .env  # then edit
PLEX_URL=... PLEX_TOKEN=... npm run dev               # stdio
MCP_PORT=3000 MCP_ALLOWED_HOSTS=localhost:3000 PLEX_URL=... PLEX_TOKEN=... npm run dev # HTTP

Логирование

Lighthouse | сервер выводит структурированные логи в stderr (в stdio-режиме stdout является транспортным каналом MCP и не должен загрязняться). Формат:

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=337

Настройка подробности через переменную окружения LOG_LEVEL (по умолчанию — info):

Уровень

Показывает

error

Только ошибки

warn

+ ответы Plex с кодом 4xx

info (по умолчанию)

+ вызовы и завершение инструментов

debug

+ каждый вызов API Plex с методом, путём, статусом, мс

trace

(зарезервировано)

Логи контейнеров сохраняются драйвером json-file Docker и ротируются автоматически (10MB × 3 файла = ~30MB; самый старый удаляется при ротации). Просмотр — docker logs plex-mcp или docker logs -f.

Безопасность

  • Контейнер запускается от непривилегированного пользователя (plexmcp).

  • Токен Plex передаётся через переменную окружения — никогда не вшивайте его в образ.

  • .githooks/pre-commit запускает gitleaks при каждом коммите. Активируйте его один раз для каждого клона: git config core.hooksPath .githooks

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables users to manage and control their Plex media library through natural language commands in MCP-compatible AI clients. It supports searching content, managing playlists, tracking library statistics, and monitoring live viewing sessions.
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server for reelgrep - browse and search your local video library from any MCP client.
    10 npm
    MIT