138 lines
3.8 KiB
Markdown
138 lines
3.8 KiB
Markdown
# 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/`:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```json
|
|
{
|
|
"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
|
|
|
|
```bash
|
|
sudo systemctl disable --now ansible-mcp
|
|
sudo rm -f /etc/systemd/system/ansible-mcp.service
|
|
sudo systemctl daemon-reload
|
|
```
|
|
|
|
Optional cleanup:
|
|
|
|
```bash
|
|
sudo rm -rf /opt/ansible-mcp /var/lib/ansible-mcp
|
|
```
|