#!/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 <mcp.json> <env-file>
#
# 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 <mcp.json> <env-file>" >&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
  # EXPECTED IN CI, and permanently so. The env-file holds live credentials, so
  # it is not on the runner and must not be -- which means this check can only
  # ever verify on a host that has one. infra#368 added jq to the runner image
  # believing that would let CI verify; it removed the jq branch below and
  # changed nothing else, because this branch is the binding one.
  #
  # Said plainly so nobody concludes CI covers this. It does not, it cannot,
  # and putting ~/.op-env on the runner to make it would be trading a real
  # secret for a green tick.
  echo "ERROR: no such env-file: $ENVFILE -- cannot verify MCP variables" >&2
  echo "       (expected in CI: this check only verifies on a host with ~/.op-env)" >&2
  exit 2
fi

# Every "<server>\t<VAR>" 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"
