Skip to content

Repository files navigation

mcp-portainer

CI Docker Python 3.11+ License: MIT

An MCP (Model Context Protocol) server that connects to a remote Portainer instance, giving any MCP-compatible AI assistant or IDE full control over your Docker environments, stacks, containers, images, networks, and volumes.

Features

  • Environments — list and inspect Docker environments registered in Portainer
  • Stacks — create (from compose string or Git repo), update, redeploy, start, stop, delete
  • Containers — list, inspect, start, stop, restart, remove, fetch logs, run commands, read stats
  • Images — list, pull, remove
  • Networks — list, create, remove
  • Volumes — list, create, remove
  • Users & Teams — list, create, delete (admin)
  • Registries — list configured registries
  • System — status, version, settings

Works with Claude Desktop, VS Code (Continue, Copilot Chat), Cursor, Windsurf, Zed, and any other MCP-compatible client.


Prerequisites

  • Python 3.11+

  • uv — provides the uvx command used in all install options below

    curl -LsSf https://astral.sh/uv/install.sh | sh

    If you see ENOENT or "command not found: uvx" errors in your MCP client, this is the fix.


Quick start

Option A — uvx (no install required)

PORTAINER_URL=https://portainer.example.com \
PORTAINER_API_KEY=ptr_xxxx \
uvx mcp-portainer

Option B — uv / pip

# Install
pip install mcp-portainer
# or: uv add mcp-portainer

# Run
PORTAINER_URL=https://portainer.example.com \
PORTAINER_API_KEY=ptr_xxxx \
mcp-portainer

Option C — Docker (as a network service)

cp .env.example .env && $EDITOR .env
docker compose up -d

The server listens at http://localhost:8000/mcp using the streamable-http transport.


Configuration

All configuration is via environment variables (or a .env file in the working directory).

Variable Required Default Description
PORTAINER_URL Portainer base URL, e.g. https://portainer.example.com
PORTAINER_API_KEY ✅* API key (preferred). Generate in Portainer → User settings → Access tokens
PORTAINER_USERNAME ✅* Username (if not using API key)
PORTAINER_PASSWORD ✅* Password (if not using API key)
PORTAINER_VERIFY_SSL true Set false for self-signed certificates
PORTAINER_TIMEOUT 30 HTTP request timeout in seconds

*One of PORTAINER_API_KEY or PORTAINER_USERNAME+PORTAINER_PASSWORD is required.

Getting a Portainer API key: Portainer → top-right menu → My account → Access tokens → Add access token.


Integrating with AI clients

Claude Code (CLI) — one-liner install

claude mcp add portainer -s user \
  -e PORTAINER_URL=https://portainer.example.com \
  -e PORTAINER_API_KEY=ptr_xxxxxxxxxxxxxxxxxxxx \
  -- uvx --from git+https://github.com/jasonarends/mcp-portainer mcp-portainer

-s user makes it available across all your projects. uvx fetches and runs the package automatically — no manual install required.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "portainer": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/jasonarends/mcp-portainer", "mcp-portainer"],
      "env": {
        "PORTAINER_URL": "https://portainer.example.com",
        "PORTAINER_API_KEY": "ptr_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Claude Code (CLI) — manual config

Or edit .claude/settings.json in your project:

{
  "mcpServers": {
    "portainer": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/jasonarends/mcp-portainer", "mcp-portainer"],
      "env": {
        "PORTAINER_URL": "https://portainer.example.com",
        "PORTAINER_API_KEY": "ptr_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

VS Code (Continue extension)

Add to .continue/config.json:

{
  "mcpServers": [
    {
      "name": "portainer",
      "command": "uvx",
      "args": ["--from", "git+https://github.com/jasonarends/mcp-portainer", "mcp-portainer"],
      "env": {
        "PORTAINER_URL": "https://portainer.example.com",
        "PORTAINER_API_KEY": "ptr_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  ]
}

Cursor

Add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "portainer": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/jasonarends/mcp-portainer", "mcp-portainer"],
      "env": {
        "PORTAINER_URL": "https://portainer.example.com",
        "PORTAINER_API_KEY": "ptr_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "portainer": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/jasonarends/mcp-portainer", "mcp-portainer"],
      "env": {
        "PORTAINER_URL": "https://portainer.example.com",
        "PORTAINER_API_KEY": "ptr_xxxxxxxxxxxxxxxxxxxx"
      }
    }
  }
}

Docker (remote / shared access)

When running via docker compose up -d, the server exposes http://localhost:8000/mcp using the streamable-http transport. Configure your client to connect to this URL instead of spawning a subprocess.

Example for Claude Desktop:

{
  "mcpServers": {
    "portainer": {
      "url": "http://localhost:8000/mcp"
    }
  }
}

Tool reference

System

Tool Description
portainer_status Portainer version, instance ID, and status
portainer_settings Current Portainer settings (admin only)

Environments

Tool Key parameters
list_environments
get_environment environment_id

Stacks

Tool Key parameters
list_stacks environment_id (optional filter)
get_stack stack_id
create_stack environment_id, name, compose_content, env_vars
create_stack_from_git environment_id, name, repo_url, compose_path, branch
update_stack stack_id, environment_id, compose_content, env_vars, prune, pull_image
redeploy_stack stack_id, environment_id, pull_image, prune
start_stack stack_id
stop_stack stack_id
delete_stack stack_id, environment_id

Containers

Tool Key parameters
list_containers environment_id, all_containers
get_container environment_id, container_id
start_container environment_id, container_id
stop_container environment_id, container_id, timeout
restart_container environment_id, container_id
remove_container environment_id, container_id, force, remove_volumes
get_container_logs environment_id, container_id, tail, timestamps
exec_command environment_id, container_id, command, user
get_container_stats environment_id, container_id

Images

Tool Key parameters
list_images environment_id
pull_image environment_id, image, tag
remove_image environment_id, image_id, force

Networks

Tool Key parameters
list_networks environment_id
create_network environment_id, name, driver
remove_network environment_id, network_id

Volumes

Tool Key parameters
list_volumes environment_id
create_volume environment_id, name, driver
remove_volume environment_id, volume_name, force

Users & Teams (admin)

Tool Key parameters
list_users
create_user username, password, role
delete_user user_id
list_teams
create_team name

Registries

Tool Key parameters
list_registries
list_webhooks

Development

git clone https://github.com/jasonarends/mcp-portainer
cd mcp-portainer
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

Running tests

pytest

Tests use respx to mock HTTP calls — no live Portainer instance required.

Releasing a new version

  1. Update __version__ in mcp_portainer/__init__.py
  2. Commit and push
  3. git tag v0.x.y && git push origin v0.x.y

The docker-publish workflow builds and pushes the Docker image to GHCR automatically.


License

MIT

About

MCP server for Portainer — manage Docker environments, stacks, and containers via AI

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages