MCP Server installation in an air-gapped environment


Overview

This procedure explains how to install CAST Imaging MCP Server on a Linux host that cannot access Docker Hub or another external container registry.

The procedure has two independent parts:

  • Transfer and install the MCP Server container image.
  • Install and configure an MCP-aware client that is compatible with the customer’s approved private LLM.

An air-gapped installation requires all installers, container images, extensions, certificates, and dependencies to be downloaded on an internet-connected staging host and transferred through the customer’s approved secure process.

Prerequisites

Internet-connected staging host

  • Docker or another OCI-compatible container tool
  • Access to the registry containing the CAST Imaging MCP Server image
  • Sufficient disk space for the image archive and imported image
  • A secure method for transferring files to the air-gapped environment

Air-gapped Linux host

  • The CAST Imaging MCP Server installer package, extracted locally
  • Docker Engine with Docker Compose v2, or Podman with a Compose-compatible provider
  • Access from the MCP Server host to CAST Imaging Control Panel and Imaging APIs
  • Access from approved client workstations to the MCP Server port (8282 by default)
  • A CAST Imaging API key
  • The exact MCP Server image name and tag supplied for the installed release

1. Identify the required container image

On the staging host, inspect the image: entry in the docker-compose.yml supplied with the MCP Server installer:

grep -E '^[[:space:]]*image:' docker-compose.yml

For example:

services:
  mcp-server:
    image: castbuild/imaging-mcp-server:3.0.2-326

Record the complete repository and tag. The locally imported image and the image referenced by Compose must match exactly.

Image repositories and tags can vary by release. Do not infer the image name from the product version or reuse the example without checking the delivered installer and release information.

2. Download and export the image on the staging host

Replace <image>:<tag> with the exact value identified in the previous step.

docker pull <image>:<tag>
docker image inspect <image>:<tag>
docker save --output imaging-mcp-server.tar <image>:<tag>
sha256sum imaging-mcp-server.tar > imaging-mcp-server.tar.sha256

Example:

docker pull castbuild/imaging-mcp-server:3.0.2-326
docker save --output imaging-mcp-server.3.0.2.tar \
  castbuild/imaging-mcp-server:3.0.2-326
sha256sum imaging-mcp-server.3.0.2.tar \
  > imaging-mcp-server.3.0.2.tar.sha256

Transfer the following files to the air-gapped host using the customer’s approved process:

  • MCP Server installer package
  • Container image tar archive
  • SHA-256 checksum file
  • Any required private CA certificate bundle

3. Verify and import the image on the air-gapped host

Verify that the archive was not corrupted or altered:

sha256sum --check imaging-mcp-server.tar.sha256

Docker

docker load --input imaging-mcp-server.tar
docker image ls

Podman

podman load --input imaging-mcp-server.tar
podman images

The load command reports the imported image reference, for example:

Loaded image: docker.io/castbuild/imaging-mcp-server:3.0.2-326

4. Make the Compose image reference match the imported image

Compare the image known to the local container engine with the image: value in docker-compose.yml.

grep -E '^[[:space:]]*image:' docker-compose.yml

If they differ, use one of the following approaches.

Preferred: tag the imported image with the name expected by the installer

This preserves the delivered Compose file and run.sh behavior.

With Docker:

docker tag <imported-image>:<tag> <compose-image>:<tag>

With Podman:

podman tag <imported-image>:<tag> <compose-image>:<tag>

Example, if the installer expects castimaging/imaging-mcp-server:3.0.2:

podman tag docker.io/castbuild/imaging-mcp-server:3.0.2-326 \
  castimaging/imaging-mcp-server:3.0.2

Alternative: update docker-compose.yml

Change only the service’s image: value to the exact locally imported image reference:

services:
  mcp-server:
    image: docker.io/castbuild/imaging-mcp-server:3.0.2-326

Compose may attempt an external pull when the reference does not exactly match a local image. Registry prefixes such as docker.io/ and localhost/ can be significant, particularly with Podman.

5. Configure the MCP Server

Edit config/app.config in the extracted installer directory. At minimum, configure the values required for the local CAST Imaging deployment:

HOST_CONTROL_PANEL="<control-panel-host>"
PORT_CONTROL_PANEL=8098
SERVICE_HOST="<mcp-server-host>"
CONTROL_PANEL_SSL_ENABLED=false

Set the exposed port in the hidden .env file:

MCP_SERVER_PORT=8282

If CAST Imaging uses a private or self-signed CA, place the PEM bundle in the installer’s certificates/ directory and set, for example:

SSL_CA_BUNDLE="/app/certificates/imaging-ca.pem"

Verify connectivity from the MCP Server host to Imaging APIs before starting the container:

curl -H "x-api-key: <imaging-api-key>" \
  http://<control-panel-host>:8090/imaging/apis/rest/ready

The expected response is true.

6. Start the MCP Server

First verify that Compose resolves to the expected image and that the image exists locally:

docker compose config
docker image inspect <compose-image>:<tag>

Use the installer script as the standard startup method. It validates required configuration and prepares file permissions and mounted directories before starting Compose:

chmod +x run.sh
./run.sh --install

The installer script does not explicitly set a no-pull policy. Before running it, ensure that the image: value in docker-compose.yml exactly matches the loaded local image.

Optional: enforce a no-pull policy

If the installed Compose version supports it, --pull never can be used as an additional safeguard:

docker compose up -d --pull never

Running Compose directly bypasses the validation and permission preparation performed by run.sh. Use this command only after the installer script has prepared the installation directory, or after performing the equivalent preparation manually.

