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.
This commit is contained in:
George Lambert 2026-09-29 11:33:50 -04:00
commit baa21b7529
2 changed files with 183 additions and 0 deletions

42
README.md Normal file
View file

@ -0,0 +1,42 @@
# verae-mcp-timestamping-server-go
[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
Go MCP timestamping server for Verae. Digests only; sibling to the Python server.
Implements the same tools as https://mcp.verae.ai/mcp (`stamp`, `verify`, `hash_report`, auth tools) using the official MCP Go SDK. Designed for shadow deploy beside Python, then cutover.
## Table of Contents
- [Install](#install)
- [Usage](#usage)
- [Contributing](#contributing)
- [License](#license)
## Install
```sh
cd verae-mcp-timestamping-server-go
go build -o bin/verae-mcp-timestamping-server ./cmd/verae-mcp-timestamping-server
```
(Requires Go 1.22+ once the module is scaffolded. Design: `docs/superpowers/specs/2026-09-29-go-mcp-timestamping-server-design.md`.)
## Usage
```sh
VERAE_MCP_TRANSPORT=streamable-http \
VERAE_MCP_HOST=127.0.0.1 \
VERAE_MCP_PORT=8001 \
./bin/verae-mcp-timestamping-server
```
Point clients at `http://127.0.0.1:8001/mcp`. Global stamps use `https://api.veraetime.net` with auth from `~/.verae/auth.properties` (or `VERAE_AUTH_PROPERTIES`).
## Contributing
Questions: this research workspace / marchon@gmail.com. PRs coordinated in-workspace first. Protocol questions: https://github.com/modelcontextprotocol.
## License
UNLICENSED © George Lambert

View file

@ -0,0 +1,141 @@
# 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.