Curated Claude Code catalog
Updated 07.05.2026 · 19:39 CET
01 / Skill
portainer

portainer-mcp

Quality
8.0

Portainer MCP implements the Model Context Protocol to link AI assistants directly with Portainer environments, providing a standardized way for AI models to interact with containerized infrastructure. It empowers AI to manage Portainer resources like users and environments, or to execute Docker and Kubernetes commands, making it ideal for AI-driven infrastructure management and operational automation.

USP

This tool uniquely integrates AI assistants with Portainer, offering direct AI control over containerized infrastructure and enabling execution of Docker/Kubernetes commands through natural language, streamlining operations.

Use cases

  • 01AI-driven Portainer resource management
  • 02Executing Docker commands via AI
  • 03Executing Kubernetes commands via AI
  • 04Automating container operations with AI

Detected files (1)

  • CLAUDE.mdclaude_md
    Show content (8853 bytes)
    # Portainer MCP Development Guide
    
    ## Build, Test & Run Commands
    **Prerequisites**: Go 1.24+, golangci-lint, Docker (for integration tests), npx (for inspector)
    
    - Build: `make build`
    - Unit tests: `make test` (excludes integration tests)
    - Run single test: `go test -v ./path/to/package -run TestName`
    - Test with coverage: `make test-coverage` (generates `coverage.out`)
    - Integration tests: `make test-integration` (requires Docker; spins up Portainer containers)
    - Run all tests: `make test-all` (unit + integration)
    - Lint: `make lint` (runs `golangci-lint run ./...`)
    - Format code: `gofmt -s -w .`
    - Run inspector: `make inspector`
    - Build for specific platform: `make PLATFORM=<platform> ARCH=<arch> build`
    - Clean build artifacts: `make clean`
    
    ### CLI Flags
    ```
    dist/portainer-mcp \
      -server <portainer-url> \   # Required: Portainer server URL
      -token <api-token> \        # Required: Portainer API token
      -tools <path>               # Optional: path to tools.yaml (default: tools.yaml)
      -read-only                  # Optional: restrict to read-only tools
      -disable-version-check      # Optional: skip Portainer version validation
    ```
    
    ## Code Style Guidelines
    - Use standard Go naming conventions: PascalCase for exported, camelCase for private
    - Follow table-driven test pattern with descriptive test cases
    - Error handling: return errors with context via `fmt.Errorf("failed to X: %w", err)`
    - Imports: group standard library, external packages, and internal packages
    - Function comments: document exported functions with Parameters/Returns sections
    - Use functional options pattern for configurable clients
    - Lint with `make lint` before committing; fix all warnings
    - Package structure: cmd/ for entry points, internal/ for implementation, pkg/ for reusable components
    - Models belong in pkg/portainer/models, client implementations in pkg/portainer/client
    - Tool YAML parsing and parameter extraction in pkg/toolgen
    - Kubernetes resource annotation stripping in internal/k8sutil
    
    ## Design Documentation
    - Design decisions are documented in individual files in `docs/design/` directory
    - Follow the naming convention: `YYYYMM-N-short-description.md` where:
      - `YYYYMM` is the year and month
      - `N` is a sequence number for that month
      - Example: `202504-1-embedded-tools-yaml.md`
    - Use the standard template structure provided in `docs/design_summary.md`
    - Add new decisions to the table in `docs/design_summary.md`
    - Review existing decisions before making significant architectural changes
    
    ## Client and Model Guidelines
    
    ### Two API Implementation Paths
    
    The `PortainerClient` in `pkg/portainer/client/client.go` holds two internal clients (`cli` for the SDK, `rawCli` for raw HTTP) because the SDK doesn't cover the full Portainer API. **When adding new operations, choose the right path:**
    
    #### Path 1: SDK Client (preferred when available)
    - Uses `github.com/portainer/client-api-go/v2`
    - Covers: environments, tags, teams, users, groups, access groups, edge stacks, settings, Docker/K8s proxy
    - Authentication is handled internally by the SDK (token passed at initialization)
    - Pattern: call `c.cli.SomeMethod()` → convert SDK models to local models → return
    - Example files: `client/environment.go`, `client/tag.go`, `client/stack.go`
    - **Unit tests**: mock the `PortainerAPIClient` interface via `MockPortainerAPI` in `mocks_test.go`
    
    #### Path 2: Raw HTTP Client (when SDK has no method)
    - Uses direct HTTP via `c.rawCli.apiRequest(method, path, body)`
    - Currently used for: local (non-edge) Docker Compose stacks (`/api/stacks/*`)
    - Authenticates with `X-API-Key` header (set in `apiRequest` helper)
    - You must manually: build the URL path, marshal request bodies, check `resp.StatusCode`, decode JSON responses
    - Define request/response structs locally in the same file (e.g., `createLocalStackRequest`)
    - Example file: `client/local_stack.go`
    - **Unit tests**: use `httptest.NewServer` to stand up a fake HTTP server (no mock interface)
    
    #### Decision Guide for New Features
    
    | Check | Use |
    |-------|-----|
    | SDK has a method for the endpoint | SDK path (`c.cli`) |
    | SDK has no method, Portainer REST API exists | Raw HTTP path (`c.rawCli.apiRequest`) |
    | Proxying Docker/K8s APIs through Portainer | SDK path (uses `c.cli.ProxyDockerRequest` / `ProxyKubernetesRequest`) |
    
    **Gotcha**: Both paths share the same `PortainerClient` wrapper and expose methods through the same `PortainerClient` interface in `internal/mcp/server.go`. Callers (MCP handlers) don't know or care which path is used — the wrapper abstracts it.
    
    ### Model Structure
    1. **Raw Models** (`portainer/client-api-go/v2/pkg/models`)
       - Direct mapping to Portainer API data structures
       - May contain fields not relevant to MCP
       - Prefix variables with `raw` (e.g., `rawSettings`, `rawEndpoint`)
    
    2. **Local Models** (`pkg/portainer/models`)
       - Simplified structures tailored for the MCP application
       - Contain only relevant fields with convenient types
       - Define conversion functions to transform from Raw Models
    
    3. **Raw HTTP Models** (for raw HTTP path only)
       - `RawLocalStack` in `pkg/portainer/models/stack.go` — maps directly to Portainer JSON (PascalCase field tags)
       - Converted to `LocalStack` (local model) with enum translation (int → string for type/status) and timestamp formatting
    
    ### Import Conventions
    ```go
    import (
        "github.com/portainer/portainer-mcp/pkg/portainer/models" // Default: models (Local MCP Models)
        apimodels "github.com/portainer/client-api-go/v2/pkg/models" // Alias: apimodels (Raw Client-API-Go Models)
    )
    ```
    
    ### Testing by API Path
    - **SDK path unit tests**: mock `PortainerAPIClient` interface, stub SDK return values, assert local model output and mock expectations (`mockAPI.AssertExpectations(t)`)
    - **Raw HTTP path unit tests**: spin up `httptest.NewServer`, verify request path/method/headers (`X-API-Key`, `Content-Type`) in the handler func, return canned JSON, assert parsed results
    - **Integration tests**: both paths tested end-to-end — call MCP handler, compare with ground-truth from direct API calls
    
    ## MCP Server Architecture
    
    ### Server Configuration
    - Server is initialized in `cmd/portainer-mcp/mcp.go`
    - Uses functional options pattern via `WithClient()`, `WithReadOnly()`, and `WithDisableVersionCheck()`
    - Connects to Portainer API using token-based authentication
    - Validates compatibility with specific Portainer version
    - Loads tool definitions from YAML file
    
    ### Tool Definitions
    - Tools are defined in `internal/tooldef/tools.yaml`
    - File is embedded in binary at build time
    - External file can override embedded definitions
    - Version checking ensures compatibility
    - Read-only mode restricts modification capabilities
    
    ### Feature Domains
    The server registers these feature groups (see `cmd/portainer-mcp/mcp.go`):
    Environment, EnvironmentGroup, Tag, Stack, LocalStack, Settings, User, Team, AccessGroup, DockerProxy, KubernetesProxy
    
    ### Handler Pattern
    - Each tool has a corresponding handler in `internal/mcp/`
    - Handlers follow ToolHandlerFunc signature
    - Standard error handling with wrapped errors
    - Parameter validation with required flag checks
    - Response serialization to JSON
    
    ## Integration Testing Framework
    
    **Integration tests are critical** — CI runs them on every push and PR. Always run `make test-integration` (or `make test-all`) before submitting changes that affect handlers, client methods, or models.
    
    ### Test Environment Setup
    - Uses Docker containers for Portainer instances via testcontainers-go
    - `tests/integration/helpers/test_env.go` provides test environment utilities
    - Creates isolated test environment for each test
    - Configures both Raw Client and MCP Server for testing
    - Automatically cleans up resources after tests
    - Requires Docker daemon running locally
    
    ### Testing Conventions
    - Tests verify both success and error conditions
    - Use table-driven tests with descriptive case names
    - Compare MCP handler results with direct API calls (ground-truth comparison)
    - Validate correct error handling and parameter validation
    - CI pipeline: `make build` → `make test-coverage` → `make test-integration`
    - Reference integration tests for structure/imports: `tests/integration/team_test.go`, `user_test.go`, `environment_test.go`
    - Use `env.RawClient` with specific getters (`GetEdgeStackByName`, `GetUser`, etc.) for ground-truth — don't list-and-iterate
    - If a handler signature changes, update its unit test file too
    
    ## Version Compatibility
    
    ### Portainer Version Support
    - Each release supports a specific Portainer version (defined in `server.go`)
    - Version check at startup prevents compatibility issues
    - Fail-fast approach with clear error messaging
    
    ### Tools File Versioning
    - Strict versioning for tools.yaml file
    - Version validation at startup
    - Clear upgrade path for breaking changes
    
    

