# Shadow deploy and cutover (Go MCP) Python stays on `127.0.0.1:8000`. Go shadows on `127.0.0.1:8001` with embedded NATS on `127.0.0.1:4223`. Do **not** install or enable the Go unit on ns1 until an explicit publish/deploy order. ## Shadow layout | Role | Bind | Notes | | --- | --- | --- | | Python MCP (live) | `127.0.0.1:8000` | Caddy → public `/mcp` | | Go MCP (shadow) | `127.0.0.1:8001` | Internal smoke only until cutover | | Go embedded NATS | `127.0.0.1:4223` | `pkg/tsnats` / bulk workers | Install tree (when deploying): `/opt/verae/verae-mcp-timestamping-server-go/` (does not overwrite the Python venv). Unit file in-repo: `deploy/verae-mcp-timestamping-go.service`. ## Bearer / host-token (shadow default) | `VERAE_MCP_REQUIRE_BEARER` | Behavior | | --- | --- | | `0` or unset (**default**) | Caller `Authorization: Bearer` wins when present. Otherwise the process keeps a host token from `~/.verae/auth.properties` (or `VERAE_AUTH_PROPERTIES` / `VERAE_GLOBAL_TOKEN`) and refreshes before expiry. | | `1` | Caller bearer required for global VeraeTime paths; no host-token fallback. | Shadow unit ships `VERAE_MCP_REQUIRE_BEARER=0` so operators can smoke without every client supplying a JWT. ## Embedded NATS / job-complete - Listen: `VERAE_NATS_LISTEN=127.0.0.1:4223` (set empty to disable embed). - Request/reply: `verae.ts.request`, `verae.ts.verify`, `verae.hash.report`. - Job-complete / jobId notify: **core NATS only** on `verae.ts.completed` (and receipt notify if used). **No JetStream** (or other persistent stream) for job-complete. Publishers fire-and-forget; listeners subscribe. ## Env cheat sheet (shadow) ```sh VERAE_MCP_TRANSPORT=streamable-http VERAE_MCP_HOST=127.0.0.1 VERAE_MCP_PORT=8001 VERAE_NATS_LISTEN=127.0.0.1:4223 VERAE_MCP_REQUIRE_BEARER=0 # optional: VERAE_AUTH_PROPERTIES, VERAE_LEDGER_PATH, VERAE_GLOBAL_URL, VERAE_GLOBAL_TOKEN, VERAE_MCP_CORS ``` Service user on ns1 is `verae-mcp` with `HOME=/var/lib/verae-mcp` (share or isolate `auth.properties` vs Python as chosen for the soak). ## Local parity before soak With Python on `:8000` and Go on `:8001`: ```sh ./scripts/parity_smoke.sh ``` Compares `tools/list` name sets. Optionally stamp/verify/hash_report the same digests against both ports during soak. ## Cutover checklist 1. Shadow green for the agreed soak (tools/list parity, global stamp/verify/hash_report, local ledger, NATS stamp + `verae.ts.completed` observe). 2. Stop Python unit **or** switch Caddy upstream away from `:8000` Python. 3. Point Go at public port: set `VERAE_MCP_PORT=8000` (or leave Go on `8001` and point Caddy at Go). 4. Confirm `https://mcp.verae.ai/mcp` `tools/list` and a known digest `hash_report`. 5. Keep the Python tree on disk for one release cycle. 6. Do not enable JetStream for job-complete as part of cutover. ## Rollback checklist 1. Restore Python `ExecStart` / Caddy upstream to `127.0.0.1:8000` Python. 2. Stop or disable `verae-mcp-timestamping-go.service` (or move Go back to `:8001` only). 3. Restart Python; confirm public `tools/list` and a known `hash_report`. 4. Leave Go binary under `/opt/verae/verae-mcp-timestamping-server-go/` for a later retry; do not delete until soak of the rollback is confirmed.