Every Ansible module as a typed MCP tool
Project description
Rocannon
Rocannon turns any Ansible control node into an MCP server: it registers every
installed module as a typed tool. It reads ansible-doc -j for each module at
startup and builds a Pydantic-validated function signature, then exposes the
result over the MCP protocol (stdio or HTTP). The tool surface is whatever you
have installed, from one collection to a hundred. Any MCP client (Claude Code,
Cursor, mcphost, custom agents) calls the same tools an operator would call from
a REPL.
Each registered tool carries the module's own ansible-doc metadata: a JSON
output schema for structured results, and MCP safety hints derived from the
module's attributes (read-only for fact modules, destructive and open-world for
command, shell, script, and raw).
Every module is also a top-level CLI subcommand:
rocannon ansible.builtin.command --target h1 --cmd 'uptime'
rocannon ansible.builtin.copy --target h1 --src /etc/hosts --dest /tmp/h
Append --record path/to/runbook.yml to any invocation and Rocannon writes
each call as a new play in a real Ansible playbook. The resulting file runs
directly under ansible-playbook -i <inv> path/to/runbook.yml.
Add --check to preview a change without applying it (Ansible check mode) and
--diff to see what would change. Each is offered per module according to its
declared check-mode support, both on the CLI and as a parameter on the matching
MCP tool. rocannon playbook run <name> --check previews an entire saved runbook.
Sessions driven via the MCP server save the same way: as Ansible playbooks
under .rocannon/playbooks/. Rocannon also loads them back on next startup
as MCP prompts.
Claude Haiku, via the Claude Agent SDK, driving Rocannon's typed Ansible-module tools against a real RHEL 9 host in natural language.
Case studies
examples/case-studydrives natural language into ad-hoc Ansible on a real RHEL 9 host: facts, a command, a config change, plus--checkand replay as standardansible-playbook.examples/containerlabruns the same agent against a two-node Arista cEOS fabric, where thearista.eosmodules become MCP tools.examples/execution-environmentbakes Rocannon into an Ansible Execution Environment for a frozen, reproducible tool set.
Install
pip install rocannon
This brings ansible-core and ansible-runner with it. rocannon doctor reports
anything missing from the environment.
Quickstart
rocannon quickstart
This scaffolds a localhost profile (ansible_connection=local) under
.rocannon/ and prints the exact wiring for your MCP client (Claude Code,
Claude Desktop, Cursor) plus a rocannon mcp doctor command to confirm the
tools register. Then ask your assistant something like "Gather facts from
localhost and tell me the OS and kernel version."
To explore from a shell instead of an MCP client:
rocannon mcp doctor --profile .rocannon/quickstart.yml # list registered tools
rocannon repl --profile .rocannon/quickstart.yml # operator shell
Inside the REPL:
rocannon> .target localhost
rocannon> ping
rocannon> command cmd="uptime"
rocannon> .save my_session
rocannon> .exit
.save writes .rocannon/playbooks/my_session.yml as a standard Ansible
playbook. Run it directly with ansible-playbook -i hosts my_session.yml, or
let Rocannon load it back as an MCP prompt next time the server starts.
CLI
rocannon quickstart scaffold a localhost profile and print client wiring
rocannon <fqcn> invoke a module: rocannon ansible.builtin.copy ...
optional --record FILE appends each call to a playbook
rocannon mcp serve start the MCP server (stdio or http)
rocannon mcp doctor list registered tools, resources, prompts
rocannon repl interactive shell on the same MCP server
rocannon run legacy ad-hoc form (module FQCN + -a key=value)
rocannon doctor system health (binaries, env, inventory)
rocannon doc <module> print parsed schema for a module
rocannon search <q> find modules by name or description
rocannon ls list hosts/groups/modules from a profile
rocannon playbook list/show/run saved playbooks
Per-module help (typed flags, defaults, descriptions from ansible-doc):
rocannon ansible.builtin.copy --help. Modules that support check mode also
accept --check and --diff.
Profiles
A profile is a YAML file declaring inventory + modules:
inventories:
- ./hosts
modules:
- ansible.builtin
- ibm.ibm_zos_core
ansible_cfg: ./ansible.cfg # optional
vault_password_file: ~/.vault_pass # optional
extra_envvars: # optional
ZOAU_HOME: /usr/lpp/IBM/zoautil
modules accepts a specific module (ansible.builtin.copy), a collection
(ansible.builtin), or a namespace (community).
Multiple profiles can live under .rocannon/profiles/:
.rocannon/profiles/
├── box1.yml
├── box2.yml
└── default.yml -> box1.yml
rocannon mcp serve # uses default.yml
rocannon mcp serve --profile box2
The active profile can be switched at runtime via three MCP tools:
rocannon_list_profiles, rocannon_current_profile, rocannon_use_profile.
The tool surface is the union of every profile's modules; a call to a module
that isn't in the active profile returns a structured error pointing at
rocannon_use_profile.
MCP clients
A working .mcp.json ships at the repo root. Per-client snippets are in
examples/clients/.
| Client | Config location |
|---|---|
| Claude Code | .mcp.json at project root, or claude mcp add |
| Claude Desktop | macOS: ~/Library/Application Support/Claude/claude_desktop_config.json |
| Cursor | .cursor/mcp.json or ~/.cursor/mcp.json |
| mcphost | ~/.mcphost.yml or --config <path> |
| IBM Bob | .bob/mcp.json or ~/.bob/mcp_settings.json |
All share the standard mcpServers envelope pointing at
rocannon mcp serve --profile <your-profile.yml>.
Development
git clone https://github.com/msradam/rocannon.git
cd rocannon
uv sync
./tests/check.sh # ruff format + lint + mypy + pytest
uv run pytest -m integration # opt-in: spins up a real UBI9 container
See ARCHITECTURE.md for how the pieces fit together.
Rocannon is developed with AI assistance.
The name
Ursula K. Le Guin coined the word "ansible" in her 1966 novel Rocannon's World. The gryphon is a nod to the Windsteeds that Rocannon and his companions ride.
Credits
- Gryphon icon: Gryphon by Aleksei Kovalenko from Noun Project (CC BY 3.0).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rocannon-0.1.1.tar.gz.
File metadata
- Download URL: rocannon-0.1.1.tar.gz
- Upload date:
- Size: 45.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6233334af02161d418eeb011c427548c1f35d21551d52a9ace07d51c0423f70
|
|
| MD5 |
2d63929ba4efc4250a8668312d634d4f
|
|
| BLAKE2b-256 |
f426a802615c6fb49d1171f99c19390a0b3d85c8255c572c3551b04ca69cfb51
|
File details
Details for the file rocannon-0.1.1-py3-none-any.whl.
File metadata
- Download URL: rocannon-0.1.1-py3-none-any.whl
- Upload date:
- Size: 51.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99b948fba98c1e33e50cd8f8d7259795c896c2521fd8e509e32ce534f1aa6bb3
|
|
| MD5 |
0b6ba4bf0d1c6d0854ce99965d98e562
|
|
| BLAKE2b-256 |
b145888dd450af5745b4b59a00491e67eaffbe354c2dc0c5a726e105ac5ed05e
|