README

Portainer MCP

Go Report Card coverage

Ever wished you could just ask Portainer what's going on?

Now you can! Portainer MCP connects your AI assistant directly to your Portainer environments. Manage Portainer resources such as users and environments, or dive deeper by executing any Docker or Kubernetes command directly through the AI.

portainer-mcp-demo

Overview

Portainer MCP is a work in progress implementation of the Model Context Protocol (MCP) for Portainer environments. This project aims to provide a standardized way to connect Portainer's container management capabilities with AI models and other services.

MCP (Model Context Protocol) is an open protocol that standardizes how applications provide context to LLMs (Large Language Models). Similar to how USB-C provides a standardized way to connect devices to peripherals, MCP provides a standardized way to connect AI models to different data sources and tools.

This implementation focuses on exposing Portainer environment data through the MCP protocol, allowing AI assistants and other tools to interact with your containerized infrastructure in a secure and standardized way.

[!NOTE] This tool is designed to work with specific Portainer versions. If your Portainer version doesn't match the supported version, you can use the --disable-version-check flag to attempt connection anyway. See Portainer Version Support for compatible versions and Disable Version Check for bypass instructions.

See the Supported Capabilities sections for more details on compatibility and available features.

Note: This project is currently under development.

It is currently designed to work with a Portainer administrator API token.

