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:
commit
baa21b7529
2 changed files with 183 additions and 0 deletions
42
README.md
Normal file
42
README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# verae-mcp-timestamping-server-go
|
||||||
|
|
||||||
|
[](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
|
||||||
|
|
@ -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.
|
||||||
Loading…
Reference in a new issue