Skip to main content
Glama

Argo CD MCP Server (Python)

An implementation of Model Context Protocol (MCP) server for Argo CD, enabling AI assistants to interact with your Argo CD applications through natural language. This server allows for seamless integration with Visual Studio Code and other MCP clients through stdio and HTTP stream transport protocols.

About this repository

This is a Python port of argoproj-labs/mcp-for-argocd, the official Argo CD MCP Server written in TypeScript. It was ported from upstream release v0.9.0 and is intended to behave identically:

Upstream (TypeScript)

This repository (Python)

Tools, argument schemas, and results

16 tools

the same 16 tools, same names and arguments

Transports

stdio, sse, http (--stateless)

the same

Environment variables and CLI flags

ARGOCD_BASE_URL, ARGOCD_API_TOKEN, ARGOCD_TOKEN_REGISTRY_PATH, MCP_AUTH_TOKEN, MCP_BIND_ADDRESS, MCP_READ_ONLY, --port, --bind-address, --allowed-host-header, --allowed-origin, --allow-unauthenticated, --stateless

the same

Credential and listener security model

see below

the same rules, same error messages, same test suite (ported)

Server identity (serverInfo.name)

argocd-mcp

argocd-mcp

How it is launched

npx argocd-mcp@latest stdio

uvx --from git+https://github.com/adityaraj178/mcp-argocd-py argocd-mcp stdio

Self-signed certificates

NODE_TLS_REJECT_UNAUTHORIZED=0

SSL_CERT_FILE or ARGOCD_INSECURE_SKIP_VERIFY=true

Runtime

Node.js, @modelcontextprotocol/sdk

Python 3.10+, the official mcp Python SDK

The documentation below is adapted from the upstream README so that the two projects stay easy to compare. Credit for the design, the tool surface, the security model, and the original documentation and tests goes to the Argo Proj Contributors; see NOTICE. Both projects are licensed under the Apache License 2.0. This port is a personal project and is not affiliated with or endorsed by the Argo Project or argoproj-labs. If you want the official, supported server, use argoproj-labs/mcp-for-argocd.

Related MCP server: hypen-argocd-mcp

Features

  • Transport Protocols: Supports both stdio and HTTP stream transport modes for flexible integration with different clients

  • Complete Argo CD API Integration: Provides comprehensive access to Argo CD resources and operations

  • AI Assistant Ready: Pre-configured tools for AI assistants to interact with Argo CD in natural language

Available Tools

The server provides the following ArgoCD management tools:

Cluster Management

  • list_clusters: List all clusters registered with ArgoCD

Project Management

  • get_appproject: Get detailed information about a specific AppProject (project)

Application Management

  • list_applications: List and filter all applications

  • get_application: Get detailed information about a specific application

  • create_application: Create a new application

  • update_application: Update an existing application

  • delete_application: Delete an application

  • sync_application: Trigger a sync operation on an application

Resource Management

  • get_application_resource_tree: Get the resource tree for a specific application

  • get_application_managed_resources: Get managed resources for a specific application

  • get_application_workload_logs: Get logs for application workloads (Pods, Deployments, etc.)

  • get_application_events: Get events for an application

  • get_resource_events: Get events for resources managed by an application

  • get_resources: Get manifests for resources managed by an application

  • get_resource_actions: Get available actions for resources

  • run_resource_action: Run an action on a resource

Installation

Prerequisites

  • Python 3.10 or higher

  • uv (recommended; uvx runs the server straight from this repository with no install step) or pip

  • Argo CD instance with API access

  • Argo CD API token (see the docs for instructions)

The package is not published to PyPI; install it from this repository:

uv tool install git+https://github.com/adityaraj178/mcp-argocd-py
# or: pip install git+https://github.com/adityaraj178/mcp-argocd-py
argocd-mcp --help

Or run it directly without installing, which is what the client configurations below do (--from names the package, argocd-mcp is the command it provides):

uvx --from git+https://github.com/adityaraj178/mcp-argocd-py argocd-mcp stdio

Pin a release by appending @<tag> to the Git URL, e.g. git+https://github.com/adityaraj178/mcp-argocd-py@v0.9.0.