Installation

You can download pre-built binaries for Linux (amd64, arm64) and macOS (arm64) from the Latest Release Page. Find the appropriate archive for your operating system and architecture under the "Assets" section.

Download the archive: You can usually download this directly from the release page. Alternatively, you can use curl. Here's an example for macOS (ARM64) version v0.2.0:

# Example for macOS (ARM64) - adjust version and architecture as needed
curl -Lo portainer-mcp-v0.2.0-darwin-arm64.tar.gz https://github.com/portainer/portainer-mcp/releases/download/v0.2.0/portainer-mcp-v0.2.0-darwin-arm64.tar.gz

(Linux AMD64 binaries are also available on the release page.)

(Optional but recommended) Verify the checksum: First, download the corresponding .md5 checksum file from the release page. Example for macOS (ARM64) v0.2.0:

# Download the checksum file (adjust version/arch)
curl -Lo portainer-mcp-v0.2.0-darwin-arm64.tar.gz.md5 https://github.com/portainer/portainer-mcp/releases/download/v0.2.0/portainer-mcp-v0.2.0-darwin-arm64.tar.gz.md5
# Now verify (output should match the content of the .md5 file)
if [ "$(md5 -q portainer-mcp-v0.2.0-darwin-arm64.tar.gz)" = "$(cat portainer-mcp-v0.2.0-darwin-arm64.tar.gz.md5)" ]; then echo "OK"; else echo "FAILED"; fi

(For Linux, you can use md5sum -c <checksum_file_name>.md5) If the verification command outputs "OK", the file is intact.

Extract the archive:

# Adjust the filename based on the downloaded version/OS/architecture
tar -xzf portainer-mcp-v0.2.0-darwin-arm64.tar.gz

This will extract the portainer-mcp executable.

Move the executable: Move the executable to a location in your $PATH (e.g., /usr/local/bin) or note its location for the configuration step below.

Usage

With Claude Desktop, configure it like so:

