plex-mcp-server

nahojnet/plex-mcp-server

3.2

If you are the rightful owner of plex-mcp-server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

Plex MCP Server is a production-ready HTTP server that integrates with the Plex Media Server API to provide read-only access to your Plex library using the Model Context Protocol (MCP).

Tools
22
Resources
0
Prompts
0

Plex MCP Server

A production-ready Model Context Protocol (MCP) HTTP server with Plex Media Server API integration. This server provides read-only access to your Plex library through the standardized MCP protocol with HTTP streaming support.

Features

  • MCP Protocol Compliant: Implements the Model Context Protocol specification (2024-11-05) with HTTP streaming
  • Plex API Integration: Read-only access to 22 Plex API endpoints
  • Secure Authentication: Bearer token authentication (supports both "Bearer token" and "token" formats)
  • Docker Support: Fully containerized with Docker and Docker Compose
  • Production Ready: Includes security best practices, logging, health checks, and monitoring
  • Session Management: Automatic session handling with configurable timeouts
  • SSE Streaming: Server-Sent Events support for real-time communication

Table of Contents

Quick Start

  1. Clone the repository and navigate to the directory
  2. Copy .env.example to .env and configure your settings:
    cp .env.example .env
    
  3. Edit .env with your credentials:
    MCP_AUTH_TOKEN=your-secure-token-here
    PLEX_URL=http://localhost:32400
    PLEX_TOKEN=your-plex-token-here
    
  4. Start with Docker Compose:
    docker-compose up -d
    
  5. Test the server:
    curl -H "Authorization: Bearer your-secure-token-here" \
         http://localhost:3000/health
    

Installation

Using Docker Compose (Recommended)

This is the easiest method for deployment.

  1. Create .env file:

    cp .env.example .env
    
  2. Configure environment variables in .env:

    # Required
    MCP_AUTH_TOKEN=your-secure-random-token
    PLEX_URL=http://your-plex-server:32400
    PLEX_TOKEN=your-plex-authentication-token
    
    # Optional
    PORT=3000
    LOG_LEVEL=info
    
  3. Start the server:

    docker-compose up -d
    
  4. View logs:

    docker-compose logs -f
    
  5. Stop the server:

    docker-compose down
    

Using Docker

If you prefer to use Docker directly without Compose:

  1. Build the image:

    docker build -t plex-mcp-server .
    
  2. Run the container:

    docker run -d \
      --name plex-mcp-server \
      -p 3000:3000 \
      -e MCP_AUTH_TOKEN="your-token" \
      -e PLEX_URL="http://plex-server:32400" \
      -e PLEX_TOKEN="your-plex-token" \
      --restart unless-stopped \
      plex-mcp-server
    

Manual Installation

For local development or non-Docker deployments:

  1. Prerequisites:

    • Node.js 20.x or higher
    • npm or yarn
  2. Install dependencies:

    npm install
    
  3. Configure environment:

    cp .env.example .env
    # Edit .env with your settings
    
  4. Build the project:

    npm run build
    
  5. Start the server:

    npm start
    

    Or for development with auto-reload:

    npm run dev
    

Configuration

Environment Variables

All configuration is done through environment variables:

Required Variables
VariableDescriptionExample
MCP_AUTH_TOKENAuthentication token for MCP servera3f8d9c2b1e4...
PLEX_URLURL to your Plex Media Serverhttp://localhost:32400
PLEX_TOKENPlex authentication tokenxyz123abc456...
Optional Variables
VariableDescriptionDefault
PORTServer listening port3000
HOSTServer binding address127.0.0.1 (Docker: 0.0.0.0)
MCP_ENDPOINTMCP endpoint path/mcp
ALLOWED_ORIGINSCORS allowed origins (comma-separated)http://localhost:*,http://127.0.0.1:*
LOG_LEVELLogging level (error, warn, info, debug)info

Getting Your Plex Token

To find your Plex authentication token:

  1. Sign in to your Plex Web App
  2. Open any media item
  3. Click "Get Info" or press i
  4. Click "View XML"
  5. Look for X-Plex-Token in the URL

Or follow the official Plex guide.

Generating a Secure Auth Token

Generate a secure random token for MCP_AUTH_TOKEN:

# Using OpenSSL
openssl rand -hex 32

# Using Node.js
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

# Using Python
python3 -c "import secrets; print(secrets.token_hex(32))"

API Documentation

MCP Protocol

The server implements the Model Context Protocol over HTTP with the following endpoints:

  • POST /mcp - Send JSON-RPC requests
  • GET /mcp - Open SSE stream (requires session)
  • DELETE /mcp - Terminate session
  • GET /health - Health check (no auth required)

Authentication

