@yawlabs/ansible-mcp
[Add to Yaw MCP]
One click adds this to your local Yaw MCP config so it's available in every Yaw Terminal session. Or install manually below.
What is actually true in THIS Ansible checkout on THIS control node: the exact option specs of the modules you have INSTALLED (so coding agents stop writing options that do not exist in your collection version), task-argument checks, role interfaces, inventory structure and vars (redacted), play structure, effective config, requirements drift, and what a collection upgrade would break in your tasks. It is read-only: it never runs a play, never runs --check, never connects to a managed host and never supplies a vault secret. It complements Red Hat's servers rather than replacing them: AAP MCP answers what is true in the controller, ADT MCP takes actions (lint --fix, navigator runs, scaffolding, EE builds). Run them together.
[npm version]
[License: MIT]
Built and maintained by Yaw Labs.
Why this one?
Your checkout has community.general 9.5.2; the model's training data has whatever version it saw most. Agents then write git_config: list_all: true (removed in 11.0.0), forget name (required since 12.0.0), or set state: present on rhsm_repository (no longer accepted). The VS Code language server knows the exact specs, but only a person in the editor sees them. This server lets the agent check before it writes, against what is installed.
- Installed, not latest -- the source of truth is
ansible-doc --json run against your collections paths, with redirects (ufw -> community.general.ufw) and tombstones resolved.
- Checks what lint skips --
ansible-lint's args rule skips modules with action plugins (copy, template); ansible_check_task_args catches their unknown options and bad values, and says plainly which cross-option rules ansible-doc cannot express.
- YAML 1.1 aware -- Ansible parses YAML 1.1, so unquoted
off is false and 0755 is the integer 493. The server reads YAML the same way and says when that is probably a bug.
- Read-only by construction -- configured vault password scripts never run (a server-owned dummy password file replaces them), script and plugin inventory sources are off by default, and play-level lookups are refused before Ansible parses a playbook (as is any playbook or lint target the pre-scan cannot fully read).
- Collection upgrade impact -- downloads only the target version into its own cache and diffs the arg specs of the modules your tasks actually use, tied to file:line.
- macOS, Linux, and Windows through WSL -- Ansible has no Windows control node; on Windows the server spawns it through
wsl.exe --exec (no shell anywhere).
Tools
Every tool takes an optional dir (the project). Tool names carry an ansible_ prefix and never reuse ADT MCP's names (ansible_lint, ansible_navigator, ...), so both can sit behind one aggregator.
Division of authority
What is read-only, and what touches the network
- Never run: plays, modules,
--check, --diff, fact gathering. The only Ansible commands are ansible --version, ansible-config dump, ansible-doc, ansible-inventory --list/--host/--graph, ansible-playbook --syntax-check/--list-*, ansible-galaxy collection list / role list, ansible-lint --offline, and (only in ansible_upgrade_impact) ansible-galaxy collection install --no-deps -p <server cache>.
- Never written: your project, your collections and roles paths, requirements files, and anything inside an existing
~/.ansible. Ansible's local temp, galaxy cache and (when you have none) galaxy token file are redirected to the server's cache. The one residue: Ansible creates an empty ~/.ansible when it does not exist, and ansible-lint creates empty ~/.ansible/roles / ~/.ansible/collections when they are missing.
- Vault: no secret is ever supplied, and a
vault_password_file / vault_identity_list script named in ansible.cfg never runs (it is replaced by a server-owned file holding a random password). Inline !vault values print as <vaulted>; whole-file vaults are listed, not read.
- Dynamic inventory (script, constructed, cloud plugins) runs code and calls APIs, so it is off unless
ANSIBLE_MCP_ALLOW_DYNAMIC_INVENTORY=1; skipped sources are named in the answer.
- Residual risk, stated:
ansible-playbook --syntax-check (and ansible-lint, which runs it) evaluates Jinja in play-level name, hosts and vars_files and imports playbook-adjacent vars_plugins/. Treat dir as code you would run --syntax-check on. Lookups in those fields are refused before Ansible sees them unless ANSIBLE_MCP_ALLOW_PLAY_LOOKUPS=1, and local plugin files are listed in the answer.
- Redaction (
ansible_inventory, ansible_role_interface, ansible_config, lint messages): vault markers, plus any string equal to a hidden one, plus values under secret-like names (ansible_become_password, api_token, vault_db_password, ... but not vault_addr or private_key_file), plus secret-shaped strings (private keys, JWTs, GitHub/GitLab/Slack/npm tokens; URL passwords masked in place). Galaxy server tokens and passwords are always redacted. There is no "show secrets" switch.
- Network: only
ansible_upgrade_impact, on a cache miss, to Galaxy or the servers in your ansible.cfg (openWorldHint: true). The cache is never evicted automatically; deleting it is safe.
Example ansible_check_task_args output (real docs, community.general 9.5.2):
Example ansible_upgrade_impact output (real 9.5.2 -> 12.0.0 docs):
Quick start
1. Have ansible-core where the server can run it. On macOS / Linux, ansible-core (and optionally ansible-lint) on PATH, or in a venv you point ANSIBLE_MCP_BIN_DIR at. On Windows, inside WSL:
2. Add the server. Claude Code, from the project:
Or add it to .mcp.json in the project (or anywhere, and set ANSIBLE_MCP_DIR):
macOS / Linux:
Windows (Ansible inside WSL):
Why the extra step on Windows? Since Node 20, child_process.spawn cannot directly execute .cmd files (that's what npx is on Windows). Wrapping with cmd /c is the standard workaround.
3. Restart your MCP client and ask, for example: "Add a task that opens port 8443 with ufw -- check the arguments against our installed collections first."
Windows and WSL, in detail
- The prefix must use
wsl.exe --exec (or -e), never --: with --, WSL re-parses the arguments with bash and a value like it's breaks the command. The server refuses a prefix without --exec.
- Nothing from the Windows environment crosses into WSL. Variables the Ansible side needs (proxies,
ANSIBLE_COLLECTIONS_PATH) are forwarded by name with ANSIBLE_MCP_PASS_ENV.
- Windows paths are translated with the mount root
wslpath reports (C:\work\site -> /mnt/c/work/site). A project inside WSL works too: pass dir as \\wsl.localhost\Ubuntu\home\me\site (the distro must match the prefix's -d).
- On a Windows drive every folder looks world-writable to WSL, and Ansible then ignores
ansible.cfg. When the project has one, the server sets ANSIBLE_CONFIG to it explicitly and says so.
- The server's Ansible-side cache lives under the WSL user's
~/.cache/ansible-mcp (never /tmp, which WSL empties on restart).
Tell your agent to use it
Paste this into the project's CLAUDE.md (or AGENTS.md):
Configuration
All optional.
Runtime (oam or Node):
The ansible-mcp command prefers oam when it finds a
usable one and otherwise runs on Node. It never serves on an oam older than 0.19.1.
An outdated oam is fixed with oam self-update. Under Yaw MCP, which runs servers
on oam by default, yaw-mcp set <namespace> runtime=node switches this server to
Node. There is no --permission sandbox option: the server spawns Ansible and
reads whatever directory a call names, so there is nothing narrow to grant.
Requirements
- Node.js 20+
- ansible-core on the control node (verified with 2.21.5); ansible-lint for
ansible_lint_summary (verified with 26.10.1)
- Windows: WSL with ansible-core installed in a distro, and
ANSIBLE_MCP_COMMAND_PREFIX set. Without it, only ansible_project_info (static half) and ansible_role_interface (local files) answer; the rest say what to set.
ansible_upgrade_impact: Galaxy (or your configured servers) reachable the first time a target version is requested; later runs for that version are offline
Contributing
See CONTRIBUTING.md for the full workflow, including release process.
License
MIT
[Follow @YawLabs on X]