homelab/ansible/archive/documentation/playbooks/deploy-ansible-mcp-watchtower.md

3.8 KiB

Deploy Ansible MCP server on Watchtower

Purpose

Deploy a custom Ansible MCP server on Watchtower so AI tools can query inventory, validate syntax, and run allowlisted playbooks through guarded tool calls.

Scope

  • Host: watchtower inventory group
  • Playbook: ansible/playbooks/ai/deploy_ansible_mcp_watchtower.yml
  • Runtime path: /opt/ansible-mcp
  • Service name: ansible-mcp
  • State and logs: /var/lib/ansible-mcp

Features delivered

  • MCP tools:
    • health
    • list_inventory
    • validate_syntax
    • run_playbook
    • get_job_status
    • cancel_job
  • Path guardrails for playbook execution (allowlisted directories only)
  • Optional explicit playbook allowlist for high-trust execution scopes
  • Write-mode guardrails:
    • global write toggle
    • explicit confirm gate for write actions
  • Auth guardrail:
    • bearer token required when ANSIBLE_MCP_API_TOKEN is configured
  • Input guardrails:
    • max extra_vars payload size
    • blocked extra_vars key list
  • Background run tracking with per-run logs and status records
  • JSONL audit records at /var/lib/ansible-mcp/audit/events.jsonl

Prerequisites

  1. Watchtower host is reachable from control node.
  2. Python 3 is installed on Watchtower.
  3. Inventory contains a valid watchtower group.
  4. Ansible control node has access to this repository at /home/chester/homelab.

Deploy

Run from ansible/:

cd /home/chester/homelab/ansible
export ANSIBLE_MCP_API_TOKEN='set-a-strong-token-before-deploy'
ansible-playbook -i inventory/hosts.ini playbooks/ai/deploy_ansible_mcp_watchtower.yml

Validate only:

cd /home/chester/homelab/ansible
ansible-playbook -i inventory/hosts.ini playbooks/ai/deploy_ansible_mcp_watchtower.yml --check

Runtime configuration

The playbook sets these environment variables in the systemd unit:

  • ANSIBLE_MCP_REPO_ROOT=/home/chester/homelab/ansible
  • ANSIBLE_MCP_INVENTORY=inventory/hosts.ini
  • ANSIBLE_MCP_ALLOWED_PLAYBOOK_DIRS=playbooks
  • ANSIBLE_MCP_ALLOWED_PLAYBOOKS= (optional comma-separated explicit allowlist)
  • ANSIBLE_MCP_API_TOKEN=<token> (required for HTTP transport in current playbook)
  • ANSIBLE_MCP_ALLOW_WRITE=true
  • ANSIBLE_MCP_REQUIRE_CONFIRM=true
  • ANSIBLE_MCP_DEFAULT_TIMEOUT=900
  • ANSIBLE_MCP_MAX_TIMEOUT=3600
  • ANSIBLE_MCP_MAX_EXTRA_VARS_BYTES=16384
  • ANSIBLE_MCP_BLOCKED_EXTRA_VARS_KEYS=ansible_password,ansible_become_password,vault_password
  • ANSIBLE_MCP_STATE_DIR=/var/lib/ansible-mcp
  • ANSIBLE_MCP_TRANSPORT=streamable-http
  • ANSIBLE_MCP_HOST=0.0.0.0
  • ANSIBLE_MCP_PORT=8449

Verify

# Service state
sudo systemctl status ansible-mcp --no-pager

# Recent logs
sudo journalctl -u ansible-mcp -n 80 --no-pager

# Listening port
ss -ltnp | grep 8449

Client connection example

For MCP clients that support HTTP transport:

{
  "mcpServers": {
    "ansible-watchtower": {
      "type": "http",
      "url": "http://10.0.0.200:8449/mcp",
      "headers": {
        "Authorization": "Bearer ${env:ANSIBLE_MCP_API_TOKEN}"
      }
    }
  }
}

If you terminate TLS upstream (recommended), expose this endpoint through your existing ingress and use an HTTPS URL.

Operational safety notes

  • Keep ANSIBLE_MCP_REQUIRE_CONFIRM=true in write mode.
  • Keep ANSIBLE_MCP_API_TOKEN set and rotate it regularly.
  • Prefer explicit ANSIBLE_MCP_ALLOWED_PLAYBOOKS over broad directory allowlists.
  • Restrict ANSIBLE_MCP_ALLOWED_PLAYBOOK_DIRS to known-safe playbook roots.
  • Do not grant broad filesystem access to the service user.
  • Treat background run logs in /var/lib/ansible-mcp/logs as audit artifacts.

Rollback

sudo systemctl disable --now ansible-mcp
sudo rm -f /etc/systemd/system/ansible-mcp.service
sudo systemctl daemon-reload

Optional cleanup:

sudo rm -rf /opt/ansible-mcp /var/lib/ansible-mcp