Include your token in the Authorization header:

# With "Bearer" prefix
Authorization: Bearer your-token-here

# Without "Bearer" prefix (also supported)
Authorization: your-token-here

MCP Methods

Initialize Session
{
  "jsonrpc": "2.0",
  "method": "initialize",
  "params": {},
  "id": 1
}
List Available Tools
{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "params": {},
  "id": 2
}
Call a Tool
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "plex_get_server_info",
    "arguments": {}
  },
  "id": 3
}

Available Tools

The server provides 22 read-only tools for accessing Plex data:

Tool NameDescriptionRequired Arguments
plex_get_server_infoGet server information and capabilitiesNone
plex_get_identityGet server identityNone
plex_get_all_preferencesGet all server preferencesNone
plex_get_preferenceGet a specific preferenceid
plex_get_library_sectionsGet all library sectionsNone
plex_get_library_sectionGet a specific library sectionsectionId
plex_get_library_section_itemsGet items in a library sectionsectionId
plex_get_metadataGet metadata for a specific itemratingKey
plex_get_metadata_childrenGet children of a metadata itemratingKey
plex_get_activitiesGet current server activitiesNone
plex_get_butler_tasksGet Butler maintenance tasksNone
plex_get_global_hubsGet global content hubsNone
plex_get_continue_watchingGet continue watching itemsNone
plex_search_librarySearch across librariesquery
plex_get_sessionsGet active playback sessionsNone
plex_get_statisticsGet media statisticsNone
plex_get_playlistsGet all playlistsNone
plex_get_playlist_itemsGet items in a playlistplaylistId
plex_get_recently_addedGet recently added itemsNone
plex_get_on_deckGet on deck itemsNone
plex_get_collectionsGet collections in a sectionsectionId
plex_searchSearch all librariesquery

Usage Examples

Example 1: Get Server Information
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-token" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "plex_get_server_info",
      "arguments": {}
    },
    "id": 1
  }'
Example 2: Search Library
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: your-token" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "plex_search",
      "arguments": {
        "query": "Inception",
        "limit": 10
      }
    },
    "id": 2
  }'
Example 3: Get Recently Added
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-token" \
  -H "Accept: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "plex_get_recently_added",
      "arguments": {}
    },
    "id": 3
  }'
