Skip to main content
This guide covers running mcp-server-db2i with Docker and docker-compose.

Quick Start

Build the Image

This builds the default odbc image with the IBM i Access ODBC Driver. IBM publishes no arm64 Linux build of that driver, so on an arm64 host such as an Apple Silicon Mac add --platform linux/amd64, or build the jt400 image instead. See Multi-Stage Build.

Run with Environment Variables

Security Warning: Passing credentials via -e flags exposes them in process lists (ps aux), docker inspect output, and shell history. Use --env-file for local testing and Docker secrets for production deployments.

Docker Compose

Basic Setup

Create a .env file:
Run with docker-compose:

HTTP Transport

To expose the HTTP API, uncomment the ports section in docker-compose.yml:
Then run:

Docker Secrets

For production deployments, use Docker secrets instead of environment variables.

1. Create Secret Files

Security Note: Avoid using echo "password" > file directly, as it may be logged in shell history. The read -s command hides input from the terminal.

2. Update docker-compose.yml

3. Run

TLS with Docker

Using Built-in TLS

  1. Mount your certificates:
  1. Generate self-signed certificates (for testing):

Using Reverse Proxy

For production, use a reverse proxy like nginx or Traefik for TLS termination:

Environment Variables

All environment variables can be set in docker-compose.yml or via .env file:

Business SQL tools

Mount a directory of YAML tool files and point MCP_CUSTOM_TOOLS at it. The example pack in examples/erp-tools uses placeholder names such as MYLIB.ORDERHDR. Edit those names before relying on the tools.
The server reads the files at startup. A statement that is not a query, or that names a library outside QUERY_ALLOWED_SCHEMAS, stops the container. See Business SQL tools.

Query exports

The image has an empty /data/exports directory owned by mcpuser with mode 0700. Point EXPORT_DIR at it and mount a named volume there, which takes the same owner:
Over HTTP, users download through the link and never see the path. Over stdio the result is a path inside the container, which is only useful on the host through a bind mount: mount a host directory at /data/exports and make it writable by the container’s mcpuser. See Query exports.

Multi-Stage Build

The Dockerfile uses a multi-stage build with two runtime targets:
  1. Builder stage: Compiles TypeScript to JavaScript, then installs the production packages for each target. Both include @ibm/mapepire-js and ssh2; only the jt400 target includes node-jt400
  2. odbc target (default): unixODBC and the IBM i Access ODBC Driver from IBM’s apt repository, no Java. Sets DB2I_DRIVER=odbc.
  3. jt400 target: OpenJDK 17 JRE and node-jt400 for the JT400 JDBC driver. Sets DB2I_DRIVER=jt400.
IBM publishes the ODBC driver package for amd64 and ppc64el, and its apt repository also carries older i386 builds (see Installing the IBM i Access ODBC Driver). There is no arm64 build, so in practice the ODBC image is an amd64 image. On an arm64 host such as an Apple Silicon Mac, build and run it under emulation with --platform linux/amd64; the build fails early with a message otherwise. The jt400 image builds natively on arm64.
Either image can run the mapepire driver, because it needs nothing native. Override the driver and pin the host key, since the container has no known_hosts. Alternatively, mount a known_hosts file and set knownHostsFile to its path.
To tell images apart in the audit log between releases, pass the git commit as MCP_BUILD_ID. Every audit line then records it as build, next to serverVersion:
The bundled docker-compose.yml builds the ODBC image with platform: linux/amd64. To use the JDBC image, set target: jt400 under build and remove the platform line. Both images:
  • Use node:22-bookworm-slim. Bookworm is pinned so OpenJDK 17 stays available for the jt400 target. Debian trixie does not package it.
  • Run as non-root user (mcpuser)
  • Include only production dependencies
  • Default MCP_SESSION_MODE to stateless, matching the server. stateful is deprecated.
The odbc image installs ibm-iaccess from public.dhe.ibm.com at build time, so the build needs network access to that host. See Database Drivers for the ODBC keywords.

Health Checks

For HTTP transport, add a health check:
Note: The image is Debian slim and does not include curl or wget. The check uses Node’s built-in fetch.

Resource Limits

Set resource limits for production:

Logging

View Logs

Log Configuration

For production, use JSON logging:

Log Drivers

Configure Docker log drivers for centralized logging:

Networking

Bridge Network (default)

Host Network

For better performance (Linux only):

Example: Complete Production Setup

Troubleshooting

Container Won’t Start

  1. Check logs: docker-compose logs mcp-server-db2i
  2. Verify environment variables are set
  3. Ensure IBM i is reachable from container

Connection Refused

  1. Check that the container can reach the IBM i ports your driver uses: 449, 8476 and 8471 (9476 and 9471 with TLS) for odbc and jt400, or SSH (port 22) for mapepire. Port 446 is not used
  2. Verify hostname resolves correctly
  3. Check firewall rules

Permission Denied

  1. Ensure secret files have correct permissions
  2. Check volume mount permissions
  3. Verify non-root user has access

Out of Memory

  1. Increase memory limits
  2. Reduce QUERY_MAX_LIMIT
  3. Lower MCP_MAX_SESSIONS