For Podman, the available command depends on the Compose provider installed in the environment. It may be podman compose or podman-compose. If that provider supports the option, the equivalent command is:

export HOST_UID="$(id -u)"
export HOST_GID="$(id -g)"
podman compose up -d --pull never

Confirm support for --pull never with the locally installed Compose provider. If unsupported, verify the exact local image reference before starting.

7. Verify the installation

Docker

docker compose ps
docker ps --filter name=mcp-server
docker logs mcp-server

Podman

podman ps --filter name=mcp-server
podman logs mcp-server

From an approved client host, confirm network access to the MCP endpoint:

curl -i http://<mcp-server-host>:8282/mcp/

An authentication or protocol-level response confirms basic network reachability. A connection timeout or refusal indicates a routing, firewall, port-mapping, or service-startup issue.

8. Install an MCP-aware client in the air-gapped environment

The MCP Server does not provide an LLM or a user-facing chat client. A separate MCP-aware client must:

  • support remote MCP servers over HTTP;
  • support custom request headers for the CAST Imaging API key and tenant;
  • connect to the customer’s approved private LLM within the permitted network architecture; and
  • be licensed and approved for offline use by the customer.

Select an MCP-aware client that supports the customer’s private LLM and remote MCP servers over HTTP. Follow the client vendor’s instructions for offline installation and private-LLM configuration.

Transfer the required client installer and dependencies to the air-gapped environment using the customer’s approved process. After installation:

  • Configure and test the connection to the private LLM.
  • Configure the CAST Imaging MCP Server endpoint and required headers.
  • Verify that the client can invoke CAST Imaging MCP tools.

9. Configure the selected MCP client

The following configuration illustrates the required connection information. Adapt the file location and schema to the selected client:

{
  "inputs": [
    {
      "id": "imaging-key",
      "type": "promptString",
      "description": "CAST Imaging API Key",
      "password": true
    },
    {
      "id": "imaging-tenant",
      "type": "promptString",
      "description": "CAST Imaging tenant"
    }
  ],
  "servers": {
    "imaging": {
      "type": "http",
      "url": "http://<mcp-server-host>:8282/mcp/",
      "headers": {
        "x-api-key": "${input:imaging-key}",
        "x-user-tenant": "${input:imaging-tenant}"
      }
    }
  }
}

Do not store API keys in source control or in shared plaintext configuration. Use the client’s secret-input or credential-storage mechanism where available.

10. Test from the MCP-aware client

After connecting the client to both the private LLM and MCP Server, try prompts such as:

List all applications.
List five transactions for application <application-name>.
List available application data graphs.
List application quality insights.

Confirm in the client that the response includes a CAST Imaging MCP tool invocation rather than an answer generated only from the LLM’s existing knowledge.

Troubleshooting

Symptom Likely cause Resolution
Compose tries to contact Docker Hub Compose image reference does not match the imported image, or the pull policy permits pulling Retag the image or correct image:; start with --pull never
manifest unknown or short-name resolution error Repository prefix or tag mismatch Use the complete reference shown by docker images or podman images
Container exits immediately Invalid configuration, permissions, or missing .env Inspect container logs and verify config/app.config, .env, mounted directories, UID, and GID
MCP client cannot connect Firewall, routing, wrong SERVICE_HOST, wrong port, or stopped container Test the endpoint with curl, inspect port mapping, and check container logs
Authentication error Missing, invalid, or expired API key; wrong tenant Regenerate the key and verify the x-api-key and x-user-tenant headers
Private LLM works but tools are unavailable Client lacks remote HTTP MCP support or MCP configuration is not loaded Verify client capabilities, configuration location, transport type, and server status
TLS validation failure Private CA is not trusted by the server or client Install the approved CA bundle and configure the applicable trust setting

Updating in an air-gapped environment

Repeat the export, checksum, transfer, and import process for every new MCP Server image. Before starting an update:

  • Back up the existing installer directory and configuration according to customer policy.
  • Import the new image and verify its exact repository and tag.
  • Extract the new installer package.
  • Set required values such as SERVICE_HOST in the new configuration.
  • Ensure the new Compose file references the imported image exactly.
  • Follow the release-specific update instructions.

Prevent registry pulls and verify the running container uses the intended image.

docker inspect mcp-server --format '{{.Config.Image}}'
docker image inspect <expected-image>:<tag> --format '{{.Id}}'

Do not assume that an old local tag points to the new release. Use immutable digests where supported by the delivered Compose configuration and release process.

Security considerations

  • Transfer artifacts only through the customer’s approved process and verify checksums or signatures after transfer.
  • Restrict access to the MCP Server port to approved client hosts.
  • Protect CAST Imaging API keys and private-LLM credentials.
  • Use TLS at an approved reverse proxy or network boundary when traffic crosses an untrusted segment.
  • Keep IMAGING_CODE=False unless source-code access is explicitly required and approved.
  • Review the MCP tool surface and use least-privilege settings appropriate to the deployment.
  • Establish an offline process for image, client, dependency, and certificate updates.

Information to record for support

When reporting an air-gapped installation issue, provide:

  • MCP Server installer version
  • Expected Compose image reference
  • Output of docker images or podman images
  • Docker/Podman and Compose-provider versions
  • Sanitized output of docker compose config
  • Container status and sanitized logs
  • Selected MCP client and version
  • Private LLM provider, API compatibility, and model identifier (without credentials)
  • Network path among the client, MCP Server, CAST Imaging APIs, and private LLM