Usage with Cursor

  1. Follow the Cursor documentation for MCP support, and create a .cursor/mcp.json file in your project:

{
  "mcpServers": {
    "argocd-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/adityaraj178/mcp-argocd-py",
        "argocd-mcp",
        "stdio"
      ],
      "env": {
        "ARGOCD_BASE_URL": "<argocd_url>",
        "ARGOCD_API_TOKEN": "<argocd_token>"
      }
    }
  }
}
  1. Start a conversation with Agent mode to use the MCP.

Usage with VSCode

  1. Follow the Use MCP servers in VS Code documentation, and create a .vscode/mcp.json file in your project:

{
  "servers": {
    "argocd-mcp-stdio": {
      "type": "stdio",
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/adityaraj178/mcp-argocd-py",
        "argocd-mcp",
        "stdio"
      ],
      "env": {
        "ARGOCD_BASE_URL": "<argocd_url>",
        "ARGOCD_API_TOKEN": "<argocd_token>"
      }
    }
  }
}
  1. Start a conversation with an AI assistant in VS Code that supports MCP.

Usage with Claude Desktop

  1. Follow the MCP in Claude Desktop documentation, and create a claude_desktop_config.json configuration file:

{
  "mcpServers": {
    "argocd-mcp": {
      "command": "uvx",
      "args": [
        "--from",
        "git+https://github.com/adityaraj178/mcp-argocd-py",
        "argocd-mcp",
        "stdio"
      ],
      "env": {
        "ARGOCD_BASE_URL": "<argocd_url>",
        "ARGOCD_API_TOKEN": "<argocd_token>"
      }
    }
  }
}
  1. Configure Claude Desktop to use this configuration file in settings.

Self-signed Certificates

If your Argo CD instance uses self-signed certificates or certificates from a private Certificate Authority (CA), point the client at your CA bundle:

"SSL_CERT_FILE": "/path/to/ca-bundle.pem"

If that is not possible, TLS certificate validation for the connection to Argo CD can be disabled with:

"ARGOCD_INSECURE_SKIP_VERIFY": "true"

(This is the equivalent of NODE_TLS_REJECT_UNAUTHORIZED=0 in the TypeScript server.)

Warning: Disabling SSL verification reduces security. Use this setting only in development environments or when you understand the security implications.

Providing ArgoCD Credentials

The server connects to ArgoCD using a base URL and an API token.

API token — header / env var only (mandatory)

The ArgoCD API token is a secret and is only ever read from the transport layer, never from a tool-call argument:

  • HTTP headers (HTTP transport only): x-argocd-api-token.

  • Environment variables: ARGOCD_API_TOKEN (all transports).

This token is outbound only: it authenticates this server to ArgoCD and never authorizes an inbound caller. See Network Exposure for who may reach the listener.

This is the default token. It is mandatory unless a token registry is configured: on the HTTP transport, a connection that supplies no token (neither header nor env var) is rejected with 400 Bad Request, but when a registry is configured a tokenless connection is allowed because each call resolves its own registry token. Keeping the token out of tool arguments ensures it never enters prompts, model context, or tool-call logs.

Base URL — header / env var, or per-call argument

The base URL may be supplied at the session level (resolved once when the server starts or when an HTTP client connects):

  • HTTP headers (HTTP transport only): x-argocd-base-url.

  • Environment variables: ARGOCD_BASE_URL (all transports).

In addition, every tool accepts an optional argocdBaseUrl argument:

  • If a session default base URL exists, argocdBaseUrl is optional and overrides the default for that single call.

  • If no session default base URL is configured (header and env var both absent), argocdBaseUrl is required; a call without it returns an error.

Token registry — per-base-URL tokens (multi-instance)

To target multiple ArgoCD instances, each with its own token, configure a token registry. Because the tokens are secrets, the registry is read from a JSON file, not an environment variable — point ARGOCD_TOKEN_REGISTRY_PATH at the file (e.g. a mounted Kubernetes secret). This keeps the tokens out of the process environment, crash dumps, and child-process inheritance.