{
    "mcpServers": {
        "portainer": {
            "command": "/path/to/portainer-mcp",
            "args": [
                "-server",
                "[IP]:[PORT]",
                "-token",
                "[TOKEN]",
                "-tools",
                "/tmp/tools.yaml"
            ]
        }
    }
}

Replace [IP], [PORT] and [TOKEN] with the IP, port and API access token associated with your Portainer instance.

[!NOTE] By default, the tool looks for "tools.yaml" in the same directory as the binary. If the file does not exist, it will be created there with the default tool definitions. You may need to modify this path as described above, particularly when using AI assistants like Claude that have restricted write permissions to the working directory.

Disable Version Check

By default, the application validates that your Portainer server version matches the supported version and will fail to start if there's a mismatch. If you have a Portainer server version that doesn't have a corresponding Portainer MCP version available, you can disable this version check to attempt connection anyway.

To disable the version check, add the -disable-version-check flag to your command arguments:

{
    "mcpServers": {
        "portainer": {
            "command": "/path/to/portainer-mcp",
            "args": [
                "-server",
                "[IP]:[PORT]",
                "-token",
                "[TOKEN]",
                "-disable-version-check"
            ]
        }
    }
}

[!WARNING] Disabling the version check may result in unexpected behavior or API incompatibilities if your Portainer server version differs significantly from the supported version. The tool may work partially or not at all with unsupported versions.

When using this flag:

  • The application will skip Portainer server version validation at startup
  • Some features may not work correctly due to API differences between versions
  • Newer Portainer versions may have API changes that cause errors
  • Older Portainer versions may be missing APIs that the tool expects

This flag is useful when:

  • You're running a newer Portainer version that doesn't have MCP support yet
  • You're running an older Portainer version and want to try the tool anyway

Tool Customization

By default, the tool definitions are embedded in the binary. The application will create a tools file at the default location if one doesn't already exist.

You can customize the tool definitions by specifying a custom tools file path using the -tools flag:

{
    "mcpServers": {
        "portainer": {
            "command": "/path/to/portainer-mcp",
            "args": [
                "-server",
                "[IP]:[PORT]",
                "-token",
                "[TOKEN]",
                "-tools",
                "/path/to/custom/tools.yaml"
            ]
        }
    }
}

The default tools file is available for reference at internal/tooldef/tools.yaml in the source code. You can modify the descriptions of the tools and their parameters to alter how AI models interpret and decide to use them. You can even decide to remove some tools if you don't wish to use them.

[!WARNING] Do not change the tool names or parameter definitions (other than descriptions), as this will prevent the tools from being properly registered and functioning correctly.

Read-Only Mode

For security-conscious users, the application can be run in read-only mode. This mode ensures that only read operations are available, completely preventing any modifications to your Portainer resources.

To enable read-only mode, add the -read-only flag to your command arguments:

{
    "mcpServers": {
        "portainer": {
            "command": "/path/to/portainer-mcp",
            "args": [
                "-server",
                "[IP]:[PORT]",
                "-token",
                "[TOKEN]",
                "-read-only"
            ]
        }
    }
}

When using read-only mode:

  • Only read tools (list, get) will be available to the AI model
  • All write tools (create, update, delete) are not loaded
  • The Docker and Kubernetes proxy tools are available but restricted to GET requests only

Portainer Version Support

This tool is pinned to support a specific version of Portainer. The application will validate the Portainer server version at startup and fail if it doesn't match the required version.

Portainer MCP VersionSupported Portainer Version
0.1.02.28.1
0.2.02.28.1
0.3.02.28.1
0.4.02.29.2
0.4.12.29.2
0.5.02.30.0
0.6.02.31.2
0.7.02.31.2

[!NOTE] If you need to connect to an unsupported Portainer version, you can use the -disable-version-check flag to bypass version validation. See the Disable Version Check section for more details and important warnings about using this feature.

Supported Capabilities

The following table lists the currently (latest version) supported operations through MCP tools:

[!NOTE] Edge Stacks vs Local Stacks: The original Portainer MCP only supports Edge Stacks (distributed via Edge Groups). Local Stack tools add support for regular standalone Docker Compose stacks deployed directly on environments — the most common stack type in non-Edge setups. Local Stack tools use raw HTTP requests to the Portainer REST API since the official SDK (client-api-go) does not expose regular stack endpoints.

