Database MCP

Configuration

Configure dbmcp with CLI flags, environment variables, and backend-specific defaults

Database MCP is configured through CLI flags and environment variables. This page documents every available option.

Precedence

Configuration values are resolved in this order (highest priority first):

  1. CLI flags — explicitly passed on the command line
  2. Environment variables — set by the MCP client (via env or envFile in server config)
  3. Built-in defaults — backend-aware defaults described below

When the same option is set in multiple places, the higher-priority source wins.

Database Connection

CLI FlagEnvironment VariableDefaultDescription
--db-backendDB_BACKENDmysqlDatabase backend: mysql, mariadb, postgres, sqlite
--db-hostDB_HOSTlocalhostDatabase host (as seen from the SSH server when tunnelling)
--db-portDB_PORTBackend-dependentDatabase port (see Backend Defaults)
--db-userDB_USERBackend-dependentDatabase user (see Backend Defaults)
--db-passwordDB_PASSWORD—Database password
--db-nameDB_NAME—Database name, or file path for SQLite

Character Set

CLI FlagEnvironment VariableDefaultDescription
--db-charsetDB_CHARSET—Character set (MySQL/MariaDB only)

Backend Defaults

Default values for --db-port and --db-user depend on the selected backend:

BackendDefault PortDefault User
MySQL3306root
MariaDB3306root
PostgreSQL5432postgres
SQLiteN/AN/A

SQLite does not use host, port, or user — only --db-name (the file path) is required.

SSL / TLS

CLI FlagEnvironment VariableDefaultDescription
--db-sslDB_SSLfalseEnable SSL for the database connection
--db-ssl-caDB_SSL_CA—Path to CA certificate
--db-ssl-certDB_SSL_CERT—Path to client certificate
--db-ssl-keyDB_SSL_KEY—Path to client key
--db-ssl-verify-certDB_SSL_VERIFY_CERTtrueVerify the server certificate

When --db-ssl is enabled, the server validates that any provided certificate paths exist before connecting.

SSH Tunnel

Database MCP can reach MySQL, MariaDB, and PostgreSQL through an SSH server (bastion / jump host) using an embedded, pure-Rust SSH client — no ssh binary is needed. The tunnel is enabled when --ssh-host / SSH_HOST is set.