Example 4: Using SSE Streaming
# First, initialize a session
RESPONSE=$(curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-token" \
  -H "Accept: text/event-stream" \
  -d '{"jsonrpc": "2.0", "method": "initialize", "id": 1}' \
  -D -)

# Extract session ID from response headers
SESSION_ID=$(echo "$RESPONSE" | grep -i "mcp-session-id" | cut -d' ' -f2 | tr -d '\r')

# Open SSE stream
curl -N http://localhost:3000/mcp \
  -H "Authorization: Bearer your-token" \
  -H "Mcp-Session-Id: $SESSION_ID"

Security

Security Features

This server implements multiple security layers:

  1. Authentication: Bearer token authentication with constant-time comparison
  2. Origin Validation: CORS with configurable allowed origins to prevent DNS rebinding
  3. Non-Root User: Docker container runs as non-privileged user (UID 1001)
  4. Read-Only Filesystem: Container uses read-only root filesystem
  5. Resource Limits: CPU and memory limits in Docker Compose
  6. Security Headers: Helmet.js for security HTTP headers
  7. Input Validation: Request validation and sanitization
  8. Session Management: Automatic session expiration (24 hours)
  9. Rate Limiting: Recommended to add reverse proxy with rate limiting

Security Best Practices

  1. Use Strong Tokens: Generate cryptographically secure random tokens
  2. HTTPS in Production: Always use HTTPS in production environments
  3. Firewall: Restrict access to the server port
  4. Reverse Proxy: Use nginx/Traefik with rate limiting and SSL termination
  5. Regular Updates: Keep dependencies and base images updated
  6. Monitor Logs: Review logs for unauthorized access attempts
  7. Network Isolation: Run in isolated Docker network when possible

Recommended Nginx Configuration

upstream plex_mcp {
    server localhost:3000;
}

server {
    listen 443 ssl http2;
    server_name mcp.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=mcp_limit:10m rate=10r/s;
    limit_req zone=mcp_limit burst=20 nodelay;

    location /mcp {
        proxy_pass http://plex_mcp;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # SSE support
        proxy_buffering off;
        proxy_read_timeout 86400;
    }
}

Troubleshooting

Common Issues

Connection Refused

Problem: Cannot connect to the server

Solutions:

  • Check if the container is running: docker-compose ps
  • Verify port mapping: docker-compose port plex-mcp-server 3000
  • Check firewall rules
  • Ensure HOST is set to 0.0.0.0 in Docker
Authentication Failed

Problem: 401 Unauthorized error

Solutions:

  • Verify MCP_AUTH_TOKEN matches in client and server
  • Check Authorization header format
  • Ensure token doesn't contain extra whitespace
Plex Connection Error

Problem: Cannot connect to Plex server

Solutions:

  • Verify PLEX_URL is correct and accessible
  • Check PLEX_TOKEN is valid
  • Ensure Plex server is running
  • Check network connectivity between containers
  • Verify firewall rules for Plex port
Session Expired

Problem: 404 Session not found

Solutions:

  • Re-initialize session
  • Check session timeout settings (24 hours default)
  • Verify Mcp-Session-Id header is being sent

Debugging

Enable debug logging:

# In .env
LOG_LEVEL=debug

# Or in docker-compose.yml
environment:
  - LOG_LEVEL=debug

View detailed logs:

# Docker Compose
docker-compose logs -f --tail=100

# Docker
docker logs -f plex-mcp-server

Health Check

Check server health:

curl http://localhost:3000/health

Expected response:

{
  "status": "ok",
  "timestamp": "2024-01-01T12:00:00.000Z"
}

Development

Project Structure

plex-mcp-server/
├── src/
│   ├── index.ts          # Application entry point
│   ├── server.ts         # MCP HTTP server implementation
│   ├── auth.ts           # Authentication middleware
│   ├── config.ts         # Configuration management
│   ├── logger.ts         # Logging configuration
│   ├── plex-client.ts    # Plex API client
│   └── tools.ts          # MCP tools definitions
├── Dockerfile            # Docker image definition
├── docker-compose.yml    # Docker Compose configuration
├── package.json          # Node.js dependencies
├── tsconfig.json         # TypeScript configuration
├── .env.example          # Environment variables template
└── README.md            # This file

Development Setup

  1. Clone and install:

    git clone <repository-url>
    cd plex-mcp-server
    npm install
    
  2. Configure environment:

    cp .env.example .env
    # Edit .env with your settings
    
  3. Run in development mode:

    npm run dev
    
  4. Build:

    npm run build
    
  5. Lint:

    npm run lint
    

Testing with MCP Inspector

You can test the server using the MCP Inspector tool:

npx @modelcontextprotocol/inspector http://localhost:3000/mcp

Adding New Tools

To add a new Plex API endpoint:

  1. Add method to PlexClient (src/plex-client.ts):

    async getNewEndpoint(param: string): Promise<any> {
      const response = await this.client.get('/new/endpoint', { params: { param } });
      return response.data;
    }
    
  2. Add tool definition (src/tools.ts):

    {
      name: 'plex_get_new_endpoint',
      description: 'Description of the endpoint',
      inputSchema: {
        type: 'object',
        properties: {
          param: { type: 'string', description: 'Parameter description' }
        },
        required: ['param']
      }
    }
    
  3. Add tool handler (src/tools.ts):

    case 'plex_get_new_endpoint':
      return await plexClient.getNewEndpoint(args.param);
    

Architecture

Technology Stack

  • Runtime: Node.js 20.x (Alpine Linux)
  • Language: TypeScript 5.x
  • Framework: Express.js
  • HTTP Client: Axios
  • Logging: Winston
  • Security: Helmet.js
  • Container: Docker with multi-stage builds

MCP Protocol Flow

Client                          MCP Server                    Plex Server
  |                                 |                              |
  |-- POST /mcp (initialize) ------>|                              |
  |<-- Mcp-Session-Id --------------|                              |
  |                                 |                              |
  |-- POST /mcp (tools/list) ------>|                              |
  |<-- Available tools -------------|                              |
  |                                 |                              |
  |-- POST /mcp (tools/call) ------>|                              |
  |                                 |-- GET /api/endpoint -------->|
  |                                 |<-- Plex data ----------------|
  |<-- Tool result -----------------|                              |
  |                                 |                              |
  |-- GET /mcp (SSE stream) ------->|                              |
  |<-- SSE events (ongoing) --------|                              |

Performance

Resource Usage

  • Memory: ~50-100MB idle, ~200MB under load
  • CPU: Minimal (<5% on modern hardware)
  • Network: Depends on Plex API response sizes

Scaling

For high-traffic scenarios:

  • Deploy multiple instances behind a load balancer
  • Use Redis for shared session storage
  • Enable connection pooling for Plex API
  • Implement response caching

License

MIT License - See LICENSE file for details

Support

For issues, questions, or contributions:

  • Open an issue on GitHub
  • Check existing issues for solutions
  • Review logs for error details

Acknowledgments


Note: This server provides read-only access to Plex. No data modification, deletion, or server configuration changes are possible through this MCP server.