Files
computer-playbook/roles/web-app-moodle/tasks/utils/mcp/provision.yml
kevinveenbirkenbachandClaude Opus 5.5 df214dd00a refactor(web-app-moodle): group the provisioning scripts in files/php/provision
provision_ai_gateway.php and provision_mcp.php shared a prefix inside one
directory, which test_prefix_grouped_files rejects. Both move into
files/php/provision/ as ai_gateway.php and mcp.php, the layout
web-app-n8n already uses for its Python provisioning scripts.

The two lookups that feed the scripts to the container follow, and the
unit test moves to its mirrored path as provision/AiGatewayTest.php.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 01:37:03 +02:00

56 lines
2.6 KiB
YAML

---
- name: "🔑 Register the MCP web service and mint its permanent token"
ansible.builtin.shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i --user {{ MOODLE_RUNTIME_USER }} \
-e MOODLE_CONFIG={{ MOODLE_CONFIG | quote }} \
-e MCP_SERVICE_NAME={{ MOODLE_MCP_EXTERNAL_SERVICE_NAME | quote }} \
-e MCP_SERVICE_SHORTNAME={{ MOODLE_MCP_EXTERNAL_SERVICE_SHORTNAME | quote }} \
-e MCP_SERVICE_FUNCTIONS={{ MOODLE_MCP_EXTERNAL_FUNCTIONS | join(',') | quote }} \
-e MCP_ACCOUNT_USERNAME={{ MOODLE_MCP_ACCOUNT_USERNAME | quote }} \
-e MCP_ACCOUNT_EMAIL={{ MOODLE_MCP_ACCOUNT_EMAIL | quote }} \
-e MCP_ACCOUNT_PASSWORD={{ MOODLE_MCP_ACCOUNT_PASSWORD | quote }} \
-e MCP_ROLE_SHORTNAME={{ MOODLE_MCP_ROLE_SHORTNAME | quote }} \
-e MCP_ROLE_NAME={{ MOODLE_MCP_ROLE_NAME | quote }} \
-e MCP_ROLE_CAPABILITIES={{ MOODLE_MCP_ROLE_CAPABILITIES | join(',') | quote }} \
{{ MOODLE_MCP_LOCAL_CID | quote }} php
args:
stdin: "{{ lookup('file', 'php/provision/mcp.php') }}"
register: moodle_mcp_provision
changed_when: false
delegate_to: "{{ MOODLE_MCP_HOST_NODE }}"
run_once: true
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "🔧 Take the minted token from the provisioning output"
ansible.builtin.set_fact:
moodle_mcp_token: "{{ moodle_mcp_provision.stdout_lines | last | trim }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
run_once: true
- name: "🛑 Refuse a Moodle that issued no usable web-service token"
ansible.builtin.assert:
that:
- moodle_mcp_token is match('^[a-f0-9]{32}$')
fail_msg: >-
Moodle returned no web-service token, so every MCP client would be
configured with an empty bearer and fail at first use.
- name: "🧹 Purge the Moodle caches so the MCP protocol takes effect"
ansible.builtin.shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec --user {{ MOODLE_RUNTIME_USER }} {{ MOODLE_MCP_LOCAL_CID | quote }} \
php {{ MOODLE_CLI_DIR }}/purge_caches.php
changed_when: true
delegate_to: "{{ MOODLE_MCP_HOST_NODE }}"
run_once: true
notify: container-recreate
- name: "💾 Persist the token so MCP clients can read it"
ansible.builtin.include_role:
name: sys-token-store
tasks_from: write.yml
vars:
sys_token_store_user_key: "{{ lookup('config', application_id, 'mcp.credential.owner') }}"
sys_token_store_app: "{{ application_id }}"
sys_token_store_token: "{{ moodle_mcp_token }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"