ARGOCD_TOKEN_REGISTRY_PATH=/app/argocd-mcp/token-registry.json

The file contains a JSON array mapping a base URL to the token that should be used for it:

[
  { "baseUrl": "https://argo-a.example.com", "token": "<token-a>" },
  { "baseUrl": "https://argo-b.example.com", "token": "<token-b>" }
]

Secure the file. Restrict it to the server's user (e.g. chmod 400) and prefer a secret-management mechanism (Kubernetes secret volume, Vault agent, etc.) over a plaintext file on disk.

Local development. The make run / make dev targets run without a registry by default; pass ARGOCD_TOKEN_REGISTRY_PATH=/path/to/tokens.json to use one. See Running locally.

With a registry configured, a caller targets an instance by passing only the (non-secret) argocdBaseUrl argument; the server pairs it with the registered token. The token never appears in the tool-call payload.

Two kinds of token

The server resolves calls using one of two distinct tokens. Keeping them straight is what makes the security model work:

Default token

Registry token

Source

x-argocd-api-token header / ARGOCD_API_TOKEN env var (the session credential)

A token entry in the ARGOCD_TOKEN_REGISTRY_PATH JSON file, keyed by baseUrl

Scope

The default base URL only (x-argocd-base-url / ARGOCD_BASE_URL)

The specific base URL its entry is keyed to

Used for

A call that targets the default base URL

A call that targets any base URL present in the registry (including the default, as a fallback)

Never used for

Any base URL other than the default — it is never sent to a different host

Any base URL not registered

The cardinal rule: the default token is bound to the default base URL; every other host's token must come from the registry. A registry token is bound to exactly the host it is registered under.

Resolution order

For a given call, the resolved base URL is the argocdBaseUrl argument if supplied, otherwise the session default. The token is then chosen by:

  1. Call targets the default base URL → use the default token. If no default token was supplied (a tokenless session), fall back to the registry token for that base URL, if one exists.

  2. Call targets any other base URL → use the registry token for that base URL only. The default token is never used here — it is not sent to a host other than the default one.

  3. If neither applies (no token can be resolved for the requested base URL), the call returns a "Missing required ArgoCD API token" error and no request is made to that host.

Why the default token is bound to the default base URL. The argocdBaseUrl argument comes from the tool call, so a caller (or a prompt-injected model) could point it at an arbitrary host. If the default token were paired with any supplied base URL, that token would be sent — as an Authorization: Bearer header — to the attacker's host. Restricting the default token to the default base URL, and requiring an explicit registry entry for every other host, prevents this token exfiltration. To target additional instances you must register their tokens (and thus their hostnames) up front.

Base URLs are normalized for lookup (lowercased scheme and host, default port and trailing slashes ignored), so minor formatting differences still match. When a registry is configured, the HTTP transport no longer requires x-argocd-api-token at connection time — a tokenless connection is allowed because the per-call base URL resolves its own token. If ARGOCD_TOKEN_REGISTRY_PATH is set but the file is missing, unreadable, or malformed, the server fails closed: it exits at startup rather than silently falling back to its default credential, so a misconfigured registry can never cause calls to be routed with the wrong token.

For example, a tools/call request overriding only the base URL:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_applications",
    "arguments": {
      "argocdBaseUrl": "https://argocd.other-cluster.example.com"
    }
  }
}

Overriding the base URL to a different instance requires a registry token. The default token (x-argocd-api-token / ARGOCD_API_TOKEN) is bound to the default base URL only and is never sent to a different host. Overriding argocdBaseUrl to point at the default instance (same host, formatting aside) reuses the default token; pointing it at any other instance requires a registry token for that instance, otherwise the call fails with "Missing required ArgoCD API token" and no request is sent. This is intentional — see why the default token is bound to the default base URL above.

Network Exposure

The http and sse transports open a network listener that reaches every ArgoCD tool, including create_application, delete_application, sync_application, and run_resource_action. By default it binds loopback only.

ARGOCD_API_TOKEN does not protect it. That token authenticates this server to ArgoCD. It says nothing about who the caller is. Inbound access is controlled by the settings below.

