verae-mcp-timestamping-serv.../docs/superpowers/specs/2026-09-29-go-mcp-timestamping-server-design.md
George Lambert baa21b7529 docs: design for Go MCP timestamping server
Sibling to the Python verae-mcp-timestamping-server. Full tool parity,
FileLedger, optional NATS (no JetStream for job-complete), official
go-sdk Streamable HTTP, shadow on :8001 then cutover checklist.
2026-09-29 11:33:50 -04:00

6.3 KiB
Raw Blame History

Go MCP timestamping server

Date: 2026-09-29
Status: Draft for review
Sibling of: verae-mcp-timestamping-server (Python, live on ns1)
Contract: Same digests-only MCP tools as https://mcp.verae.ai/mcp and Application Client OpenAPI

Problem

The live Verae MCP timestamping service is a Python process (verae-mcp-timestamping-server in a venv, Streamable HTTP on 127.0.0.1:8000). Operators want a Go executable with full tool and ledger parity, suitable for shadow deploy and eventual cutover, without changing the public MCP contract.

Goals

  1. Single static Go binary implementing the MCP timestamping server.
  2. Full tool parity: stamp, verify, hash_report, signup, login, session, create_user.
  3. Local/shared FileLedger (JSON file, mode 0600) and global VeraeTime HTTPS client.
  4. Optional core-NATS bridge (same subjects as Python); no JetStream for job-complete.
  5. Streamable HTTP + stdio transports; CORS / allowed hosts/origins compatible with ns1.
  6. Shadow on ns1 beside Python; documented cutover checklist.

Non-goals (this project)

  • Changing live MCP tool schemas or Application Client OpenAPI semantics.
  • Replacing Python on day one without a shadow period.
  • JetStream (or other persistent streams) for job-complete / jobId notification.
  • Accepting file bytes / content on stamp tools.

Current state (Python)

  • Package: verae-mcp-timestamping-server (Python ≥3.10, mcp[cli]).
  • Deploy: /opt/verae/verae-mcp-timestamping-server, user verae-mcp, systemd verae-mcp-timestamping.service.
  • Public: Caddy → 127.0.0.1:8000 for mcp.verae.ai, mcp.veraetime.net, mcp.georgelambert.org.
  • Global stamps: POST https://api.veraetime.net/api/timestamp with restamp: false.

Architecture

Clients
   │
   ▼
verae-mcp-timestamping-server-go
   ├── local|shared → FileLedger (~/.verae/mcp-timestamp-local.json or VERAE_LEDGER_PATH)
   ├── global       → api.veraetime.net (/api/timestamp, /api/verify, /api/hash/{sha}, /auth/*)
   └── optional NATS → verae.ts.request, verae.ts.verify, verae.hash.report (core NATS only)

SDK: official github.com/modelcontextprotocol/go-sdk/mcp (NewStreamableHTTPHandler, AddTool, stdio).

Repository layout

Path: /Users/marchon/research/modelcontextprotocol/verae-mcp-timestamping-server-go
Remote (planned): ssh://git@git.georgelambert.org:2223/marchon/verae-mcp-timestamping-server-go.git

cmd/verae-mcp-timestamping-server/main.go
internal/config/
internal/digest/
internal/ledger/          # FileLedger
internal/veraetime/       # GlobalClient + auth.properties
internal/natsbridge/      # optional
internal/tools/           # MCP tool handlers
docs/superpowers/specs/
docs/cutover.md           # cutover checklist (deliverable)
README.md                 # Standard Readme

Binary name: verae-mcp-timestamping-server
Install dir on ns1 (shadow): /opt/verae/verae-mcp-timestamping-server-go/ so it does not overwrite the Python venv path.

Tool contract

Match Python docs/api.md / live tools/list:

Tool Required args Notes
stamp sha256 scope local|shared|global; optional cube_id, org_id
verify receipt_id optional want_scope; global or CID-like id → VeraeTime
hash_report sha256 optional org_id, want_scope
signup username, password VeraeTime /auth/signup
login username, password stores JWT in auth.properties; does not return JWT
session — /auth/validate
create_user username, password, role admin bearer

Digests only: reject content/bytes/file/data/path/body/payload/blob/archive.
Normalize SHA-256 (optional sha256: prefix; 64 hex).
Global stamp: restamp: false; poll /api/status/{jobId} when needed.

Config (env)

Variable Default
VERAE_MCP_TRANSPORT streamable-http (or stdio)
VERAE_MCP_HOST 127.0.0.1
VERAE_MCP_PORT 8000 (shadow uses 8001)
VERAE_GLOBAL_URL https://api.veraetime.net
VERAE_AUTH_PROPERTIES $HOME/.verae/auth.properties
VERAE_LEDGER_PATH $HOME/.verae/mcp-timestamp-local.json
VERAE_NATS_URL empty (optional)
VERAE_MCP_CORS unset / 1
VERAE_MCP_ALLOWED_HOSTS same list as Python verae-ai.conf
VERAE_MCP_ALLOWED_ORIGINS same list as Python

HOME for the service user remains /var/lib/verae-mcp (shared auth file with Python during shadow if desired, or separate path for isolation).

Shadow deploy

  1. Build linux amd64 (and optionally arm64) release binary.
  2. Install under /opt/verae/verae-mcp-timestamping-server-go/.
  3. Systemd unit verae-mcp-timestamping-go.service: VERAE_MCP_PORT=8001, same user verae-mcp, same or dedicated auth properties.
  4. Optional Caddy path or internal-only listen for smoke (do not steal public /mcp until cutover).
  5. Compare tools/list and stamp/verify/hash_report against Python on :8000.

Cutover checklist (docs/cutover.md)

  1. Shadow green for agreed soak (tools + global stamp/verify/hash_report + local ledger).
  2. Stop Python unit (or switch Caddy upstream).
  3. Point Go unit at VERAE_MCP_PORT=8000 (or Caddy to Go’s port).
  4. Confirm https://mcp.verae.ai/mcp tools/list and a known digest hash_report.
  5. Keep Python tree on disk for rollback for one release cycle.
  6. Rollback: restore Python ExecStart / Caddy upstream; restart.

Testing

  • Unit: digest normalize/guard; FileLedger idempotency; VeraeTime request shaping (restamp: false) with fake HTTP.
  • Integration: Streamable HTTP initialize → tools/call against an httptest test server.
  • Parity script: same digests against Python :8000 and Go :8001.
  • Optional live smoke behind flag (requires auth.properties).

Success criteria

  • go build produces a single runnable binary.
  • Full tool list matches Python.
  • Local/shared persist to ledger file; global uses VeraeTime with caller/host token.
  • Optional NATS path does not use JetStream for job-complete.
  • Shadow unit runs on ns1 without disturbing Python :8000.
  • Cutover doc is complete enough to swap without inventing steps on the day.

Open follow-ups

  • Whether shadow shares /var/lib/verae-mcp/auth.properties with Python or uses a separate file.
  • Whether public hostname gets a temporary Go-only path (e.g. /mcp-go) during soak.