Profiles

A profile is a YAML file that declares which inventory to use and which modules and roles to expose as MCP tools. Rocannon reads one or more profiles at startup and registers the union of their tools.

Full profile reference

inventories:
  - ./hosts                        # path to inventory file or directory
  - ./hosts.d/                     # multiple inventories are supported

modules:
  - ansible.builtin.copy           # a single module FQCN
  - ansible.builtin                # a whole collection → all its modules
  - community                      # a namespace → all collections in it
  - community.docker               # mix module, collection, namespace specs freely

roles:                             # optional
  - my_ns.my_coll.setup_web        # FQCN for a collection role
  - standalone_role                # bare name for a standalone role (needs roles_path)

roles_path: ./roles                # optional; resolves against the profile file's directory

ansible_cfg: ./ansible.cfg         # optional; sets ANSIBLE_CONFIG for module runs

vault_password_file: ./vault.key   # optional; sets ANSIBLE_VAULT_PASSWORD_FILE

extra_envvars:                     # optional; merged into the ansible-runner environment
  CUSTOM_VAR: value
  ANOTHER_VAR: other

timeouts:                          # optional; per-module execution timeout in seconds
  ansible.builtin.command: 60      # default is 300s (5 minutes)
  ansible.builtin.shell: 60
All file paths in a profile resolve relative to the profile file's directory, not the process CWD. This is what makes absolute-path invocations from MCP clients work correctly.

Configuration keys

Key Required Description
inventories required List of paths to Ansible inventory files or directories. Rocannon delegates all parsing (group_vars, Jinja2, dynamic inventories) to ansible-inventory.
modules required* List of module, collection, or namespace specs. A namespace like community expands to every installed module in that namespace. Only modules become tools; filter and lookup plugins are skipped. *Required unless roles is set.
roles optional List of role names to expose. A collection role uses its FQCN (my_ns.my_coll.role). A standalone role uses its directory name. Roles without meta/argument_specs.yml are skipped (Rocannon cannot build a typed interface without a documented spec).
roles_path optional Directory containing standalone roles. Set this when roles are not in a collection and not on the default Ansible roles path.
ansible_cfg optional Path to an ansible.cfg file. Passed to ansible-runner as ANSIBLE_CONFIG.
vault_password_file optional Path to a Vault password file. Passed as ANSIBLE_VAULT_PASSWORD_FILE. Vault-encrypted variables in inventory or host_vars are decrypted automatically.
extra_envvars optional Key-value pairs merged into the subprocess environment for every module run. Useful for passing credentials that modules read from environment variables (e.g. AWS_PROFILE, ZOAU_HOME).
timeouts optional Per-module execution timeout in seconds. The global default is 300s (overridden by ROCANNON_TIMEOUT). Set shorter timeouts for modules that should fail fast, or longer ones for slow provisioning steps.

Profile discovery

When you run rocannon mcp serve without --profile, Rocannon walks up from the current directory looking for .rocannon/profiles/. If it finds the directory, it loads every *.yml file in it as a named profile.

Default profile resolution order:

  1. default.yml as a symlink; the symlink target's stem becomes the active name
  2. default.yml as a regular file
  3. The only profile in the directory, if exactly one exists
  4. Falls back to ~/.rocannon/profiles/ if no project-level directory is found

Runtime switching

Load multiple profiles in .rocannon/profiles/ and switch between them at runtime without restarting the server:

# In your MCP client or REPL:
rocannon_list_profiles     → lists all profiles and which is active
rocannon_current_profile   → returns the active profile's full config
rocannon_use_profile       → switches to a named profile

Tool functions read the active profile's inventory, envvars, and timeouts on every call. A profile switch takes effect immediately for subsequent calls.

Union registration. Rocannon registers the union of every profile's modules at startup. Calling a module that isn't in the active profile returns a structured error pointing at rocannon_use_profile, rather than failing inside ansible-runner.

Example: dev/staging/prod

.rocannon/profiles/
  dev.yml         → dev inventory, full module set, permissive timeouts
  staging.yml     → staging inventory, same modules, tighter timeouts
  prod.yml        → production inventory, restricted module subset
  default.yml     → symlink → dev.yml

The agent sees all module tools on startup. rocannon_use_profile("prod") narrows execution to the production inventory and module subset without re-registering anything.

Example: network automation

inventories:
  - ./inventory/network.yml    # Arista and Cisco hosts

modules:
  - arista.eos
  - cisco.ios
  - ansible.netcommon

ansible_cfg: ./ansible-network.cfg   # network-optimised connection settings

timeouts:
  arista.eos.eos_config: 120         # config pushes can be slow on large devices

Dependencies: modules with third-party libraries

Some modules require Python packages beyond ansible-core:

CollectionPython dependency
community.dockerpip install docker
community.cryptopip install cryptography
community.mongodbpip install pymongo
community.postgresqlpip install psycopg2-binary
amazon.awspip install boto3
kubernetes.corepip install kubernetes

Install these in the same environment as Rocannon. The quickstart profile pins ansible_python_interpreter so localhost modules use the right interpreter automatically.