Setting

Flag

Env var

Default

What it does

Bind address

--bind-address

MCP_BIND_ADDRESS

127.0.0.1

Which address the listener accepts connections on.

Inbound token

MCP_AUTH_TOKEN

unset

When set, every request must carry Authorization: Bearer <token>.

Allowed Host

--allowed-host-header

loopback names

Extra hostname accepted in a request's Host header. Repeat per name.

Allowed Origin

--allowed-origin

loopback origins

Extra browser origin accepted in a request's Origin header. Repeat per origin.

External auth

--allow-unauthenticated

false

Allows a non-loopback bind with no token, when something in front already authenticates callers.

Port

--port

3000

Which port to listen on.

--bind-address decides who may connect. --allowed-host-header only checks what an already-connected client claims. They are not a pair, and the second is not a firewall.

Flags with no env var are passed as arguments, in a container too: docker run <image> http --allow-unauthenticated.

Behaviour:

  • Widening the bind requires MCP_AUTH_TOKEN or --allow-unauthenticated. Otherwise the server logs why and exits non-zero instead of starting exposed.

  • Origin is always checked, on scheme, host, and port. This is what stops a malicious web page, including one using DNS rebinding.

  • Host is checked on a loopback bind, or on any bind with at least one --allowed-host-header. Otherwise the hostname clients legitimately use is unknown, so the check is skipped and a warning is logged.

  • GET /healthz is exempt, so a kubelet probe still succeeds. It returns liveness only.

  • Unusable configuration fails at startup with the reason, rather than being ignored.

  • Read-only mode is independent of all of this and caps what any caller can do.

Exposing the listener deliberately:

export MCP_AUTH_TOKEN=<inbound_token>
argocd-mcp http --bind-address 0.0.0.0 --allowed-host-header mcp.internal.example.com

