#!/bin/sh # check-mcp-env — assert every variable a live MCP server interpolates is one # the session env-file actually defines. # # Why this is a gate and not a comment: the failure is silent. A header of # "Bearer ${FOO}" where FOO is undefined does not error -- it goes out empty, # the server answers 401, and Claude Code reports "requires authentication", # which reads exactly like a revoked credential. On 2026-09-07 that cost a # full investigation on koala before the credential turned out to be fine. # # Servers under `_parked` are exempt by design. Parked means "reachable, but # nothing puts its token in the environment yet" -- flagging those would # report the intended state as a fault. # # Usage: check-mcp-env # # Exit 0 every live server's variables are defined # 1 at least one is not, named on stderr # 2 could not verify (bad usage, unreadable input, jq absent). # Deliberately distinct from 0: an unverified config is not a clean # one, and a gate that cannot run should say so rather than pass. set -u CONFIG=${1:-} ENVFILE=${2:-} if [ -z "$CONFIG" ] || [ -z "$ENVFILE" ]; then echo "usage: check-mcp-env " >&2 exit 2 fi if ! command -v jq >/dev/null 2>&1; then echo "SKIP: jq not installed -- MCP env wiring unverified" >&2 exit 2 fi if [ ! -f "$CONFIG" ]; then echo "ERROR: no such config: $CONFIG" >&2 exit 2 fi if [ ! -f "$ENVFILE" ]; then echo "ERROR: no such env-file: $ENVFILE -- cannot verify MCP variables" >&2 exit 2 fi # Every "\t" pair a live server interpolates. `..` walks the whole # value, so a variable is found wherever it is placed, not only under headers. refs=$(jq -r ' .mcpServers // {} | to_entries[] | .key as $server | (.value | .. | strings) | select(test("\\$\\{")) | [ scan("\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}")[] ] | .[] | "\($server)\t\(.)" ' "$CONFIG" 2>/dev/null) || { echo "ERROR: $CONFIG is not valid JSON -- MCP env wiring unverified" >&2 exit 2 } if [ -z "$refs" ]; then echo "check-mcp-env: no interpolated variables in live servers" exit 0 fi fail=0 checked=0 for pair in $(printf '%s\n' "$refs" | tr '\t' ':'); do server=${pair%%:*} var=${pair#*:} checked=$((checked + 1)) if grep -qE "^[[:space:]]*(export[[:space:]]+)?$var=" "$ENVFILE"; then continue fi printf 'ERROR: MCP server %s interpolates %s, which %s does not define.\n' \ "$server" "$var" "$ENVFILE" >&2 printf ' It will send an empty Authorization header and report as "requires authentication".\n' >&2 fail=1 done if [ "$fail" -ne 0 ]; then exit 1 fi printf 'check-mcp-env: %d interpolated variable(s) across live MCP servers, all defined in %s\n' \ "$checked" "$ENVFILE"