A minimal read-only Model Context Protocol server for ArgoCD. Lets an MCP client (Claude Code, Claude Desktop, etc.) inspect application sync/health, resource trees, live-vs-desired diffs, events, and pod logs — without exposing any mutating endpoints.
No third-party services. The server runs locally on your machine and talks directly to your ArgoCD API over HTTPS.
All read-only — no sync, refresh, terminate-op, rollback, or delete endpoints are wired up.
| Tool | What it does |
|---|---|
list_applications(project?, selector?) |
Apps with sync status, health, project, target revision |
get_application(name) |
Full app details: spec, status, conditions, current operation |
get_application_resource_tree(name) |
Every k8s resource managed by the app, with per-node health |
get_application_managed_resources(name) |
Live-vs-desired diff (great for OutOfSync drift) |
get_application_events(name) |
Recent k8s events for the app |
get_application_manifests(name, revision?) |
Rendered desired-state manifests |
get_application_logs(name, pod, container?, tail_lines?, namespace?) |
Pod logs via ArgoCD's proxy |
list_projects() |
ArgoCD projects + their source/destination allowlists |
list_clusters() |
Registered clusters (credentials stripped) |
list_repositories() |
Registered Git repos (credentials stripped) |
pip3 install mcp httpxThe server supports two:
Mode A — bearer token (preferred). In the ArgoCD UI: Settings → Accounts → <your account> → Generate New Token (set "Expires In" to 0 for "never expires" if you want a long-lived token). The account needs the apiKey capability — by default the built-in admin user does not have this; an admin will need to add accounts.<name>: apiKey, login to the argocd-cm ConfigMap.
Mode B — username + password. Use this when you can't easily change cluster config. The server POSTs your credentials to /api/v1/session at startup, gets a session token, and refreshes it automatically when it expires (handles 401s transparently). Slightly less ideal — sessions are short-lived (~24h default) — but the refresh logic makes that invisible.
| Var | Required | Notes |
|---|---|---|
ARGOCD_SERVER |
yes | Hostname (full URLs like https://argocd.example.com/applications are stripped to host automatically) |
ARGOCD_AUTH_TOKEN |
Mode A | Bearer token from step 2 |
ARGOCD_USERNAME |
Mode B | Username for session login |
ARGOCD_PASSWORD |
Mode B | Password for session login |
ARGOCD_INSECURE |
no | Set to 1 to skip TLS verification (self-signed certs) |
You can export them however you like. The recommended pattern is 1Password CLI (op run) so secrets never touch disk in plaintext — see below.
For Claude Code, add to ~/.claude/settings.json:
{
"mcpServers": {
"argocd-readonly": {
"command": "python3",
"args": ["/absolute/path/to/server.py"],
"env": {
"ARGOCD_SERVER": "argocd.example.com",
"ARGOCD_AUTH_TOKEN": "your-token-here",
"ARGOCD_INSECURE": "1"
}
}
}
}Restart your client and the tools become available.
If you'd rather not paste secrets into settings.json, drop them in a .env file next to server.py and load them at launch. You have two options:
Simplest. Put the actual secrets in .env:
ARGOCD_SERVER=argocd.example.com
ARGOCD_AUTH_TOKEN=eyJhbGciOi...your-token-here...
ARGOCD_INSECURE=1
Load it however your shell or process manager prefers. With op run (works without 1Password too — it just passes plain values through):
{
"mcpServers": {
"argocd-readonly": {
"command": "op",
"args": ["run", "--env-file=/absolute/path/to/.env", "--", "python3", "/absolute/path/to/server.py"]
}
}
}Or skip op entirely with a tiny shell wrapper:
{
"mcpServers": {
"argocd-readonly": {
"command": "bash",
"args": ["-c", "set -a; source /absolute/path/to/.env; set +a; exec python3 /absolute/path/to/server.py"]
}
}
}This is fine for personal machines. Just remember .env now holds real secrets — gitignore it, and don't commit it to a dotfiles repo without a vault.
Put secret references in .env instead of values. op run resolves them against your vault at launch, so real secrets never sit on disk:
ARGOCD_SERVER=op://Vault/ArgoCD/website
ARGOCD_AUTH_TOKEN=op://Vault/ArgoCD/token
ARGOCD_INSECURE=1
For Mode B (username/password), use:
ARGOCD_SERVER=op://Vault/ArgoCD/website
ARGOCD_USERNAME=op://Vault/ArgoCD/username
ARGOCD_PASSWORD=op://Vault/ArgoCD/password
ARGOCD_INSECURE=1
Wire your client to op run exactly as in Option A — same command, same args. The only difference is what's in the file. You can mix and match: ARGOCD_INSECURE=1 as a literal, secrets as op:// refs.
Heads up — special characters in item names.
op://references reject parentheses and some other special characters in vault/item names. If your item is called something likeArgoCD (prod), look up its UUID and use that instead:op item get "ArgoCD (prod)" --vault "Vault" --format json | jq -r '.id' # -> zmwp44ddjeta252qt5rttuk6ky # then in .env: ARGOCD_SERVER=op://Vault/zmwp44ddjeta252qt5rttuk6ky/website
Requires the 1Password CLI (op) signed in to your account.
- Read-only by design. No mutating ArgoCD endpoints are exposed. If you want sync/rollback, fork it — but be aware an LLM with sync power can do real damage on a misread.
- Token scope. Use a dedicated ArgoCD account with the narrowest project RBAC you can get away with. If you only need to inspect one project, restrict the token to that project.
ARGOCD_INSECURE. Only enable when you know you're hitting a cluster with a self-signed cert. It disables certificate verification entirely — it does not just "ignore hostname mismatch."- Credential scrubbing.
list_clustersandlist_repositoriesdrop credential fields (passwords, SSH keys, GitHub App keys, etc.) before returning. The full ArgoCD API does include these in responses for users with the right RBAC; the server filters them out so they don't end up in your LLM context. - Logs leak content.
get_application_logsreturns raw pod log content into your LLM context. Skip that tool if your workloads log sensitive data.
MIT — do whatever you want with it.