The container image (ghcr.io/adityaraj178/mcp-argocd-py, built by this repository's workflow) keeps the same loopback default, so it needs no extra configuration when the caller shares its network namespace, such as a sidecar in the same Kubernetes pod:

docker run -e ARGOCD_BASE_URL=<argocd_url> -e ARGOCD_API_TOKEN=<argocd_token> \
  ghcr.io/adityaraj178/mcp-argocd-py

To publish a port, widen the bind and set an inbound credential:

docker run -p 3000:3000 \
  -e ARGOCD_BASE_URL=<argocd_url> -e ARGOCD_API_TOKEN=<argocd_token> \
  -e MCP_BIND_ADDRESS=0.0.0.0 -e MCP_AUTH_TOKEN=<inbound_token> \
  ghcr.io/adityaraj178/mcp-argocd-py

When the bind is widened and a proxy or mesh already authenticates callers, use --allow-unauthenticated instead of MCP_AUTH_TOKEN.

See Operator notes for the deployment caveats.

Read Only Mode

If you want to run the MCP Server in a ReadOnly mode to avoid resource or application modification, you should set the environment variable:

"MCP_READ_ONLY": "true"

This will disable the following tools:

  • create_application

  • update_application

  • delete_application

  • sync_application

  • run_resource_action

By default, all the tools will be available.

Stateless Mode

By default, the HTTP transport assigns a session ID to each client connection and keeps an in-memory map of active sessions. This works well for single-instance deployments but causes 400 errors when multiple replicas are running without sticky sessions, because a request routed to a different pod will not find the session that was created on the original pod.

To run without session affinity requirements, start the server with the --stateless flag:

argocd-mcp http --stateless

Or with Docker:

docker run -p 3000:3000 \
  -e ARGOCD_BASE_URL=<argocd_url> -e ARGOCD_API_TOKEN=<argocd_token> \
  -e MCP_BIND_ADDRESS=0.0.0.0 -e MCP_AUTH_TOKEN=<inbound_token> \
  ghcr.io/adityaraj178/mcp-argocd-py http --stateless

The image has an ENTRYPOINT, so overriding the command replaces only the arguments. Publishing a port is what makes the wider bind and the inbound token necessary here; see Network Exposure.

In stateless mode:

  • No Mcp-Session-Id is returned or required — any replica can handle any request

  • ArgoCD credentials must be supplied on every request via environment variables or x-argocd-base-url / x-argocd-api-token headers (the base URL may also be overridden per call via the argocdBaseUrl tool argument; the API token is always header/env only)

  • GET /mcp and DELETE /mcp return 405 Method Not Allowed (session-level SSE and termination are not supported)

This mode is recommended for Kubernetes deployments with Horizontal Pod Autoscaling (HPA) where network-level sticky sessions are not available.

Logging

Logs are written to stderr as JSON lines (stdout is reserved for the stdio transport's protocol frames). Set LOG_LEVEL (DEBUG, INFO, WARNING, ERROR) to change the verbosity; the default is INFO.

For Development

  1. Clone the repository:

git clone https://github.com/adityaraj178/mcp-argocd-py.git
cd mcp-argocd-py
  1. Install project dependencies (creates .venv):

uv sync --all-groups
  1. Start the development server with hot reloading enabled:

make dev

Once the server is running, you can utilize the MCP server within Visual Studio Code or other MCP client.

Run the checks the CI runs:

make lint   # ruff check, ruff format --check, mypy
make test   # pytest

Running locally

The Makefile provides targets for running the server over the HTTP transport:

make run    # run the HTTP server
make dev    # run the HTTP server, restarting when the source changes

By default neither target sets any credentials — the server starts with no default base URL or token, so callers must supply them per request (x-argocd-base-url / x-argocd-api-token headers, or the argocdBaseUrl tool argument once a registry is configured). Override the port the same way:

make run PORT=4000

To configure credentials, export the relevant environment variable on the command line. There are three (all optional):

Variable

Purpose

ARGOCD_BASE_URL

Default ArgoCD instance URL used when a call doesn't override it.

ARGOCD_API_TOKEN

Static API token for the default base URL.

ARGOCD_TOKEN_REGISTRY_PATH

Path to a JSON token registry mapping base URLs to tokens (for targeting multiple instances).

These are all outbound credentials. For who may reach the listener, see Network Exposure.

# Single instance with a static base URL + token:
make run ARGOCD_BASE_URL=https://argo.example.com ARGOCD_API_TOKEN=<token>

# Multiple instances via a token registry:
make run ARGOCD_TOKEN_REGISTRY_PATH=/path/to/tokens.json

# Both — a default instance plus extra instances resolved from the registry:
make dev ARGOCD_BASE_URL=https://argo.example.com ARGOCD_API_TOKEN=<token> \
  ARGOCD_TOKEN_REGISTRY_PATH=/path/to/tokens.json

A .env file in the working directory is loaded at startup (values already present in the environment win).

See Token resolution for how the default token and registry interact. If ARGOCD_TOKEN_REGISTRY_PATH is set but the file is missing, unreadable, or malformed, the server fails closed at startup.

Project layout

src/argocd_mcp/
├── cmd.py                 CLI (argparse): stdio | sse | http
├── log.py                 JSON-lines logger on stderr
├── models.py              Tool argument schemas (pydantic)
├── argocd/
│   ├── http.py            httpx wrapper (JSON + NDJSON log streaming)
│   └── client.py          ArgoCD REST client
└── server/
    ├── server.py          MCP server: tool registry, per-call credential resolution
    ├── security.py        Bind policy, bearer auth, Host/Origin validation
    ├── token_registry.py  Base URL -> token registry
    └── transport.py       stdio / SSE / Streamable HTTP (stateful & stateless)
tests/                     pytest suite (boots real listeners on loopback)

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An MCP (Model Context Protocol) server that integrates with the ArgoCD API, enabling AI assistants and large language models to manage ArgoCD applications and resources through natural language interactions.
    10
    12
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to interact with ArgoCD APIs through standardized MCP tools for managing applications, resources, and deployments.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Safety-first GitOps operations for ArgoCD via the Model Context Protocol. Enables listing, diagnosing, syncing, and managing ArgoCD applications with progressive disclosure and defense-in-depth security.
    15
    Apache 2.0