Skip to main content
Version: ERPBridge + bridgectl ยท v0.5.0-alpha.2

Docker deployment guide

This guide covers how to deploy and manage the ERPBridge ecosystem with Docker and Docker Compose.

1. Quick startโ€‹

Make sure that you have Docker and Docker Compose installed.

Start the local development stack
# Clone the repository
git clone https://github.com/nmdra/ERPBridge.git
cd ERPBridge

# Safely bootstrap ephemeral local MockERP credentials
make dev-up

# Direct Compose use requires a credential source first.
docker compose --env-file .env up --build --force-recreate -d

The stack includes:

  • ERPBridge Server (:8080): The core MCP middleware. The development Compose path enables system.*_test demonstration tools; production must leave MCP_ENABLE_TEST_TOOLS unset or false.
  • mock-erp (:8081): Simulates ERP endpoints.
  • Redis (:6379): Provides the exact-match cache.

RedisInsight binds to 127.0.0.1 by default. Keep it loopback-only or opt it out; never expose it publicly.

2. Configurationโ€‹

Environment variables for the server are set in the docker-compose.yml file.

VariableDescriptionDefault (compose)
BASE_URLPublic URL of the MCP server.http://localhost:8080
ERPBRIDGE_HOST_PORTHost port for the ERPBridge container.8080
ERP_BASE_URLBase URL of the underlying ERP system.http://mock-erp:8081
MOCK_ERP_HOST_PORTHost port for the MockERP container.8081
MOCK_ERP_IMAGEPinned MockERP image.ghcr.io/nmdra/mockerp:0.2.1
MOCK_ERP_VERSIONMockERP release used for OpenAPI specification generation.0.2.1
MOCK_ERP_OPENAPI_URLVersioned MockERP OpenAPI URL.https://raw.githubusercontent.com/nmdra/mockerp/v0.2.1/openapi.yaml
MOCK_ERP_CREDENTIALS_JSONJSON credentials for local/container use.(required)
MOCK_ERP_CREDENTIALS_FILEMounted JSON secret path.(required alternative)
REDIS_URLURL for the Redis cache.redis://redis:6379
REDIS_HOST_PORTHost port for Redis.6379
REDIS_INSIGHT_BIND_ADDRESSHost address for the RedisInsight binding.127.0.0.1
REDIS_INSIGHT_HOST_PORTHost port for RedisInsight.8001
MCP_ENABLE_TEST_TOOLSDevelopment-only registration of system.*_test tools.true in this Compose path
DATABASE_PATHPath of the SQLite tool registry inside the container./app/data/erpbridge.db
RATE_LIMIT_RPSPer-session requests per second.10
RATE_LIMIT_BURSTToken bucket burst size.20
API_AUTH_TOKENAdmin bearer token for protected control-plane, MCP, and direct-invoke routes.(unset)
ERP_PRIMARY_KEYExample environment credential referenced by generated ERP tools.(unset)
ERPBRIDGE_CREDENTIALS_DIROptional mounted directory used only by resources with credentialSource: file.(unset)
PLUGIN_<NAME>Environment credential referenced by a plugin credentialRef; the value is never persisted.(unset)
PLUGIN_ENDPOINT_ALLOWLISTExact normalized host:port values allowed for credentialed plugin endpoints.(unset)
INSECURE_AUTH_ALLOWED_HOSTSExact development-only host:port exceptions for credentialed HTTP.(unset)

For the full list of server environment variables, see the environment variables reference. See the MockERP integration contract for the pinned release, credential boundary, SQLite reset, and supported fixture groups.

make dev-up generates an ephemeral credential pair only when neither MOCK_ERP_CREDENTIALS_JSON nor MOCK_ERP_CREDENTIALS_FILE is set. It keeps those values in memory, validates docker compose config --quiet, force recreates the stack, and waits for both health endpoints. It does not write or print credentials. Direct Compose use requires one of the two credential sources. Compose reads quoted .env values; do not source .env in your shell. Use docker compose --env-file .env config --quiet before up --build --force-recreate -d when an env file is used.

Optional mounted credentialsโ€‹

Environment variables remain the default credential source. To rotate a selected credential without recreating the ERPBridge container, mount a read-only directory and set ERPBRIDGE_CREDENTIALS_DIR in the server:

services:
erpbridge-server:
volumes:
- ./operator-secrets:/run/secrets/erpbridge:ro
environment:
ERPBRIDGE_CREDENTIALS_DIR: /run/secrets/erpbridge

Set credentialSource: file beside the logical credentialRef only on tools, APIs, resources, or plugins using that directory. ERPBridge reads the file on each operation and fails closed on missing, empty, invalid, control-character, non-regular, invalid UTF-8, or larger-than-64 KiB content. For local writable mounts, replace files with a complete same-directory temporary file and an atomic rename. Provider-managed CSI updates are eventual; use a normal volume directory, never subPath.

AWS EKS ASCP, AKS Key Vault CSI, and GKE Secret Manager CSI can populate the directory. Use workload identity, least privilege, and provider rotation settings. Adding a new cloud secret may require a provider mapping change and workload rollout before the filename is mounted. Replicas may observe updates at different times. ERPBridge does not call cloud APIs directly.

3. Tool registryโ€‹

The server keeps tool definitions in a SQLite database (DATABASE_PATH). The schemas/ directory is NOT mounted into the container. schemas/ is also not tracked by git. There is no file-system watcher.

To load tools into the registry, generate a draft and apply one reviewed manifest from your host. Set CTX to the intended configured context first:

CTX=local # replace local with the selected context
  1. Register the ERP API:
    Register the API
    ./bridgectl api register --context "$CTX" --name erp --url http://localhost:8081 --module erp --description "Mock ERP" --auth-type api-key --credential-ref ERP_PRIMARY_KEY
  2. Generate one temporary YAML draft:
    Generate one draft stream
    ./bridgectl tool generate --context "$CTX" --api erp -o yaml > /tmp/erpbridge-draft.yaml
  3. Validate and apply the reviewed source manifest:
    Validate and apply the reviewed manifest
    ./bridgectl tool validate --context "$CTX" -f manifests/erp/tools.yaml
    ./bridgectl tool apply --context "$CTX" -f manifests/erp/tools.yaml

make generate-tools is the convenience path: it applies one temporary draft stream once and removes it. Generated output is not a second schemas/ tree or per-tool JSON authority.

The server detects new registry entries within 10 seconds and exposes them over MCP. A restart is not necessary.

4. Using bridgectl with Dockerโ€‹

You can use the local bridgectl binary to interact with the server running in Docker.

  1. Build bridgectl:

    Build the CLI
    go build -o bridgectl tools/bridgectl/main.go
  2. Verify Connection:

    Verify connection
    ./bridgectl tool get
  3. Generate the pinned MockERP tools:

    Generate and apply tools
    make generate-tools

    The Makefile downloads the versioned MockERP OpenAPI contract, generates the tool YAML, and applies it to ERPBridge.

  4. Test an API through the server:

    Run the server-side probe
    ./bridgectl api test --context "$CTX" erp

    The default probe resolves credentialRef in the server and returns only a bounded status summary. Use --local only for an explicit legacy host-side diagnostic. CLI control-plane requests use the configured MCP host root; only the exact /mcp or /mcp/ suffix is removed. Other paths return CONTROL_PLANE_URL_INVALID. /mcp/ remains the MCP transport endpoint.

5. Logs and monitoringโ€‹

  • View Container Logs:
    Follow container logs
    docker compose logs -f erpbridge-server
  • Live Stream Logs via CLI:
    Stream logs with the CLI
    ./bridgectl log tail
  • Metrics: Prometheus metrics are available at http://localhost:8080/metrics.

6. External pluginsโ€‹

ERPBridge does not install, start, update, or schedule plugin code. Deploy a pinned plugin image separately, then apply a Plugin resource with its reachable endpoint and an exact-version PluginBinding. See the External Plugins guide for the manifest and /v1/process contract.

For example, an operator-owned deployment can use:

services:
response-transformer:
image: ghcr.io/nmdra/erpbridge-plugins/mock-plugin:0.1.0

The plugin image is separate from the ERPBridge Server image and receives no ERP credentials or inbound request headers. Configure plugin authentication with an environment-backed PLUGIN_* reference, not a literal secret:

spec:
endpoint: https://response-transformer:8080
auth:
type: api-key
credentialRef: PLUGIN_RESPONSE_API_KEY
header: X-API-Key

Credentialed plugin endpoints require HTTPS and exact PLUGIN_ENDPOINT_ALLOWLIST membership. Use an exact INSECURE_AUTH_ALLOWED_HOSTS entry only for isolated development fixtures. Rotate the environment value, then flush affected cache entries with an authenticated bridgectl cache flush --all.

The ERPBridge repository includes an opt-in black-box fixture. It builds the mock-plugin from the sibling ../ERPBridge-Plugins polyrepo, generates separate admin, ERP, and plugin API keys without printing them, starts it with the pinned MockERP image, checks missing/wrong/correct plugin keys, tests both MCP and direct invocation, and removes only its isolated project:

make test-plugin-integration

The test uses the Compose project erpbridge-plugin-test. Its cleanup trap removes the containers, network, and volumes even when an assertion fails.

7. Connecting MCP clientsโ€‹

ERPBridge supports the stdio and Streamable HTTP transports.

Claude Desktop connects to MCP servers via standard input and output. The server binary supports the --stdio flag.

  1. Locate Configuration:

    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows: %APPDATA%\Claude\claude_desktop_config.json
  2. Add ERPBridge Server: Add the following to the mcpServers section. This runs the server in stdio mode inside a container.

    claude_desktop_config.json
    {
    "mcpServers": {
    "erpbridge": {
    "command": "docker",
    "args": [
    "run",
    "-i",
    "--rm",
    "ghcr.io/nmdra/erpbridge-server:latest",
    "--stdio"
    ]
    }
    }
    }
    Tool persistence

    The tool registry lives in the SQLite database. Tools persist inside the container only while it runs. To keep tools across restarts, run the full docker compose stack and connect via Streamable HTTP instead.

  3. Restart Claude: Fully quit and restart Claude Desktop. Look for the tool icon in the chat input.

8. Troubleshootingโ€‹

  • Connection Refused: Make sure that ERP_BASE_URL in docker-compose.yml uses the service name http://mock-erp:8081 instead of localhost. Run docker compose ps and check both /mcp/health and MockERP /health.
  • Structured control-plane error: Use the stable error value and safe suggestion in the JSON envelope. It never contains upstream bodies, credentials, or internal stack details.
  • Claude stdio timeout: If Claude fails to connect, build the server binary first and run it directly. This shows any startup errors.
  • Schema Errors: Validate the tool definition locally before you apply it:
    Validate a schema
    ./bridgectl tool validate -f schemas/erp/list_employees.json