CLI FlagEnvironment VariableDefaultDescription
--ssh-hostSSH_HOST—SSH server host; enables the tunnel when set
--ssh-portSSH_PORT22SSH server port
--ssh-userSSH_USER—SSH user
--ssh-passwordSSH_PASSWORD—SSH password
--ssh-keySSH_KEY—Path to SSH private key (OpenSSH, PKCS#1, PKCS#8, SEC1)
--ssh-key-passphraseSSH_KEY_PASSPHRASE—Passphrase for the SSH private key
--ssh-known-hostsSSH_KNOWN_HOSTS~/.ssh/known_hostsPath to known_hosts file (default: ~/.ssh/known_hosts)
--ssh-strict-host-key-checkingSSH_STRICT_HOST_KEY_CHECKINGyesHost key policy: yes rejects unknown hosts, accept-new trusts on first use, no disables verification (insecure)
--ssh-keepalive-intervalSSH_KEEPALIVE_INTERVAL30SSH keepalive interval in seconds (0 disables)
--ssh-local-portSSH_LOCAL_PORTephemeralLocal tunnel port (default: ephemeral)

SSH_USER and one of SSH_PASSWORD / SSH_KEY are required with SSH_HOST. Setting any other SSH_* option without SSH_HOST is a startup error, as is SSH_KEY_PASSPHRASE without SSH_KEY. A leading ~ in SSH_KEY and SSH_KNOWN_HOSTS expands to your home directory; when no home directory can be determined, SSH_KNOWN_HOSTS must be set explicitly (unless the host-key policy is no).

Docker: inside the container ~ is the image's home directory, not yours. Mount the private key and a known_hosts file into the container (readable by the container user) and point SSH_KEY / SSH_KNOWN_HOSTS at the mounted paths. Avoid accept-new with --rm containers: every new container starts with an empty known_hosts and trusts the first key it sees on each launch.

{
  "mcpServers": {
    "dbmcp": {
      "command": "dbmcp",
      "args": ["stdio"],
      "env": {
        "DB_BACKEND": "postgres",
        "DB_HOST": "db.internal",
        "DB_USER": "postgres",
        "DB_NAME": "mydb",
        "SSH_HOST": "bastion.example.com",
        "SSH_USER": "deploy",
        "SSH_KEY": "~/.ssh/id_ed25519"
      }
    }
  }
}

How It Works

  • Database MCP listens on 127.0.0.1:<port> (ephemeral unless --ssh-local-port is set) and points the database driver at it. Each database connection is forwarded over its own direct-tcpip channel on one shared SSH session.
  • DB_HOST and DB_PORT are resolved by the SSH server, not locally — use the name or address the bastion can reach (e.g. db.internal, a private IP, or 127.0.0.1 for a database on the bastion itself).
  • The SSH session opens lazily on the first database connection, so an unreachable SSH server does not prevent startup. Connecting, verifying the host key, and authenticating must finish within 10 seconds.
  • If the session drops, the next database connection reconnects it. Concurrent connections share one reconnect attempt.
  • Keepalives are sent every --ssh-keepalive-interval seconds; when keepalives go unanswered for about four intervals (~2 minutes at the default 30 s) the session is treated as dead. 0 disables keepalives (a silently dropped connection is then only noticed when the operating system gives up on it).

Authentication

  • Password (SSH_PASSWORD) and private key (SSH_KEY). When both are set, the key is tried first, then the password.
  • Key formats: OpenSSH (plain or passphrase-encrypted), PKCS#1 RSA (including legacy AES-128-CBC encryption), SEC1 EC (unencrypted), PKCS#8 (plain or PBES2-encrypted).
  • Key types: Ed25519, ECDSA (P-256, P-384, P-521), and RSA. RSA keys sign with rsa-sha2-256/rsa-sha2-512, as required by OpenSSH 8.8+.
  • The key is read and decrypted once at startup; a wrong passphrase or unsupported format aborts startup.
  • On Unix, a key accessible by group or others (any of the 0o077 mode bits set) logs a warning suggesting chmod 600; startup continues. No permission check is done on Windows.

Host-Key Policies

The SSH server's host key is checked against known_hosts (re-read on every connect) before any credentials are sent.

ValueBehavior
yes (default)Only hosts already in known_hosts are accepted. Unknown hosts are rejected with the key's fingerprint and an ssh-keyscan hint.
accept-newUnknown hosts are trusted on first use and appended to known_hosts. On Unix, a newly created file gets mode 0600 and newly created directories 0700 (subject to your umask); existing ones keep their permissions. A known host presenting a different key — including a key of a type not yet recorded — is rejected.
noVerification is disabled (a warning is logged at startup). A changed key is accepted with a warning, but the password is withheld for that session. Insecure: exposes the tunnel to man-in-the-middle attacks.

Keys marked @revoked are rejected under every policy, as long as known_hosts can be read. Under no, an unreadable known_hosts is ignored with a warning, so its @revoked entries no longer apply. known_hosts entries may be hashed (|1|…), use [host]:port, comma-separated host lists, and * / ? / ! patterns. See SSH Host-Key Verification for the security implications.

Database TLS Through the Tunnel

All DB_SSL_* settings work unchanged, and TLS stays end-to-end between Database MCP and the database. DB_SSL_VERIFY_CERT=true validates the certificate chain (against system roots and DB_SSL_CA) but not the hostname, so connecting via 127.0.0.1 does not cause a name mismatch.

Limitation: because the driver connects to an IP address, no TLS SNI is sent. Services that route on SNI (for example Neon's proxy) cannot be reached through the tunnel.

Not Supported

  • SQLite (rejected at startup)
  • ssh-agent, keyboard-interactive / 2FA authentication
  • ~/.ssh/config parsing and Host aliases
  • Multi-hop / ProxyJump, HTTP or SOCKS proxies in front of SSH
  • Host-key fingerprint pinning (use a dedicated known_hosts file instead)
  • DSA keys, FIDO/security-key (sk-*) keys, user certificates
  • Host certificates and @cert-authority entries
  • Hostname-verifying database TLS (verify-full)

Troubleshooting

Unknown host key — under yes, the error names the fingerprint and suggests a command:

SSH host key for bastion.example.com (SHA256:…) is not in /home/me/.ssh/known_hosts; verify the fingerprint, then run `ssh-keyscan -p 22 bastion.example.com >> /home/me/.ssh/known_hosts`

Compare the fingerprint with one obtained out-of-band (e.g. from the server's console via ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub) before running the suggested command.

Host key does not match — … does not match <file>:<line>; the server may be impersonated. If the server was legitimately re-keyed, remove the old entry with ssh-keygen -R <host> (or ssh-keygen -R '[host]:port') and add the new one.

Unsupported or legacy key encryption — SSH key <path> uses an unsupported encryption format; re-encrypt it with ssh-keygen -p -f <path>. This covers legacy PEM keys encrypted with AES-256 or 3DES, encrypted SEC1 EC keys, and PKCS#8 PBES1. ssh-keygen -p rewrites the key in the OpenSSH format. An encrypted key without SSH_KEY_PASSPHRASE fails with SSH key <path> is encrypted; set SSH_KEY_PASSPHRASE.

Unsupported key types — DSA, FIDO (sk-ecdsa-…, sk-ssh-ed25519-…) keys, and certificates cannot be loaded. Use an Ed25519, ECDSA, or RSA key.

SSH_HOST is not supported with the sqlite backend — SQLite is a local file; remove the SSH_* settings.

Tool errors ending in (SSH tunnel: …) — when the database cannot be reached and the tunnel has an unresolved failure (connect timeout, authentication, host key, channel open, or a lost session), the cause is appended to the tool error, e.g. … (SSH tunnel: SSH authentication failed for deploy@bastion.example.com:22). Other errors (SQL errors, read-only rejections) never get the suffix. It disappears once a connection through the tunnel succeeds. Failed connects are also logged with their full error chain at error level; a lost session is logged at warn.

Windows: os error 10013 with --ssh-local-port — the port falls in a range Windows reserves (often for Hyper-V/WSL). List reserved ranges with netsh interface ipv4 show excludedportrange protocol=tcp, pick a port outside them, or omit --ssh-local-port to use an ephemeral port.

Windows: a different known_hosts than ssh uses — Database MCP resolves ~ from USERPROFILE. Win32-OpenSSH (ssh.exe in System32) uses the Windows profile directory even when USERPROFILE is overridden, and Git Bash's ssh uses $HOME, so they may read a different known_hosts. Set SSH_KNOWN_HOSTS explicitly to share one file. A known_hosts created outside your profile inherits that folder's permissions.

Server Behavior

CLI FlagEnvironment VariableDefaultDescription
--db-read-onlyDB_READ_ONLYtrueEnable read-only mode
--db-max-pool-sizeDB_MAX_POOL_SIZE5Maximum database connection pool size
--db-connection-timeoutDB_CONNECTION_TIMEOUT—Connection timeout in seconds
--db-query-timeoutDB_QUERY_TIMEOUT30Query execution timeout in seconds
--db-page-sizeDB_PAGE_SIZE100Max items per paginated tool response (range 1–500)
--log-levelLOG_LEVELinfoLog level: error, warn, info, debug, trace

Security note: Read-only mode is enabled by default. In this mode, write tools (writeQuery, createDatabase) are hidden from the AI assistant. Only read tools are available, and readQuery enforces SQL validation (SELECT, SHOW, DESCRIBE, USE, EXPLAIN only). Set --db-read-only=false or DB_READ_ONLY=false to enable write tools.

The page size applies uniformly to every paginated tool; see the Cursor Pagination section on the Features page for the full protocol.

HTTP Transport

These options are available only when running in HTTP mode (dbmcp http):

CLI FlagDefaultDescription
--host127.0.0.1Bind host for the HTTP server
--port9001Bind port for the HTTP server
--allowed-originshttp://localhost:*,http://127.0.0.1:*,http://[::1]:*,https://localhost:*,https://127.0.0.1:*,https://[::1]:*Allowed browser origins (comma-separated). Drives both CORS preflight and server-side Origin header rejection. Use :* to match any port or an explicit port (https://app.example:443); entries without a port are deprecated. Malformed entries are rejected at startup; pass "" to disable Origin validation for non-browser deployments.
--allowed-hostslocalhost,127.0.0.1,::1Allowed host names (comma-separated). Enforced server-side; HTTP/2 :authority is honored.
--auth-token(unset)Bearer token required on every request (Authorization: Bearer <token>). Env: HTTP_AUTH_TOKEN (preferred — CLI args are visible in ps). Required for non-loopback binds.
--dangerously-allow-unauthenticatedfalseAllow a non-loopback bind without a token. Env: HTTP_DANGEROUSLY_ALLOW_UNAUTHENTICATED. Only behind a reverse proxy that authenticates callers.

Security note: Binding a non-loopback host (e.g. --host 0.0.0.0) without HTTP_AUTH_TOKEN is refused at startup. The Origin/Host allowlists defend against browser DNS rebinding only — they do not authenticate callers.

Security note: The default --allowed-origins accept browser pages served from any port on localhost/127.0.0.1/[::1], so any local web app can call the server. On shared or development machines, set HTTP_AUTH_TOKEN or narrow --allowed-origins to the explicit origins you trust (e.g. http://localhost:5173).

A transport subcommand is required — running dbmcp with no subcommand prints usage help and exits with a non-zero status. The stdio transport requires no additional configuration beyond the database options above.

PII

Database MCP can rewrite detected PII spans inside query tool output. The feature is opt-in and off by default — applies to query tool response payloads (readQuery and any future query tools that route through the redactor) and to tool error messages (regex recognizers only, no NER pass). It is not applied to logs, successful schema-discovery responses, or tool arguments. See Features for the supported entity list.

CLI FlagEnvironment VariableDefaultDescription
--piiPII_ENABLEfalseEnable PII redaction of query tool output
--pii-operatorPII_OPERATORreplaceOperator applied to detected PII spans
--pii-categoriesPII_CATEGORIESunset (all built-ins)Comma-separated category subset for the analyzer registry
--pii-nerPII_NER_ENABLEfalseEnable the optional ML/NER pass (person, location, organization, NRP & facility detection)
--pii-ner-modelPII_NER_MODELunsetPath to the NER model directory (required with --pii-ner)

Operator Values

--pii-operator accepts one of the following values:

  • replace — replace each detected span with an entity-aware placeholder (for example, an EMAIL_ADDRESS match becomes <EMAIL_ADDRESS>)
  • mask — mask each detected span with * (length-preserving)
  • redact — remove each detected span (replace with empty string)
  • hash — replace each detected span with a stable hex digest (SHA-256)

Category Values

--pii-categories accepts a comma-separated list of kebab-case category names. Leaving the flag unset enables every built-in recogniser; passing a subset narrows the analyzer registry to recognisers tagged with at least one of the selected categories.

  • personal — EMAIL_ADDRESS
  • financial — BANK_ACCOUNT_UK, CREDIT_CARD, CVV, IBAN_CODE, ROUTING_NUMBER_US, SORT_CODE_UK
  • government — ITIN, NHS_NUMBER, NINO_UK, PASSPORT_UK, PASSPORT_US, SIN_CA, TAX_ID_EIN, US_SSN, VAT_NUMBER
  • contact — PHONE_NUMBER
  • network — IP_ADDRESS, MAC_ADDRESS, URL
  • digital-identity — API_KEY, JWT_TOKEN, PRIVATE_KEY
  • crypto — CRYPTO

An empty list is rejected at startup. If the selected categories produce an empty registry, the analyzer falls back to the default registry and logs a warning so redaction is never silently disabled.

ML/NER pass (person, location, organization, NRP & facility)

The regex/checksum recognisers cannot catch free-form person names, place names, organizations, nationality/religious/political groups, or facilities — those have no fixed pattern. An optional machine-learning Named Entity Recognition (NER) pass adds PERSON, LOCATION, ORGANIZATION, NATIONALITY_RELIGION_POLITICS, and FACILITY detection on top of the regex layer. Which entities a given model can produce depends on its label set: a CoNLL model (e.g. dslim/bert-base-NER) yields person/location/organization, while an OntoNotes-class model additionally yields NRP and facility.

It is opt-in at runtime: the ML/NER code is always built into the binary, but stays inactive until both --pii and --pii-ner are enabled and a model directory is supplied.

Inference uses ONNX Runtime — there is no external runtime library to install: you need only the dbmcp binary and a model directory. The directory must contain:

  • config.json (with an id2label map exposing at least one supported NER label: PER/PERSON, LOC/GPE, ORG/ORGANIZATION, NORP/NRP, or FAC)
  • tokenizer.json
  • model.onnx

Any other files in the directory are ignored — dbmcp reads only these three.

Set up a model locally

The quickest path is to download a model that has already been exported to ONNX. The steps below use the recommended English model, optimum/bert-base-NER — an ONNX export of dslim/bert-base-NER (MIT licensed). It uses CoNLL labels, so it detects PERSON, LOCATION, and ORGANIZATION; protectai/bert-base-NER-onnx is an equivalent alternative. NRP and facility detection require an OntoNotes-class model. v1 is English-only, but the pipeline is model-agnostic — any directory with the three files above works.

Note: These pre-exported models are full-precision (fp32, ~430 MB). They need no Python toolchain to obtain, but an int8-quantized export is smaller and faster at inference if you can produce one.

1. Download the model into a local directory — either with the Hugging Face CLI (pip install huggingface_hub):

hf download optimum/bert-base-NER \
  --include config.json tokenizer.json model.onnx \
  --local-dir ./models/bert-ner

--include fetches only the three required files and skips the rest.

or with git + Git LFS (the model.onnx weights are LFS-tracked):

git lfs install
git clone https://huggingface.co/optimum/bert-base-NER ./models/bert-ner

or manually from the browser — open the model's Files and versions tab on Hugging Face and download config.json, tokenizer.json, and model.onnx with the download icon next to each, saving all three into one directory (e.g. ./models/bert-ner).

2. Confirm the required files are present:

ls ./models/bert-ner
# config.json  model.onnx  tokenizer.json  (plus vocab.txt, tokenizer_config.json, … — ignored)

3. Start dbmcp with the NER pass enabled, pointing at the directory:

dbmcp stdio --db-backend sqlite --db-name app.db \
  --pii true --pii-ner true --pii-ner-model ./models/bert-ner

4. Verify it loaded. Loading is fail-closed: a missing file or an unusable model makes the server refuse to start, so a clean startup means the model loaded. To confirm the pass is rewriting output, run a readQuery over a column holding a person or place name and check the value comes back as <PERSON> / <LOCATION> (with the default replace operator).

Behaviour notes:

  • Fail-closed. If --pii-ner is set but the model cannot be loaded, the server refuses to start. If inference fails mid-request, that request errors — it never silently falls back to regex-only.
  • Category-aware. The NER pass respects --pii-categories: PERSON, ORGANIZATION, and NATIONALITY_RELIGION_POLITICS are emitted only when personal is selected; LOCATION and FACILITY only when contact is. With no subset (the default), all apply. When the subset selects neither category, the model is not loaded at all.

Default: redaction is off. Setting PII_ENABLE=true (or --pii true) is the only way to activate the redactor — PII_OPERATOR, PII_CATEGORIES, and the PII_NER_* flags alone have no effect.

Client Configuration Examples

MCP clients configure servers through JSON files. Each tool uses a slightly different file path, but the format is nearly identical. The examples below connect to a local MySQL database.

Claude Code

Create a .mcp.json file in your project root:

{
  "mcpServers": {
    "dbmcp": {
      "command": "dbmcp",
      "args": ["stdio"],
      "env": {
        "DB_BACKEND": "mysql",
        "DB_HOST": "localhost",
        "DB_USER": "root",
        "DB_PASSWORD": "secret",
        "DB_NAME": "myapp"
      }
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Claude Code also supports HTTP transport for remote servers:

{
  "mcpServers": {
    "dbmcp": {
      "type": "http",
      "url": "http://127.0.0.1:9001/mcp"
    }
  }
}

File locations: .mcp.json (project, shareable) · ~/.claude.json (user, global)

Using Docker:

{
  "mcpServers": {
    "dbmcp": {
      "type": "stdio",
      "command": "docker",
      "args": ["run", "-i", "--rm",
        "-e", "DB_BACKEND", "-e", "DB_HOST", "-e", "DB_USER",
        "-e", "DB_PASSWORD", "-e", "DB_NAME",
        "ghcr.io/haymon-ai/dbmcp"
      ],
      "env": {
        "DB_BACKEND": "postgres",
        "DB_HOST": "host.docker.internal",
        "DB_USER": "postgres",
        "DB_PASSWORD": "secret",
        "DB_NAME": "myapp"
      }
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Claude Desktop

Edit the config file at:

  • Linux: ~/.config/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "dbmcp": {
      "command": "dbmcp",
      "args": ["stdio"],
      "env": {
        "DB_BACKEND": "postgres",
        "DB_HOST": "localhost",
        "DB_USER": "postgres",
        "DB_PASSWORD": "secret",
        "DB_NAME": "myapp"
      }
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Using Docker:

{
  "mcpServers": {
    "dbmcp": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
        "-e", "DB_BACKEND", "-e", "DB_HOST", "-e", "DB_USER",
        "-e", "DB_PASSWORD", "-e", "DB_NAME",
        "ghcr.io/haymon-ai/dbmcp"
      ],
      "env": {
        "DB_BACKEND": "postgres",
        "DB_HOST": "host.docker.internal",
        "DB_USER": "postgres",
        "DB_PASSWORD": "secret",
        "DB_NAME": "myapp"
      }
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Claude Desktop only supports stdio transport. For HTTP mode, use the Connectors UI under Settings > Connectors > Add custom connector.

Cursor

Create .cursor/mcp.json in your project root, or use ~/.cursor/mcp.json for global configuration:

{
  "mcpServers": {
    "dbmcp": {
      "type": "stdio",
      "command": "dbmcp",
      "args": ["stdio"],
      "env": {
        "DB_BACKEND": "mysql",
        "DB_HOST": "localhost",
        "DB_USER": "root",
        "DB_NAME": "myapp"
      },
      "envFile": ".env"
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Using Docker:

{
  "mcpServers": {
    "dbmcp": {
      "type": "stdio",
      "command": "docker",
      "args": ["run", "-i", "--rm",
        "-e", "DB_BACKEND", "-e", "DB_HOST", "-e", "DB_USER",
        "-e", "DB_PASSWORD", "-e", "DB_NAME",
        "ghcr.io/haymon-ai/dbmcp"
      ],
      "env": {
        "DB_BACKEND": "mysql",
        "DB_HOST": "host.docker.internal",
        "DB_USER": "root",
        "DB_NAME": "myapp"
      },
      "envFile": ".env"
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Cursor supports envFile to load variables from a .env file. Sensitive values like DB_PASSWORD can be kept there instead of in the JSON config.

Windsurf

Edit the config file at:

  • Linux: ~/.codeium/windsurf/mcp_config.json
{
  "mcpServers": {
    "dbmcp": {
      "command": "dbmcp",
      "args": ["stdio"],
      "env": {
        "DB_BACKEND": "mysql",
        "DB_HOST": "localhost",
        "DB_USER": "root",
        "DB_PASSWORD": "${env:DB_PASSWORD}",
        "DB_NAME": "myapp"
      }
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Using Docker:

{
  "mcpServers": {
    "dbmcp": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
        "-e", "DB_BACKEND", "-e", "DB_HOST", "-e", "DB_USER",
        "-e", "DB_PASSWORD", "-e", "DB_NAME",
        "ghcr.io/haymon-ai/dbmcp"
      ],
      "env": {
        "DB_BACKEND": "mysql",
        "DB_HOST": "host.docker.internal",
        "DB_USER": "root",
        "DB_PASSWORD": "${env:DB_PASSWORD}",
        "DB_NAME": "myapp"
      }
    }
  }
}

To enable PII redaction, add "PII_ENABLE": "true" and optionally "PII_OPERATOR": "<replace|mask|redact|hash>" (and "PII_CATEGORIES": "<personal,financial,...>" to scope detection) to the env map.

Windsurf supports ${env:VARIABLE_NAME} interpolation to reference values from your shell environment instead of hardcoding them.

Environment Variables vs. envFile

FeatureClaude CodeClaude DesktopCursorWindsurf
env objectYesYesYesYes
envFileNoNoYesNo
Variable interpolation${VAR}No${env:VAR}${env:VAR}
HTTP transport in configYesNoYesYes
Project-scoped configYesNoYesNo

On this page