#!/usr/bin/env bash # check-mcp-client-sync.sh — drift guard for the vendored streamable-HTTP MCP client. # # The RemoteMcpClient in extensions/pi/mempalace.ts is a VENDORED copy of the # canonical implementation in pi-extensions/extensions/mcp-loader.ts (the two # repos ship independently, so a shared import isn't practical for one small, # protocol-frozen class — see the annotated header in mempalace.ts). # # Both blocks carry a matching sync token: # MCP-STREAMABLE-HTTP-CLIENT-SYNC: vN # Bump it in BOTH files whenever the streamable-HTTP protocol handling changes. # This guard fails when the tokens diverge, so a protocol fix in one file can't # silently skip the other. # # It is a LOCAL developer guard: it needs the sibling pi-extensions checkout to # compare against. If that isn't found it SKIPS (exit 0) rather than failing — # so it's safe to wire into CI that only checks out this repo. # # Point it at a specific checkout with: PI_EXTENSIONS_DIR=/path/to/pi-extensions set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" VENDORED="$REPO_ROOT/extensions/pi/mempalace.ts" TOKEN_RE='MCP-STREAMABLE-HTTP-CLIENT-SYNC: v[0-9]+' extract_token() { grep -oE "$TOKEN_RE" "$1" 2>/dev/null | head -1 | grep -oE 'v[0-9]+' || true; } if [[ ! -f "$VENDORED" ]]; then echo "ERROR: vendored file not found: $VENDORED" >&2 exit 1 fi VENDORED_TOKEN="$(extract_token "$VENDORED")" if [[ -z "$VENDORED_TOKEN" ]]; then echo "FAIL: no '$TOKEN_RE' token in $VENDORED" >&2 echo " The vendored RemoteMcpClient must carry a sync token." >&2 exit 1 fi # Locate the canonical mcp-loader.ts across common dev layouts. CANDIDATES=( "${PI_EXTENSIONS_DIR:-}/extensions/mcp-loader.ts" "$REPO_ROOT/../pi-extensions/extensions/mcp-loader.ts" "/workspace/pi-extensions/extensions/mcp-loader.ts" "$HOME/src/pi-extensions/extensions/mcp-loader.ts" "$HOME/src/src_local/pi-extensions/extensions/mcp-loader.ts" "/opt/pi-extensions/extensions/mcp-loader.ts" ) CANONICAL="" for c in "${CANDIDATES[@]}"; do [[ -n "$c" && -f "$c" ]] && { CANONICAL="$c"; break; } done if [[ -z "$CANONICAL" ]]; then echo "SKIP: canonical pi-extensions/extensions/mcp-loader.ts not found — cannot compare." echo " (vendored token: $VENDORED_TOKEN). Set PI_EXTENSIONS_DIR to enable the check." exit 0 fi CANONICAL_TOKEN="$(extract_token "$CANONICAL")" if [[ -z "$CANONICAL_TOKEN" ]]; then echo "FAIL: no '$TOKEN_RE' token in canonical $CANONICAL" >&2 exit 1 fi if [[ "$VENDORED_TOKEN" != "$CANONICAL_TOKEN" ]]; then echo "FAIL: MCP client sync token drift." >&2 echo " vendored ($VENDORED): $VENDORED_TOKEN" >&2 echo " canonical ($CANONICAL): $CANONICAL_TOKEN" >&2 echo " A streamable-HTTP protocol change landed in one file but not the other." >&2 echo " Reconcile RemoteMcpClient in both, then bump the token in BOTH to match." >&2 exit 1 fi echo "OK: MCP client sync token matches ($VENDORED_TOKEN)." echo " vendored: $VENDORED" echo " canonical: $CANONICAL"