Portainer MCP Docker

Dockerized Portainer MCP Server (stdio/streamable HTTP) for easy deployment alongside Portainer

portainer-mcp-docker

Dockerized version of the Portainer MCP Server for easy deployment.

Instead of manually downloading and managing binaries, this project provides minimal Alpine-based Docker images that can be deployed alongside Portainer using Docker Compose.

Features

  • Minimal Alpine Linux image with the official portainer-mcp binary
  • Two variants: stdio (local) and HTTP (remote/web)
  • Multi-architecture support (linux/amd64, linux/arm64)
  • Automatic updates via GitHub Actions when new upstream releases are published
  • Base image updates via Dependabot with auto-merge (security patches, Alpine updates)
  • Versioned tags matching the upstream release (e.g., v0.7.0-1)

Image Variants

Image TagTransportUse Case
latest / v0.7.0-1stdioLocal MCP clients (Claude Desktop, Claude Code CLI)
http / v0.7.0-1-httpStreamable HTTPRemote access (Claude Web, shared servers)

stdio (default)

The standard image. MCP clients launch the container and communicate over stdin/stdout. Best for local setups where the MCP client runs on the same machine.

HTTP

Wraps the MCP server with mcp-proxy to expose it over Streamable HTTP. Supports bearer token authentication so the endpoint is not publicly accessible. Best for remote access, e.g., connecting from Claude Web to a Portainer instance on your server.

Installation

Prerequisites

  • A running Portainer instance
  • A Portainer API access token (generated from the Portainer UI under My Account > Access Tokens)
  • Docker and Docker Compose

stdio Variant (Local)

Quick Start

docker pull ghcr.io/serraniel/portainer-mcp-docker:latest

docker run -i --rm ghcr.io/serraniel/portainer-mcp-docker:latest \
  -server your-portainer:9443 \
  -token your-api-token

Networking: Portainer on the Same Host

When Portainer runs on the same machine as the MCP container, localhost inside the container refers to the container itself, not the host. Use host.docker.internal instead:

docker run -i --rm \
  --add-host=host.docker.internal:host-gateway \
  ghcr.io/serraniel/portainer-mcp-docker:latest \
  -server host.docker.internal:9443 \
  -token your-api-token

MCP Client Configuration

Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "portainer": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--add-host=host.docker.internal:host-gateway",
        "ghcr.io/serraniel/portainer-mcp-docker:latest",
        "-server", "host.docker.internal:9443",
        "-token", "your-api-token"
      ]
    }
  }
}

Replace host.docker.internal:9443 with your Portainer's actual hostname:port if it runs on a different machine.

Claude Code

Add to your Claude Code MCP settings:

{
  "mcpServers": {
    "portainer": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--add-host=host.docker.internal:host-gateway",
        "ghcr.io/serraniel/portainer-mcp-docker:latest",
        "-server", "host.docker.internal:9443",
        "-token", "your-api-token"
      ]
    }
  }
}

HTTP Variant (Remote)

Generating Tokens

The HTTP variant requires two tokens:

  1. Portainer API token (PORTAINER_TOKEN) — authenticates the MCP server against your Portainer instance. Generate one in the Portainer UI under My Account > Access Tokens > Add access token.

  2. MCP bearer token (API_ACCESS_TOKEN) — protects the HTTP endpoint so only authorized MCP clients can connect. This is a secret you create yourself. Generate a secure random token:

openssl rand -hex 32

Use the output as your MCP_API_TOKEN in the .env file and configure the same value in your MCP client's Authorization: Bearer <token> header.

Quick Start

docker pull ghcr.io/serraniel/portainer-mcp-docker:http

docker run -d --rm \
  -p 8080:8080 \
  -e PORTAINER_SERVER=your-portainer:9443 \
  -e PORTAINER_TOKEN=your-portainer-api-token \
  -e API_ACCESS_TOKEN=your-mcp-bearer-token \
  ghcr.io/serraniel/portainer-mcp-docker:http

Docker Compose

services:
  portainer:
    image: portainer/portainer-ce:latest
    restart: always
    ports:
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

  portainer-mcp:
    image: ghcr.io/serraniel/portainer-mcp-docker:http
    restart: always
    ports:
      - "8080:8080"
    environment:
      - PORTAINER_SERVER=portainer:9443
      - PORTAINER_TOKEN=${PORTAINER_TOKEN}
      - API_ACCESS_TOKEN=${MCP_API_TOKEN}
      # Optional:
      # - PORTAINER_READ_ONLY=true
      # - PORTAINER_DISABLE_VERSION_CHECK=true
      # - MCP_PORT=8080
      # - MCP_HOST=0.0.0.0

volumes:
  portainer_data:

Create a .env file:

PORTAINER_TOKEN=your-portainer-api-token
MCP_API_TOKEN=your-mcp-bearer-token

MCP Client Configuration (Remote)

Claude Web / Claude Desktop (Remote URL)

Configure your MCP client to connect to the HTTP endpoint:

  • URL: http://your-server:8080/sse
  • Authorization: Bearer token (the MCP_API_TOKEN you configured)

Claude Code (Remote)

{
  "mcpServers": {
    "portainer": {
      "type": "url",
      "url": "http://your-server:8080/sse",
      "headers": {
        "Authorization": "Bearer your-mcp-bearer-token"
      }
    }
  }
}

Environment Variables (HTTP)

VariableRequiredDescription
PORTAINER_SERVERYesPortainer server address as host:port (no protocol prefix, HTTPS is used automatically)
PORTAINER_TOKENYesPortainer API access token
API_ACCESS_TOKENRecommendedBearer token for MCP endpoint authentication
PORTAINER_READ_ONLYNoSet to true for read-only mode
PORTAINER_DISABLE_VERSION_CHECKNoSet to true to skip version validation
MCP_PORTNoHTTP listen port (default: 8080)
MCP_HOSTNoHTTP listen address (default: 0.0.0.0)

Command Line Options (stdio)

All flags from the upstream binary are supported:

FlagDescription
-server <host:port>Portainer server address, without protocol prefix (required)
-token <token>Portainer API access token (required)
-tools <path>Path to custom tools YAML file
-read-onlyRestrict to read-only operations (GET requests only)
-disable-version-checkSkip Portainer server version validation

Versioning

Image tags follow the format v<upstream>-<build>:

  • v0.7.0-1 - First build of upstream v0.7.0 (stdio)
  • v0.7.0-1-http - Same version, HTTP variant
  • v0.7.0-2 - Rebuild (e.g., base image security update)
  • latest - Most recent stdio build
  • http - Most recent HTTP build

How Automatic Updates Work

TriggerWhat happens
New upstream releaseDaily check creates a new tag (e.g., v0.8.0-1) and builds both images
Dependabot PR mergedAuto-merged after build test, increments build number and rebuilds
Manual dispatchWorkflow can be triggered manually with a specific upstream version

Upstream Documentation

For full documentation on the Portainer MCP server capabilities, tools, and Portainer version compatibility, see the upstream README.

License

This project is licensed under the European Union Public License v1.2 (EUPL-1.2).

The upstream portainer-mcp binary is licensed under the Zlib License.

Server Terkait