From 740f55155d267531e3c86f794997b064876e3fa4 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Tue, 4 Nov 2025 16:23:37 -0500 Subject: [PATCH 01/17] Add server_info action plugin --- plugins/action/server_info.py | 49 +++++++++++++++++++++ plugins/modules/server_info.py | 80 ++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 plugins/action/server_info.py create mode 100644 plugins/modules/server_info.py diff --git a/plugins/action/server_info.py b/plugins/action/server_info.py new file mode 100644 index 0000000..f75c975 --- /dev/null +++ b/plugins/action/server_info.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2025 Red Hat, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from ansible.errors import AnsibleActionFail +from ansible.module_utils.connection import Connection +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + """Action plugin to retrieve MCP server information.""" + + def run(self, tmp=None, task_vars=None): + """Execute the server_info action. + + Returns: + dict: Ansible result dictionary containing server_info + """ + if task_vars is None: + task_vars = {} + + result = super(ActionModule, self).run(tmp, task_vars) + result["changed"] = False + + # Ensure we're using the MCP connection + connection_type = self._play_context.connection + if not connection_type or not connection_type.endswith(".mcp"): + raise AnsibleActionFail( + "Connection type %s is not valid for server_info module, " + "please use fully qualified name of MCP connection type." + % connection_type + ) + + # Get socket path from connection + socket_path = self._connection.socket_path + if socket_path is None: + raise AnsibleActionFail("socket_path is not available from connection") + + try: + # Use Connection class to call server_info on the connection plugin + conn = Connection(socket_path) + server_info = conn.server_info() + + result["server_info"] = server_info + return result + + except Exception as e: + raise AnsibleActionFail("Failed to retrieve server info: %s" % str(e)) diff --git a/plugins/modules/server_info.py b/plugins/modules/server_info.py new file mode 100644 index 0000000..e31d33b --- /dev/null +++ b/plugins/modules/server_info.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2025 Red Hat, Inc. +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" + +module: server_info + +short_description: Retrieve MCP server information + +author: + - Bianca Henderson (@beeankha) + +description: + - This module retrieves server information from an MCP (Model Context Protocol) server. + - The server information is returned from the initialization step of the MCP connection. + - This module requires the MCP connection plugin to be configured. + +version_added: "1.0.0" + +notes: + - This module requires the MCP connection plugin (ansible.mcp.mcp) to be configured. + - The connection plugin must be initialized before this module can retrieve server information. + - Server information is retrieved from the MCP server's initialization response. +""" + +EXAMPLES = r""" +- name: Retrieve server info from GitHub MCP server + ansible.mcp.server_info: + register: gh_mcp_server_info + +- name: Display server info + ansible.builtin.debug: + var: gh_mcp_server_info + +- name: Retrieve server info from AWS IAM MCP server + ansible.mcp.server_info: + register: aws_mcp_server_info + +- name: Display AWS server info + ansible.builtin.debug: + var: aws_mcp_server_info +""" + +RETURN = r""" +server_info: + description: Server information returned from the MCP server initialization. + returned: success + type: dict + contains: + protocolVersion: + description: MCP protocol version supported by the server. + returned: success + type: str + sample: "2025-03-26" + serverInfo: + description: Information about the MCP server. + returned: success + type: dict + contains: + name: + description: Name of the MCP server. + returned: success + type: str + sample: "github-server" + version: + description: Version of the MCP server. + returned: success + type: str + sample: "1.0.0" + capabilities: + description: Capabilities supported by the MCP server. + returned: success + type: dict +""" From c7af33c928b11f559c3fda59164a80fa380061a4 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Tue, 4 Nov 2025 16:38:19 -0500 Subject: [PATCH 02/17] Fix linter error --- plugins/action/server_info.py | 3 +-- plugins/modules/server_info.py | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/action/server_info.py b/plugins/action/server_info.py index f75c975..ba8f89b 100644 --- a/plugins/action/server_info.py +++ b/plugins/action/server_info.py @@ -28,8 +28,7 @@ def run(self, tmp=None, task_vars=None): if not connection_type or not connection_type.endswith(".mcp"): raise AnsibleActionFail( "Connection type %s is not valid for server_info module, " - "please use fully qualified name of MCP connection type." - % connection_type + "please use fully qualified name of MCP connection type." % connection_type ) # Get socket path from connection diff --git a/plugins/modules/server_info.py b/plugins/modules/server_info.py index e31d33b..91070ae 100644 --- a/plugins/modules/server_info.py +++ b/plugins/modules/server_info.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, division, print_function + __metaclass__ = type DOCUMENTATION = r""" From 51074dc3c9fa647f0ef41f75a6454882a0f61bbd Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Tue, 4 Nov 2025 20:16:34 -0500 Subject: [PATCH 03/17] Remove unnecessary intermediate variable for conn.server_info() --- plugins/action/server_info.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/action/server_info.py b/plugins/action/server_info.py index ba8f89b..983f542 100644 --- a/plugins/action/server_info.py +++ b/plugins/action/server_info.py @@ -39,9 +39,7 @@ def run(self, tmp=None, task_vars=None): try: # Use Connection class to call server_info on the connection plugin conn = Connection(socket_path) - server_info = conn.server_info() - - result["server_info"] = server_info + result["server_info"] = conn.server_info() return result except Exception as e: From adce35bd37df7595660f6e5c1701cabd463d907a Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Wed, 5 Nov 2025 15:22:59 -0500 Subject: [PATCH 04/17] Add integration test --- .../targets/server_info/inventory.yml | 19 ++++++++++ .../integration/targets/server_info/runme.sh | 17 +++++++++ .../targets/server_info/tasks/main.yml | 38 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 tests/integration/targets/server_info/inventory.yml create mode 100755 tests/integration/targets/server_info/runme.sh create mode 100644 tests/integration/targets/server_info/tasks/main.yml diff --git a/tests/integration/targets/server_info/inventory.yml b/tests/integration/targets/server_info/inventory.yml new file mode 100644 index 0000000..f04f00d --- /dev/null +++ b/tests/integration/targets/server_info/inventory.yml @@ -0,0 +1,19 @@ +all: + children: + mcp_servers: + hosts: + github_server: + ansible_connection: ansible.mcp.mcp + ansible_mcp_server_name: github-server + ansible_mcp_server_args: [] + ansible_mcp_server_env: {} + ansible_mcp_manifest_path: /opt/mcp/mcpservers.json + aws_iam_server: + ansible_connection: ansible.mcp.mcp + ansible_mcp_server_name: aws-iam-mcp-server + ansible_mcp_server_args: + - --readonly + ansible_mcp_server_env: + AWS_REGION: us-east-1 + AWS_PROFILE: default + ansible_mcp_manifest_path: /opt/mcp/mcpservers.json diff --git a/tests/integration/targets/server_info/runme.sh b/tests/integration/targets/server_info/runme.sh new file mode 100755 index 0000000..b28d686 --- /dev/null +++ b/tests/integration/targets/server_info/runme.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -eux +export ANSIBLE_CALLBACKS_ENABLED=profile_tasks +export ANSIBLE_ROLES_PATH=../ + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +GITHUB_PAT_VALUE="${ANSIBLE_TEST_GITHUB_PAT:-${GITHUB_PAT:-${GITHUB_TOKEN:-${GITHUB_PERSONAL_ACCESS_TOKEN:-}}}}" + +EXTRA_VARS="" +if [ -n "${GITHUB_PAT_VALUE:-}" ]; then + EXTRA_VARS="-e github_pat='${GITHUB_PAT_VALUE}'" +fi + +INVENTORY="${SCRIPT_DIR}/inventory.yml" + +ansible-playbook -i "${INVENTORY}" tasks/main.yml ${EXTRA_VARS} "$@" diff --git a/tests/integration/targets/server_info/tasks/main.yml b/tests/integration/targets/server_info/tasks/main.yml new file mode 100644 index 0000000..42a8e10 --- /dev/null +++ b/tests/integration/targets/server_info/tasks/main.yml @@ -0,0 +1,38 @@ +--- +- name: Test server_info with GitHub MCP server + hosts: github_server + gather_facts: false + tasks: + - name: Retrieve server info from GitHub MCP server + ansible.mcp.server_info: + register: github_server_info + when: github_pat is defined and github_pat | length > 0 + + - name: Verify GitHub server_info result succeeded + ansible.builtin.assert: + that: + - not github_server_info.failed | default(false) + - github_server_info.server_info is defined + - github_server_info.server_info.serverInfo is defined + - github_server_info.server_info.serverInfo.name is defined + - github_server_info.server_info.serverInfo.version is defined + fail_msg: "GitHub server_info does not contain expected structure" + when: github_pat is defined and github_pat | length > 0 + +- name: Test server_info with AWS IAM MCP server + hosts: aws_iam_server + gather_facts: false + tasks: + - name: Retrieve server info from AWS IAM MCP server + ansible.mcp.server_info: + register: aws_server_info + + - name: Verify AWS server_info result succeeded + ansible.builtin.assert: + that: + - not aws_server_info.failed | default(false) + - aws_server_info.server_info is defined + - aws_server_info.server_info.serverInfo is defined + - aws_server_info.server_info.serverInfo.name is defined + - aws_server_info.server_info.serverInfo.version is defined + fail_msg: "AWS server_info does not contain expected structure" From 10a279f2d3e91c1e623d06d2893ef0afb4c01308 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Wed, 5 Nov 2025 15:30:00 -0500 Subject: [PATCH 05/17] Add .ansible-lint file --- .ansible-lint | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .ansible-lint diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..c174bd0 --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,7 @@ +--- +profile: production + +exclude_paths: + - .github/ + - tests/integration + From 591f9657da2fa17fe0502d1942900a7da0875f29 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Wed, 5 Nov 2025 15:35:08 -0500 Subject: [PATCH 06/17] Update runme.sh --- tests/integration/targets/server_info/runme.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/integration/targets/server_info/runme.sh b/tests/integration/targets/server_info/runme.sh index b28d686..1a9e59c 100755 --- a/tests/integration/targets/server_info/runme.sh +++ b/tests/integration/targets/server_info/runme.sh @@ -7,11 +7,10 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" GITHUB_PAT_VALUE="${ANSIBLE_TEST_GITHUB_PAT:-${GITHUB_PAT:-${GITHUB_TOKEN:-${GITHUB_PERSONAL_ACCESS_TOKEN:-}}}}" -EXTRA_VARS="" -if [ -n "${GITHUB_PAT_VALUE:-}" ]; then - EXTRA_VARS="-e github_pat='${GITHUB_PAT_VALUE}'" -fi - INVENTORY="${SCRIPT_DIR}/inventory.yml" -ansible-playbook -i "${INVENTORY}" tasks/main.yml ${EXTRA_VARS} "$@" +if [ -n "${GITHUB_PAT_VALUE:-}" ]; then + ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "github_pat=${GITHUB_PAT_VALUE}" "$@" +else + ansible-playbook -i "${INVENTORY}" tasks/main.yml "$@" +fi From 7fae3a4e330b4a9b0fb4ac0e51e12c001f71bf0a Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Wed, 5 Nov 2025 15:46:13 -0500 Subject: [PATCH 07/17] Remove blank line for linter --- .ansible-lint | 1 - 1 file changed, 1 deletion(-) diff --git a/.ansible-lint b/.ansible-lint index c174bd0..55cbb4c 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -4,4 +4,3 @@ profile: production exclude_paths: - .github/ - tests/integration - From 758e4835de8623295d23437a26846e28a57a221f Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Thu, 6 Nov 2025 11:14:11 -0500 Subject: [PATCH 08/17] Update GH test workflow file to recognize integration tests --- .github/workflows/tests.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7b65473..d61c2d1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,6 +65,8 @@ jobs: "python": "3.12" } ] + integration: + uses: ansible/ansible-content-actions/.github/workflows/integration.yaml@main all_green: if: ${{ always() }} needs: @@ -72,13 +74,15 @@ jobs: - sanity - unit-galaxy - ansible-lint + - integration runs-on: ubuntu-latest steps: - run: >- python -c "assert 'failure' not in set([ '${{ needs.sanity.result }}', - '${{ needs.unit-galaxy.result }}' - '${{ needs.ansible-lint.result }}' - '${{ needs.build-import.result }}' + '${{ needs.unit-galaxy.result }}', + '${{ needs.ansible-lint.result }}', + '${{ needs.build-import.result }}', + '${{ needs.integration.result }}' ])" From 15651ecebe111b40fca392c21132122f3c9a8394 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Thu, 6 Nov 2025 13:35:48 -0500 Subject: [PATCH 09/17] Update GH integration workflow file --- .github/workflows/tests.yml | 43 ++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d61c2d1..1fecd5d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -66,7 +66,48 @@ jobs: } ] integration: - uses: ansible/ansible-content-actions/.github/workflows/integration.yaml@main + runs-on: ubuntu-latest + timeout-minutes: 60 + env: + ansible_version: "milestone" + python_version: "3.12" + steps: + - name: Checkout collection + uses: actions/checkout@v4 + + - name: Set up Python ${{ env.python_version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ env.python_version }} + + - name: Install ansible-core (${{ env.ansible_version }}) + run: >- + python3 -m pip install + https://github.com/ansible/ansible/archive/${{ env.ansible_version }}.tar.gz + --disable-pip-version-check + shell: bash + + - name: Build and install collection + id: install-collection + uses: ansible-network/github_actions/.github/actions/build_install_collection@main + with: + install_python_dependencies: true + source_path: . + + - name: Set up git + run: | + git config --global user.email gha@localhost + git config --global user.name "Github Actions" + shell: bash + + - name: Run integration tests + uses: ansible-network/github_actions/.github/actions/ansible_test_integration@main + with: + collection_path: ${{ steps.install-collection.outputs.collection_path }} + python_version: ${{ env.python_version }} + ansible_version: ${{ env.ansible_version }} + env: + ANSIBLE_TEST_GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} all_green: if: ${{ always() }} needs: From e0044372a495676259d813152bc03c0fc59cc8d9 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Thu, 6 Nov 2025 13:55:30 -0500 Subject: [PATCH 10/17] Remove requirements.txt file, update GH workflow file --- .github/workflows/tests.yml | 3 ++- .../targets/server_info/mcpservers.json | 15 +++++++++++++++ tests/integration/targets/server_info/runme.sh | 5 +++-- .../targets/server_info/tasks/main.yml | 4 ++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 tests/integration/targets/server_info/mcpservers.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1fecd5d..efdea06 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -91,7 +91,7 @@ jobs: id: install-collection uses: ansible-network/github_actions/.github/actions/build_install_collection@main with: - install_python_dependencies: true + install_python_dependencies: false source_path: . - name: Set up git @@ -106,6 +106,7 @@ jobs: collection_path: ${{ steps.install-collection.outputs.collection_path }} python_version: ${{ env.python_version }} ansible_version: ${{ env.ansible_version }} + ansible_test_requirement_files: 'test-requirements.txt' env: ANSIBLE_TEST_GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} all_green: diff --git a/tests/integration/targets/server_info/mcpservers.json b/tests/integration/targets/server_info/mcpservers.json new file mode 100644 index 0000000..6dd032d --- /dev/null +++ b/tests/integration/targets/server_info/mcpservers.json @@ -0,0 +1,15 @@ +{ + "github-server": { + "type": "stdio", + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-github"], + "description": "GitHub MCP Server - Access GitHub repositories, issues, and pull requests" + }, + "aws-iam-mcp-server": { + "type": "stdio", + "command": "uvx", + "args": ["awslabs.iam-mcp-server"], + "description": "AWS IAM MCP Server - Manage AWS IAM resources through MCP protocol" + } +} + diff --git a/tests/integration/targets/server_info/runme.sh b/tests/integration/targets/server_info/runme.sh index 1a9e59c..36ff6b9 100755 --- a/tests/integration/targets/server_info/runme.sh +++ b/tests/integration/targets/server_info/runme.sh @@ -8,9 +8,10 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" GITHUB_PAT_VALUE="${ANSIBLE_TEST_GITHUB_PAT:-${GITHUB_PAT:-${GITHUB_TOKEN:-${GITHUB_PERSONAL_ACCESS_TOKEN:-}}}}" INVENTORY="${SCRIPT_DIR}/inventory.yml" +MANIFEST_PATH="${SCRIPT_DIR}/mcpservers.json" if [ -n "${GITHUB_PAT_VALUE:-}" ]; then - ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "github_pat=${GITHUB_PAT_VALUE}" "$@" + ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" -e "github_pat=${GITHUB_PAT_VALUE}" "$@" else - ansible-playbook -i "${INVENTORY}" tasks/main.yml "$@" + ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" "$@" fi diff --git a/tests/integration/targets/server_info/tasks/main.yml b/tests/integration/targets/server_info/tasks/main.yml index 42a8e10..df3c8bf 100644 --- a/tests/integration/targets/server_info/tasks/main.yml +++ b/tests/integration/targets/server_info/tasks/main.yml @@ -2,6 +2,8 @@ - name: Test server_info with GitHub MCP server hosts: github_server gather_facts: false + vars: + ansible_mcp_manifest_path: "{{ ansible_mcp_manifest_path | default(playbook_dir | dirname + '/mcpservers.json') }}" tasks: - name: Retrieve server info from GitHub MCP server ansible.mcp.server_info: @@ -22,6 +24,8 @@ - name: Test server_info with AWS IAM MCP server hosts: aws_iam_server gather_facts: false + vars: + ansible_mcp_manifest_path: "{{ ansible_mcp_manifest_path | default(playbook_dir | dirname + '/mcpservers.json') }}" tasks: - name: Retrieve server info from AWS IAM MCP server ansible.mcp.server_info: From 5e6a21537e661f92ee8c359ccdad11ac9275497f Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Thu, 6 Nov 2025 15:02:00 -0500 Subject: [PATCH 11/17] Add uv to requirements file for tests, update test workflow files --- .github/workflows/tests.yml | 4 ++-- test-requirements.txt | 2 ++ tests/integration/targets/server_info/tasks/main.yml | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index efdea06..c697884 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -107,8 +107,8 @@ jobs: python_version: ${{ env.python_version }} ansible_version: ${{ env.ansible_version }} ansible_test_requirement_files: 'test-requirements.txt' - env: - ANSIBLE_TEST_GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + ansible_test_environment: | + ANSIBLE_TEST_GITHUB_PAT=${{ secrets.GITHUB_TOKEN }} all_green: if: ${{ always() }} needs: diff --git a/test-requirements.txt b/test-requirements.txt index 78ee7b0..f8bce3f 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,3 +2,5 @@ pytest-ansible pytest-xdist ansible-compat +# uv provides uvx command-line tool needed for AWS IAM MCP server integration tests +uv diff --git a/tests/integration/targets/server_info/tasks/main.yml b/tests/integration/targets/server_info/tasks/main.yml index df3c8bf..01422a3 100644 --- a/tests/integration/targets/server_info/tasks/main.yml +++ b/tests/integration/targets/server_info/tasks/main.yml @@ -27,9 +27,17 @@ vars: ansible_mcp_manifest_path: "{{ ansible_mcp_manifest_path | default(playbook_dir | dirname + '/mcpservers.json') }}" tasks: + - name: Check if uvx is available + ansible.builtin.command: which uvx + register: uvx_check + changed_when: false + failed_when: false + check_mode: false + - name: Retrieve server info from AWS IAM MCP server ansible.mcp.server_info: register: aws_server_info + when: uvx_check.rc == 0 - name: Verify AWS server_info result succeeded ansible.builtin.assert: @@ -40,3 +48,4 @@ - aws_server_info.server_info.serverInfo.name is defined - aws_server_info.server_info.serverInfo.version is defined fail_msg: "AWS server_info does not contain expected structure" + when: uvx_check.rc == 0 From f7f5e4fcdfb72c23265615de22b3a46034a12076 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Fri, 7 Nov 2025 11:08:24 -0500 Subject: [PATCH 12/17] Remove integration test from github workflow file --- .github/workflows/tests.yml | 48 +------------------------------------ 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c697884..c2029cc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -65,50 +65,6 @@ jobs: "python": "3.12" } ] - integration: - runs-on: ubuntu-latest - timeout-minutes: 60 - env: - ansible_version: "milestone" - python_version: "3.12" - steps: - - name: Checkout collection - uses: actions/checkout@v4 - - - name: Set up Python ${{ env.python_version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ env.python_version }} - - - name: Install ansible-core (${{ env.ansible_version }}) - run: >- - python3 -m pip install - https://github.com/ansible/ansible/archive/${{ env.ansible_version }}.tar.gz - --disable-pip-version-check - shell: bash - - - name: Build and install collection - id: install-collection - uses: ansible-network/github_actions/.github/actions/build_install_collection@main - with: - install_python_dependencies: false - source_path: . - - - name: Set up git - run: | - git config --global user.email gha@localhost - git config --global user.name "Github Actions" - shell: bash - - - name: Run integration tests - uses: ansible-network/github_actions/.github/actions/ansible_test_integration@main - with: - collection_path: ${{ steps.install-collection.outputs.collection_path }} - python_version: ${{ env.python_version }} - ansible_version: ${{ env.ansible_version }} - ansible_test_requirement_files: 'test-requirements.txt' - ansible_test_environment: | - ANSIBLE_TEST_GITHUB_PAT=${{ secrets.GITHUB_TOKEN }} all_green: if: ${{ always() }} needs: @@ -116,7 +72,6 @@ jobs: - sanity - unit-galaxy - ansible-lint - - integration runs-on: ubuntu-latest steps: - run: >- @@ -125,6 +80,5 @@ jobs: '${{ needs.sanity.result }}', '${{ needs.unit-galaxy.result }}', '${{ needs.ansible-lint.result }}', - '${{ needs.build-import.result }}', - '${{ needs.integration.result }}' + '${{ needs.build-import.result }}' ])" From f128afede17fa1eef5b83a862578e4da354aa54f Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Fri, 7 Nov 2025 11:13:44 -0500 Subject: [PATCH 13/17] Add alias file --- tests/integration/targets/server_info/aliases | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/integration/targets/server_info/aliases diff --git a/tests/integration/targets/server_info/aliases b/tests/integration/targets/server_info/aliases new file mode 100644 index 0000000..4ef4b20 --- /dev/null +++ b/tests/integration/targets/server_info/aliases @@ -0,0 +1 @@ +cloud/aws From 3b8f101d1f75c139d8e2d644af60a4e4cc02842e Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Fri, 7 Nov 2025 15:23:27 -0500 Subject: [PATCH 14/17] More updates to integration test setup --- plugins/connection/mcp.py | 4 +-- .../{inventory.yml => inventory.yml.j2} | 8 +++++- .../targets/server_info/mcpservers.json | 15 ----------- .../integration/targets/server_info/runme.sh | 27 +++++++++++++++---- .../targets/server_info/tasks/main.yml | 10 +++++-- 5 files changed, 39 insertions(+), 25 deletions(-) rename tests/integration/targets/server_info/{inventory.yml => inventory.yml.j2} (74%) delete mode 100644 tests/integration/targets/server_info/mcpservers.json diff --git a/plugins/connection/mcp.py b/plugins/connection/mcp.py index 5419e8e..ac5cdda 100644 --- a/plugins/connection/mcp.py +++ b/plugins/connection/mcp.py @@ -30,8 +30,6 @@ elements: str vars: - name: ansible_mcp_server_args - env: - - name: MCP_BEARER_TOKEN server_env: description: - Additional environment variables to pass to the server when using stdio transport. @@ -47,6 +45,8 @@ type: str vars: - name: ansible_mcp_bearer_token + env: + - name: MCP_BEARER_TOKEN manifest_path: description: - Path to MCP manifest JSON file to resolve server executable paths for stdio. diff --git a/tests/integration/targets/server_info/inventory.yml b/tests/integration/targets/server_info/inventory.yml.j2 similarity index 74% rename from tests/integration/targets/server_info/inventory.yml rename to tests/integration/targets/server_info/inventory.yml.j2 index f04f00d..26ab92c 100644 --- a/tests/integration/targets/server_info/inventory.yml +++ b/tests/integration/targets/server_info/inventory.yml.j2 @@ -6,7 +6,12 @@ all: ansible_connection: ansible.mcp.mcp ansible_mcp_server_name: github-server ansible_mcp_server_args: [] - ansible_mcp_server_env: {} + ansible_mcp_server_env: +{% if github_mcp_pat is defined and github_mcp_pat | length > 0 %} + GITHUB_PERSONAL_ACCESS_TOKEN: "{{ github_mcp_pat }}" +{% else %} + {} +{% endif %} ansible_mcp_manifest_path: /opt/mcp/mcpservers.json aws_iam_server: ansible_connection: ansible.mcp.mcp @@ -17,3 +22,4 @@ all: AWS_REGION: us-east-1 AWS_PROFILE: default ansible_mcp_manifest_path: /opt/mcp/mcpservers.json + diff --git a/tests/integration/targets/server_info/mcpservers.json b/tests/integration/targets/server_info/mcpservers.json deleted file mode 100644 index 6dd032d..0000000 --- a/tests/integration/targets/server_info/mcpservers.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "github-server": { - "type": "stdio", - "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-github"], - "description": "GitHub MCP Server - Access GitHub repositories, issues, and pull requests" - }, - "aws-iam-mcp-server": { - "type": "stdio", - "command": "uvx", - "args": ["awslabs.iam-mcp-server"], - "description": "AWS IAM MCP Server - Manage AWS IAM resources through MCP protocol" - } -} - diff --git a/tests/integration/targets/server_info/runme.sh b/tests/integration/targets/server_info/runme.sh index 36ff6b9..ccc6f89 100755 --- a/tests/integration/targets/server_info/runme.sh +++ b/tests/integration/targets/server_info/runme.sh @@ -4,14 +4,31 @@ export ANSIBLE_CALLBACKS_ENABLED=profile_tasks export ANSIBLE_ROLES_PATH=../ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MANIFEST_PATH="${SCRIPT_DIR}/mcpservers.json" +INVENTORY="${SCRIPT_DIR}/inventory.yml" -GITHUB_PAT_VALUE="${ANSIBLE_TEST_GITHUB_PAT:-${GITHUB_PAT:-${GITHUB_TOKEN:-${GITHUB_PERSONAL_ACCESS_TOKEN:-}}}}" +# Cleanup function to remove generated inventory file +cleanup() { + local exit_code=$? + rm -f "${INVENTORY}" + exit "${exit_code}" +} -INVENTORY="${SCRIPT_DIR}/inventory.yml" -MANIFEST_PATH="${SCRIPT_DIR}/mcpservers.json" +# Set up trap early to ensure cleanup runs on error/early exit +trap cleanup EXIT +GITHUB_PAT_VALUE="${github_mcp_pat:-${ANSIBLE_TEST_GITHUB_PAT:-${GITHUB_PAT:-${GITHUB_TOKEN:-${GITHUB_PERSONAL_ACCESS_TOKEN:-}}}}}" + +# Generate inventory file with PAT injected from template +# This will overwrite the existing inventory.yml file with the generated version if [ -n "${GITHUB_PAT_VALUE:-}" ]; then - ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" -e "github_pat=${GITHUB_PAT_VALUE}" "$@" + ansible-playbook -c local generate_inventory.yml -e "github_mcp_pat=${GITHUB_PAT_VALUE}" "$@" else - ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" "$@" + ansible-playbook -c local generate_inventory.yml "$@" fi + +# Run integration tests +ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" "$@" + +# Delete generated inventory file after tests complete +rm -f "${INVENTORY}" diff --git a/tests/integration/targets/server_info/tasks/main.yml b/tests/integration/targets/server_info/tasks/main.yml index 01422a3..a0689d7 100644 --- a/tests/integration/targets/server_info/tasks/main.yml +++ b/tests/integration/targets/server_info/tasks/main.yml @@ -8,7 +8,10 @@ - name: Retrieve server info from GitHub MCP server ansible.mcp.server_info: register: github_server_info - when: github_pat is defined and github_pat | length > 0 + when: > + ansible_mcp_server_env is defined and + ansible_mcp_server_env.GITHUB_PERSONAL_ACCESS_TOKEN is defined and + ansible_mcp_server_env.GITHUB_PERSONAL_ACCESS_TOKEN | length > 0 - name: Verify GitHub server_info result succeeded ansible.builtin.assert: @@ -19,7 +22,10 @@ - github_server_info.server_info.serverInfo.name is defined - github_server_info.server_info.serverInfo.version is defined fail_msg: "GitHub server_info does not contain expected structure" - when: github_pat is defined and github_pat | length > 0 + when: > + ansible_mcp_server_env is defined and + ansible_mcp_server_env.GITHUB_PERSONAL_ACCESS_TOKEN is defined and + ansible_mcp_server_env.GITHUB_PERSONAL_ACCESS_TOKEN | length > 0 - name: Test server_info with AWS IAM MCP server hosts: aws_iam_server From 10c1791dba4d161cf64fa62a9b383118ac0b363d Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Fri, 7 Nov 2025 15:55:59 -0500 Subject: [PATCH 15/17] Change runme.sh to use full path to inventory generation playbook --- tests/integration/targets/server_info/runme.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/integration/targets/server_info/runme.sh b/tests/integration/targets/server_info/runme.sh index ccc6f89..47b335e 100755 --- a/tests/integration/targets/server_info/runme.sh +++ b/tests/integration/targets/server_info/runme.sh @@ -21,14 +21,15 @@ GITHUB_PAT_VALUE="${github_mcp_pat:-${ANSIBLE_TEST_GITHUB_PAT:-${GITHUB_PAT:-${G # Generate inventory file with PAT injected from template # This will overwrite the existing inventory.yml file with the generated version +GENERATE_INVENTORY="${SCRIPT_DIR}/generate_inventory.yml" if [ -n "${GITHUB_PAT_VALUE:-}" ]; then - ansible-playbook -c local generate_inventory.yml -e "github_mcp_pat=${GITHUB_PAT_VALUE}" "$@" + ansible-playbook -c local "${GENERATE_INVENTORY}" -e "github_mcp_pat=${GITHUB_PAT_VALUE}" "$@" else - ansible-playbook -c local generate_inventory.yml "$@" + ansible-playbook -c local "${GENERATE_INVENTORY}" "$@" fi # Run integration tests -ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" "$@" +ansible-playbook -i "${INVENTORY}" "${SCRIPT_DIR}/tasks/main.yml" -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" "$@" # Delete generated inventory file after tests complete rm -f "${INVENTORY}" From a94c030691560b8455174019c41f2beb2c07c063 Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Mon, 10 Nov 2025 10:33:57 -0500 Subject: [PATCH 16/17] Restore generate_inventory.yml step for integration test --- .../targets/server_info/generate_inventory.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/integration/targets/server_info/generate_inventory.yml diff --git a/tests/integration/targets/server_info/generate_inventory.yml b/tests/integration/targets/server_info/generate_inventory.yml new file mode 100644 index 0000000..38ef87e --- /dev/null +++ b/tests/integration/targets/server_info/generate_inventory.yml @@ -0,0 +1,15 @@ +--- +- name: Generate inventory file for integration tests + hosts: localhost + connection: local + gather_facts: false + vars: + template_file: "{{ playbook_dir }}/inventory.yml.j2" + inventory_file: "{{ playbook_dir }}/inventory.yml" + tasks: + - name: Write inventory file + ansible.builtin.copy: + dest: "{{ inventory_file }}" + content: "{{ lookup('template', template_file) }}" + mode: "0644" + From 222f4a3f78e250804392b106d798c488e15cbe0c Mon Sep 17 00:00:00 2001 From: Bianca Henderson Date: Mon, 10 Nov 2025 10:39:10 -0500 Subject: [PATCH 17/17] Update error handling --- plugins/action/server_info.py | 7 ++++++- .../integration/targets/server_info/generate_inventory.yml | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/action/server_info.py b/plugins/action/server_info.py index 983f542..f27f695 100644 --- a/plugins/action/server_info.py +++ b/plugins/action/server_info.py @@ -3,6 +3,8 @@ # Copyright (c) 2025 Red Hat, Inc. # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +import traceback + from ansible.errors import AnsibleActionFail from ansible.module_utils.connection import Connection from ansible.plugins.action import ActionBase @@ -43,4 +45,7 @@ def run(self, tmp=None, task_vars=None): return result except Exception as e: - raise AnsibleActionFail("Failed to retrieve server info: %s" % str(e)) + result["failed"] = True + result["msg"] = "Failed to retrieve server info: %s" % str(e) + result["exception"] = "".join(traceback.format_exception(None, e, e.__traceback__)) + return result diff --git a/tests/integration/targets/server_info/generate_inventory.yml b/tests/integration/targets/server_info/generate_inventory.yml index 38ef87e..0c438b7 100644 --- a/tests/integration/targets/server_info/generate_inventory.yml +++ b/tests/integration/targets/server_info/generate_inventory.yml @@ -12,4 +12,3 @@ dest: "{{ inventory_file }}" content: "{{ lookup('template', template_file) }}" mode: "0644" -