ResourceOperationDescriptionSupported In Version
Environments
ListEnvironmentsList all available environments0.1.0
UpdateEnvironmentTagsUpdate tags associated with an environment0.1.0
UpdateEnvironmentUserAccessesUpdate user access policies for an environment0.1.0
UpdateEnvironmentTeamAccessesUpdate team access policies for an environment0.1.0
Environment Groups (Edge Groups)
ListEnvironmentGroupsList all available environment groups0.1.0
CreateEnvironmentGroupCreate a new environment group0.1.0
UpdateEnvironmentGroupNameUpdate the name of an environment group0.1.0
UpdateEnvironmentGroupEnvironmentsUpdate environments associated with a group0.1.0
UpdateEnvironmentGroupTagsUpdate tags associated with a group0.1.0
Access Groups (Endpoint Groups)
ListAccessGroupsList all available access groups0.1.0
CreateAccessGroupCreate a new access group0.1.0
UpdateAccessGroupNameUpdate the name of an access group0.1.0
UpdateAccessGroupUserAccessesUpdate user accesses for an access group0.1.0
UpdateAccessGroupTeamAccessesUpdate team accesses for an access group0.1.0
AddEnvironmentToAccessGroupAdd an environment to an access group0.1.0
RemoveEnvironmentFromAccessGroupRemove an environment from an access group0.1.0
Stacks (Edge Stacks)
ListStacksList all available stacks0.1.0
GetStackFileGet the compose file for a specific stack0.1.0
CreateStackCreate a new Docker stack0.1.0
UpdateStackUpdate an existing Docker stack0.1.0
Tags
ListEnvironmentTagsList all available environment tags0.1.0
CreateEnvironmentTagCreate a new environment tag0.1.0
Teams
ListTeamsList all available teams0.1.0
CreateTeamCreate a new team0.1.0
UpdateTeamNameUpdate the name of a team0.1.0
UpdateTeamMembersUpdate the members of a team0.1.0
Users
ListUsersList all available users0.1.0
UpdateUserUpdate an existing user0.1.0
GetSettingsGet the settings of the Portainer instance0.1.0
Docker
DockerProxyProxy ANY Docker API requests (GET only in read-only mode)0.2.0
Kubernetes
KubernetesProxyProxy ANY Kubernetes API requests (GET only in read-only mode)0.3.0
getKubernetesResourceStrippedProxy GET Kubernetes API requests and automatically strip verbose metadata fields0.6.0
Local Stacks (Standalone Docker Compose)
ListLocalStacksList all local (non-edge) stacks deployed on environments0.7.0
GetLocalStackFileGet the docker-compose file content for a local stack0.7.0
CreateLocalStackCreate a new local standalone Docker Compose stack0.7.0
UpdateLocalStackUpdate an existing local stack with new compose file0.7.0
StartLocalStackStart a stopped local stack0.7.0
StopLocalStackStop a running local stack0.7.0
DeleteLocalStackDelete a local stack permanently0.7.0

Development

Code Statistics

The repository includes a helper script cloc.sh to calculate lines of code and other metrics for the Go source files using the cloc tool. You might need to install cloc first (e.g., sudo apt install cloc or brew install cloc).

Run the script from the repository root to see the default summary output:

./cloc.sh

Refer to the comment header within the cloc.sh script for details on available flags to retrieve specific metrics.

Token Counting

To get an estimate of how many tokens your current tool definitions consume in prompts, you can use the provided Go program and shell script to query the Anthropic API's token counting endpoint.

1. Generate the Tools JSON:

First, use the token-count Go program to convert your YAML tool definitions into the JSON format required by the Anthropic API. Run this from the repository root:

# Replace internal/tooldef/tools.yaml with your YAML file if different
# Replace .tmp/tools.json with your desired output path
go run ./cmd/token-count -input internal/tooldef/tools.yaml -output .tmp/tools.json

This command reads the tool definitions from the specified input YAML file and writes a JSON array of tools (containing name, description, and input_schema) to the specified output file.

2. Query the Anthropic API:

Next, use the token.sh script to send these tool definitions along with a sample message to the Anthropic API. You will need an Anthropic API key for this step.

# Ensure you have jq installed
# Replace sk-ant-xxxxxxxx with your actual Anthropic API key
# Replace .tmp/tools.json with the path to the file generated in step 1
./token.sh -k sk-ant-xxxxxxxx -i .tmp/tools.json

The script will output the JSON response from the Anthropic API, which includes the estimated token count for the provided tools and sample message under the usage.input_tokens field.

This process helps in understanding the token cost associated with the toolset provided to the language model.