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.
# 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 enablessystem.*_testdemonstration tools; production must leaveMCP_ENABLE_TEST_TOOLSunset 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.
| Variable | Description | Default (compose) |
|---|---|---|
BASE_URL | Public URL of the MCP server. | http://localhost:8080 |
ERPBRIDGE_HOST_PORT | Host port for the ERPBridge container. | 8080 |
ERP_BASE_URL | Base URL of the underlying ERP system. | http://mock-erp:8081 |
MOCK_ERP_HOST_PORT | Host port for the MockERP container. | 8081 |
MOCK_ERP_IMAGE | Pinned MockERP image. | ghcr.io/nmdra/mockerp:0.2.1 |
MOCK_ERP_VERSION | MockERP release used for OpenAPI specification generation. | 0.2.1 |
MOCK_ERP_OPENAPI_URL | Versioned MockERP OpenAPI URL. | https://raw.githubusercontent.com/nmdra/mockerp/v0.2.1/openapi.yaml |
MOCK_ERP_CREDENTIALS_JSON | JSON credentials for local/container use. | (required) |
MOCK_ERP_CREDENTIALS_FILE | Mounted JSON secret path. | (required alternative) |
REDIS_URL | URL for the Redis cache. | redis://redis:6379 |
REDIS_HOST_PORT | Host port for Redis. | 6379 |
REDIS_INSIGHT_BIND_ADDRESS | Host address for the RedisInsight binding. | 127.0.0.1 |
REDIS_INSIGHT_HOST_PORT | Host port for RedisInsight. | 8001 |
MCP_ENABLE_TEST_TOOLS | Development-only registration of system.*_test tools. | true in this Compose path |
DATABASE_PATH | Path of the SQLite tool registry inside the container. | /app/data/erpbridge.db |
RATE_LIMIT_RPS | Per-session requests per second. | 10 |
RATE_LIMIT_BURST | Token bucket burst size. | 20 |
API_AUTH_TOKEN | Admin bearer token for protected control-plane, MCP, and direct-invoke routes. | (unset) |
ERP_PRIMARY_KEY | Example environment credential referenced by generated ERP tools. | (unset) |
ERPBRIDGE_CREDENTIALS_DIR | Optional 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_ALLOWLIST | Exact normalized host:port values allowed for credentialed plugin endpoints. | (unset) |
INSECURE_AUTH_ALLOWED_HOSTS | Exact 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
- 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
- Generate one temporary YAML draft:
Generate one draft stream./bridgectl tool generate --context "$CTX" --api erp -o yaml > /tmp/erpbridge-draft.yaml
- 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.
-
Build bridgectl:
Build the CLIgo build -o bridgectl tools/bridgectl/main.go -
Verify Connection:
Verify connection./bridgectl tool get -
Generate the pinned MockERP tools:
Generate and apply toolsmake generate-toolsThe Makefile downloads the versioned MockERP OpenAPI contract, generates the tool YAML, and applies it to ERPBridge.
-
Test an API through the server:
Run the server-side probe./bridgectl api test --context "$CTX" erpThe default probe resolves
credentialRefin the server and returns only a bounded status summary. Use--localonly for an explicit legacy host-side diagnostic. CLI control-plane requests use the configured MCP host root; only the exact/mcpor/mcp/suffix is removed. Other paths returnCONTROL_PLANE_URL_INVALID./mcp/remains the MCP transport endpoint.
5. Logs and monitoringโ
- View Container Logs:
Follow container logsdocker 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 (stdio)
- Cursor (Streamable HTTP)
Claude Desktop connects to MCP servers via standard input and output. The server binary supports the --stdio flag.
-
Locate Configuration:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
- macOS:
-
Add ERPBridge Server: Add the following to the
mcpServerssection. 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 persistenceThe 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 composestack and connect via Streamable HTTP instead. -
Restart Claude: Fully quit and restart Claude Desktop. Look for the tool icon in the chat input.
Cursor connects to remote MCP servers via HTTP. Use this method when the ERPBridge stack is already running via docker compose up.
-
Make Sure the Server Is Running: Verify that the stack is up and the server is reachable at
http://localhost:8080. -
Configure Cursor:
- Open Cursor Settings (
Cmd+,orCtrl+,). - Navigate to Features > MCP.
- Click + Add New MCP Server.
- Name:
ERPBridge - Type:
streamable-http(orhttp, depending on your Cursor version) - URL:
http://localhost:8080/mcp/
- Open Cursor Settings (
-
Verify: You see a green status indicator. You can now use the ERP tools in Cursor Chat or Composer.
8. Troubleshootingโ
- Connection Refused: Make sure that
ERP_BASE_URLindocker-compose.ymluses the service namehttp://mock-erp:8081instead oflocalhost. Rundocker compose psand check both/mcp/healthand MockERP/health. - Structured control-plane error: Use the stable
errorvalue and safesuggestionin 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