Create and integrate custom MCP Servers in execution environments
Integrate custom Model Context Protocol (MCP) servers into execution environments using the ansible.mcp_builder framework to automate installation, configuration, and lifecycle management.
Preparing your environment
Before you begin, ensure you have the following:
- ansible-builder : Version 3.1 or later installed on your build system. Install it using
dnf install ansible-builder. - ansible-core: : Version 2.16 or later.
- Access to a base Execution Environment image, for example, ee-minimal-rhel9 from the Red Hat registry.
- The
ansible.mcp_buildercollection (version 1.0.3 or later), installed using:ansible-galaxy collection install ansible.mcp_builder. - The
ansible.mcpcollection (a required dependency), installed using:ansible-galaxy collection install ansible.mcp. - Familiarity with Ansible roles, collections, and execution environment definitions.
Evaluate MCP servers before installation Copy linkLink copied!
To protect your execution environment from vulnerabilities, evaluate Model Context protocol (MCP) servers before installation by auditing code, pinning versions, enforcing read-only modes, and verifying permissions
Before including an MCP server in your execution environment:
- Review the source code: MCP servers can execute arbitrary operations on your infrastructure. Audit the server code before installing, especially for servers from community or third-party sources.
- Pin to specific versions: Use explicit version numbers in your registry metadata rather than latest.
cfn_mcp_version: "1.0.19"This ensures reproducible builds and prevents unexpected behavior from upstream changes.
- Use read-only mode where available: Many MCP servers support a read-only flag that prevents mutating operations:
cfn_mcp_registry: - name: "awslabs.cfn-mcp-server" type: "stdio" lang: "pypi" args: ["--readonly"] description: "AWS CloudFormation MCP Server (read-only)" - Review required permissions: Understand what permissions each MCP server needs. For example, the CloudFormation MCP server requires
cloudcontrol:*andcloudformation:*IAM permissions. Grant only the minimum permissions needed.
Understand the MCP builder framework Copy linkLink copied!
ansible.mcp_builder collection provides a reusable framework for installing MCP servers inside execution environments. Rather than manually scripting installation steps in your container build, you define a role with metadata about your MCP server, and the framework handles the rest.
To automate the installation and lifecycle management of your servers, you must understand how the ansible.mcp_builder framework operates.
The framework consists of three main components:
- The common role (
ansible.mcp_builder.common) provides shared installation logic for MCP servers. Based on the language specified in your role's registry metadata, the common role automatically:- Installs the appropriate language runtime (Go, Node.js, or Python/uv) if not already present.
- Downloads and installs the MCP server package from the correct source (PyPI, npm, or Git).
- Generates a unified manifest file (
/opt/mcp/mcpservers.json) listing all available MCP servers. - Creates the mcp_manage utility for listing, querying, and running installed MCP servers
- Your custom role defines metadata about the MCP server you want to install. At minimum, it includes:
- A registry variable that specifies the server name, transport type, language, and description.
- A tasks file that invokes the common role's
install_managerandgenerate_manifesttasks.
- A playbook ties your custom role into the build process. This playbook is called by ansible-builder during the execution environment container build.
Select an installation method
| Language | Install method | Example servers |
|---|---|---|
| pypi | Installed with uv tool install from PyPI | AWS CloudFormation MCP, AWS Core MCP, AWS IAM MCP |
| npm | Installed with npm install from the npm registry | Azure MCP |
| go | Built from source with go build from a Git repository | GitHub MCP |
Track configurations with the MCP servers manifest Copy linkLink copied!
Understand how the MCP servers manifest registers and automatically merges multiple server installations into the /opt/mcp/mcpservers.json file so that you can effectively track and verify your execution environment configurations.
All installed MCP servers are registered in /opt/mcp/mcpservers.json. This file follows the mcp.json format established by VS Code, with each server entry containing:
{
"server-name": {
"type": "stdio",
"command": "/opt/mcp/bin/server-name",
"args": [],
"description": "Description of the MCP server"
}
}
For remote (HTTP-based) MCP servers, the entry uses url instead of command:
{
"server-name": {
"type": "http",
"url": "https://remote-server:12345",
"args": [],
"description": "Remote MCP server"
}
}
When multiple playbooks install MCP servers into the same execution environment, the manifest merges automatically. Each subsequent installation appends its entries to the existing manifest without overwriting previous entries.
Create a custom MCP server role Copy linkLink copied!
Develop a custom Ansible role to automate the installation, configuration, and management of your specific custom Model Context Protocol (MCP) server for seamless integration into execution environments.
About this task Copy linkLink copied!
This procedure uses the AWS CloudFormation MCP Server (awslabs.cfn-mcp-server) as a working example.
Procedure Copy linkLink copied!
Build an execution environment with your dev preview MCP server Copy linkLink copied!
Use the ansible-builder tool to compile and build an execution environment container image that incorporates your dev preview Model Context Protocol (MCP) server role and its dependencies.
Procedure Copy linkLink copied!
Combine custom and dev preview MCP servers Copy linkLink copied!
Integrate both custom-developed and dev-preview Model Context Protocol (MCP) servers within a single execution environment to use comprehensive automation capabilities.
To include both dev preview MCP servers from ansible.mcp_builder (such as aws_ccapi_mcp) and your custom role in the same execution environment, chain multiple playbook calls in additional_build_steps:
additional_build_steps:
append_final: |
RUN ansible-playbook ansible.mcp_builder.install_mcp -e mcp_servers=aws_ccapi_mcp
RUN ansible-playbook myorg.mcp_cfn.install_cfn_mcp
The manifest file merges automatically. The second playbook appends its entries to the existing mcpservers.json created by the first.
Test and verify your MCP server Copy linkLink copied!
Verify your MCP server configuration by listing registered servers, inspecting the generated JSON manifest, and testing container connectivity with Podman.
Testing your MCP server in the execution environment
After building the execution environment, verify that your MCP server is correctly installed and functional.
List the MCP servers registered in the manifest:
podman run --rm my-cfn-mcp-ee:latest mcp_manage list
Expected output:
Available MCP servers:
- awslabs.cfn-mcp-server (type: stdio, path: /opt/mcp/bin/awslabs.cfn-mcp-server)
Verify the manifest file
Inspect the generated manifest directly:
podman run --rm my-cfn-mcp-ee:latest cat /opt/mcp/mcpservers.json
Expected output:
{
"awslabs.cfn-mcp-server": {
"args": [],
"command": "/opt/mcp/bin/awslabs.cfn-mcp-server",
"description": "AWS CloudFormation MCP Server - manage AWS resources via Cloud Control API",
"type": "stdio"
}
}
Test server connectivity
Run the MCP server with --help to confirm it is callable:
podman run --rm my-cfn-mcp-ee:latest mcp_manage run awslabs.cfn-mcp-server --help
For servers that require credentials (such as AWS), pass environment variables:
podman run --rm \
-e AWS_PROFILE=my-profile \
-e AWS_REGION=us-east-1 \
-v ~/.aws:/home/runner/.aws:ro \
my-cfn-mcp-ee:latest \
mcp_manage run awslabs.cfn-mcp-server
Configure remote MCP servers Copy linkLink copied!
If you need to bypass local installation and dynamically choose your deployment mode at build time, configure your role to reference a remote MCP server via HTTP.
Add a remote server to your role
To define a remote MCP server, set the type to http in your registry metadata:
# roles/cfn_mcp/defaults/main.yml (remote mode example)
---
cfn_mcp_registry:
- name: "awslabs.cfn-mcp-server"
type: "http"
lang: "pypi"
path: "https://my-mcp-host.example.com:8443/cfn"
args: []
description: "Remote AWS CloudFormation MCP Server"
cfn_mcp_version: "latest"
When type is http, the framework only registers the server in the manifest with its URL.
Support both modes
The GitHub MCP role in ansible.mcp_builder demonstrates a pattern for supporting both embedded and remote modes. You can adopt this pattern by:
- Creating a
vars/remote.ymlfile with the remote registry definition. - Loading it conditionally in your tasks:
# roles/cfn_mcp/tasks/main.yml
---
- name: Override registry for remote mode
ansible.builtin.include_vars:
file: remote.yml
when: cfn_mcp_mode | default('local') == 'remote'
- name: Include install manager tasks
ansible.builtin.include_role:
name: ansible.mcp_builder.common
tasks_from: install_manager
- name: Update MCP servers manifest
ansible.builtin.include_role:
name: ansible.mcp_builder.common
tasks_from: generate_manifest
You can then select the mode when building the execution environment:
additional_build_steps:
append_final: |
RUN ansible-playbook myorg.mcp_cfn.install_cfn_mcp -e cfn_mcp_mode=remote
Secure your custom MCP servers Copy linkLink copied!
Apply essential security configurations and best practices to safeguard your custom MCP servers, manage credentials securely, and harden your execution environments.
Managing credentials and secrets
MCP servers frequently require credentials to interact with cloud providers or external services. Follow these practices:
- Never embed credentials into the execution environment image: Credentials embedded during build time persist in the container image layers and can be extracted. Instead, pass credentials at runtime using environment variables or mounted files.
- Use runtime environment variables: Pass credentials when launching the execution environment:
podman run --rm \ -e AWS_PROFILE=my-profile \ -e GITHUB_PERSONAL_ACCESS_TOKEN="$GITHUB_TOKEN" \ my-mcp-ee:latest … - Mount credential files as read-only: For providers that use credential files (such as AWS), mount them read-only:
-v ~/.aws:/home/runner/.aws:ro - In Ansible Automation Platform, use credential types: When running MCP-enabled execution environments through Ansible Automation Platform, configure credentials through the automation controller credential management system rather than embedding them in playbooks or job templates.
Use your MCP-enabled execution environment in Ansible Automation Platform Copy linkLink copied!
To secure your infrastructure and ensure predictable execution, evaluate MCP servers before installation by auditing code, pinning versions, enabling read-only modes, and enforcing least-privilege permissions.
After building and testing your execution environment locally, you can use it in Ansible Automation Platform.
Push the image to a registry
Tag and push your execution environment image to a container registry accessible by your Ansible Automation Platform instance:
podman tag my-cfn-mcp-ee:latest registry.example.com/ee/my-cfn-mcp-ee:latest
podman push registry.example.com/ee/my-cfn-mcp-ee:latest
If you are using the Private Automation Hub included with Ansible Automation Platform, push to its registry.
Add the execution environment to Ansible Automation Platform Copy linkLink copied!
To execute automation tasks using your custom MCP server, add its execution environment to Ansible Automation Platform by registering the container image path and secure credentials in the administration settings.
Procedure Copy linkLink copied!
- In the navigation panel, select Automation execution > Administration > Execution Environments.
- Click Add.
- Enter the image path (for example,
registry.example.com/ee/my-cfn-mcp-ee:latest). - Configure registry credentials if required.
- Save the execution environment.
Assign to a Job Template Copy linkLink copied!
Configure your job template with an MCP-enabled execution environment and credentials to ensure your automation jobs execute correctly.
Procedure Copy linkLink copied!
- In the navigation panel, select
Automation execution > Templates. - Edit or create a Job Template.
- In the Execution Environment field, select your MCP-enabled execution environment.
- Configure any required credentials for the MCP server (such as AWS credentials).
- Save and launch the template.
Debug common issues Copy linkLink copied!
Diagnose and resolve initialization failures when your MCP server is unlisted or fails to execute. By systematically verifying build logs, installed files, and manifests, you can identify the root cause of deployment errors and successfully run your server.
Procedure Copy linkLink copied!
Troubleshoot build and runtime errors
Diagnose and resolve common issues encountered when building, configuring, and integrating custom or built-in Model Context Protocol (MCP) servers within your execution environments.
Build failures
| Error | Reason |
|---|---|
| Unable to find collection artifact file. | This error occurs when the collection tarball path in requirements.yml does not match the path inside the container. Ensure:
|
| Package download fails during build | The execution environment build environment requires network access to download packages from PyPI, npm, or Git repositories. If building behind a proxy, configure proxy settings in your container build environment. If building in an air-gapped environment, you must pre-download packages and include them usingadditional_build_files. |
| Go build fails with "module not found" | For Go-based MCP servers, ensure thebuild_repo URL andbuild_repo_branch are correct and accessible. The framework clones the repository and runs go mod download before building. |
Runtime failures
| Error | Reason |
|---|---|
mcp_manage: command not found |
The Ensure your playbook includes |
| MCP server fails with permission errors | The execution environment runs as user 1000 (non-root). Ensure your playbook includes the ownership fix task:
|
| Server listed but not executing | If
|
Variable validation errors
| Error | Reason |
|---|---|
| Missing registry variable | The common role expects a registry variable named<role_name>_registry. Ensure yourdefaults/main.yml follows the naming convention. For a role named xdefaults/main.yml, the variable must becfn_mcp_registry. |
| Invalid language type | The lang field in the registry must be one of: pypi, npm, or go. Any other value causes the install manager to skip installation. However,generate_manifest.yml will fail with'dict object' has no attribute 'path' (rc=2) because it expects a variable the skipped installer never set. |
Understanding support boundaries
Red Hat provides and supports the following components:
- The
ansible.mcp_buildercollection, including the common role and its installation framework. - The ansible-builder tool for creating execution environments.
- The execution environment runtime within Ansible Automation Platform.
The following are the customer's responsibility:
- Individual MCP server implementations. Red Hat does not support any specific MCP server, including the reference examples (AWS, Azure, GitHub) provided in the
ansible.mcp_buildercollection. These examples are Dev Preview. - Custom MCP roles and collections. Your organization owns the creation, testing, and maintenance of custom roles.
- MCP server security. Your organization is responsible for evaluating, auditing, and securing the MCP servers you deploy.
- MCP server credentials and access controls. Configuring and securing access to external services is your responsibility.
If you encounter issues:
- For problems with ansible-builder, the common role, or the execution environment build process, contact Red Hat support.
- For problems with a specific MCP server, contact the MCP server vendor or community.