-
Notifications
You must be signed in to change notification settings - Fork 5
Add server_info action plugin
#11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 11 commits
12a2b93
f2c19e7
7f0ed9f
78e2afa
3793a87
439ccce
7b6205e
a155e40
9d08394
80f0ce1
d96b45a
11737b2
18b4504
77f7ef7
12b4b17
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| profile: production | ||
|
|
||
| exclude_paths: | ||
| - .github/ | ||
| - tests/integration |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # -*- 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) | ||
| result["server_info"] = conn.server_info() | ||
| return result | ||
|
|
||
| except Exception as e: | ||
| raise AnsibleActionFail("Failed to retrieve server info: %s" % str(e)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think in this case we should treat it like a module failure. So rather than raising an exception, we should do something like: result["failed"] = True
result["msg"] = "some useful error message..."
result["exception"] = "".join(traceback.format_exception(None, e, e.__traceback__)) |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| # -*- 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 | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| # TO-DO: add python packages that are required for testing this collection | ||
| pytest-ansible | ||
| pytest-xdist | ||
| # uv provides uvx command-line tool needed for AWS IAM MCP server integration tests | ||
| uv |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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:-}}}}" | ||
|
|
||
| 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 "ansible_mcp_manifest_path=${MANIFEST_PATH}" -e "github_pat=${GITHUB_PAT_VALUE}" "$@" | ||
| else | ||
| ansible-playbook -i "${INVENTORY}" tasks/main.yml -e "ansible_mcp_manifest_path=${MANIFEST_PATH}" "$@" | ||
| fi |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| --- | ||
| - 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: | ||
| 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 | ||
| 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: | ||
| 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" | ||
| when: uvx_check.rc == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
integration will be ran using zuul, this workflow should be removed