Your machine
+~/.verae/auth.properties
+Mode 600, owned by you. Holds the JWT, its expiry, your username, and your password so a stamp can log in again before the 24-hour token expires. Do not commit this file.
+diff --git a/README.md b/README.md
index 1c840df..4df2516 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,40 @@ Verae MCP timestamping server. Hash-only stamps via leaf locald/NATS.
The MCP process never hashes content. Clients send a SHA-256 hex digest. `scope=local` writes `~/.verae/mcp-timestamp-local.json`. `scope=global` POSTs to `https://api.veraetime.net/api/timestamp` (same wire as `verae-timestamp/global.Client`). `want_scope=global` verifies against that API as the central source of truth. `signup` creates a `user` account with no existing session. `login` stores the VeraeTime JWT on this host. `session` checks it. `create_user` adds an account when that JWT is an admin.
+## Table of Contents
+
+- [Install](#install)
+- [Usage](#usage)
+- [Contributing](#contributing)
+- [License](#license)
+
## Install
+On the machine that will run the server:
+
+```sh
+uvx verae-mcp-timestamping-server setup
+```
+
+`setup` asks whether this is a new account or an existing one, then writes `~/.verae/auth.properties` (mode 600). It prints the username, role, and expiry. It does not print the token. `uvx verae-mcp-timestamping-server session` prints the same check.
+
+Assistant config names the command or the public URL. It does not contain the token:
+
+```json
+{
+ "mcpServers": {
+ "verae-timestamping": {
+ "command": "uvx",
+ "args": ["verae-mcp-timestamping-server"]
+ }
+ }
+}
+```
+
+For the public server, set `url` to `https://mcp.veraetime.net/mcp`. With `VERAE_MCP_OAUTH=1` and `VERAE_MCP_PUBLIC_URL=https://mcp.veraetime.net`, the first connection opens a browser page to create an account or log in. The assistant stores that token in its own OAuth file.
+
+Development checkout:
+
```sh
cd /Users/marchon/research/modelcontextprotocol/verae-mcp-timestamping-server
uv sync --group dev
@@ -59,10 +91,11 @@ open docs/html/index.html
Sources: `docs/operator-guide.md`, `docs/architecture.md`, `docs/api.md`, `docs/standards.md`.
-Sample page (talks to Streamable HTTP on this machine):
+Install page and stamp sample:
```sh
open site/index.html
+open site/sample.html
```
Public copy of the page and the docs: `https://mcp.georgelambert.org/`.
diff --git a/docs/api.md b/docs/api.md
index 097fee5..13bc57e 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -68,7 +68,7 @@ Returns `valid`, `username`, `role`, and `expires_at`.
| `password` | required | New password |
| `role` | required | `user` or `admin` |
-`POST /auth/users` with the stored JWT. Refuses unless `session` reports role `admin`. Returns `id`, `username`, and `role`. There is no public signup; the first admin already exists on the timestamping service.
+`POST /auth/users` with the stored JWT. Refuses unless `session` reports role `admin`. Returns `id`, `username`, and `role`. Public registration is `signup`. `create_user` is how an admin sets a role.
A stored login is refreshed when `stamp` or `verify` runs and `expires_at` is missing or within 5 minutes, if `username` and `password` are in the auth file.
diff --git a/docs/html/api.html b/docs/html/api.html
index 61836ce..d076c29 100644
--- a/docs/html/api.html
+++ b/docs/html/api.html
@@ -292,9 +292,9 @@ replace the JWT stored for stamp. A new account calls
POST /auth/users with the stored JWT. Refuses unless
session reports role admin. Returns
-id, username, and role. There is
-no public signup; the first admin already exists on the timestamping
-service.
id, username, and role. Public
+registration is signup. create_user is how an
+admin sets a role.
A stored login is refreshed when stamp or
verify runs and expires_at is missing or
within 5 minutes, if username and password are
diff --git a/docs/html/operator-guide.html b/docs/html/operator-guide.html
index 148073b..48f62e0 100644
--- a/docs/html/operator-guide.html
+++ b/docs/html/operator-guide.html
@@ -112,12 +112,20 @@
site/index.html on the same machine, or put TLS and an
access control in front of a non-loopback bind you choose yourself.
A new machine runs
+uvx verae-mcp-timestamping-server setup. That creates an
+account or logs in and writes ~/.verae/auth.properties
+(mode 600). It prints username, role, and expiry, not the JWT.
+session checks that file. Starting the server with no login
+prints the setup command on stderr.
signup creates a role user account with no
-bearer token. Call login with that username and password to
-store the JWT in ~/.verae/auth.properties (mode 600). The
-server uses it for scope=global without a restart.
-session checks that JWT. create_user adds an
-account when the stored role is admin.
create_user adds an account when the stored
+role is admin.
+Set VERAE_MCP_OAUTH=1 and
+VERAE_MCP_PUBLIC_URL to the public HTTPS origin to require
+a browser login on the HTTP MCP endpoint. That login’s JWT is the
+caller’s bearer for stamp and is not written over the host
+file.
# or skip the tool and export a token yourself:
export VERAE_GLOBAL_TOKEN=...This page calls a Model Context Protocol (MCP) server. The three letters are MCP. The server name is verae-timestamping. It stamps a SHA-256 digest. It does not upload a file.
Start the server on this machine, then submit. A page on the public internet cannot reach 127.0.0.1.
VERAE_MCP_CORS=1 VERAE_MCP_TRANSPORT=streamable-http uv run verae-mcp-timestamping-server- -
Waiting.-
Docs in this repo: HTML · standards PDF
-Same files on the public host: HTML · standards PDF
- +} +No local program. The assistant connects to this host. When per-user sign-in is on, the first connection opens a browser page at /account to create an account or log in. That token stays in the assistant’s OAuth store, not in this file.
+{
+ "mcpServers": {
+ "verae-timestamping": {
+ "url": "https://mcp.veraetime.net/mcp"
+ }
+ }
+}
+
+
+ Your machine
+Mode 600, owned by you. Holds the JWT, its expiry, your username, and your password so a stamp can log in again before the 24-hour token expires. Do not commit this file.
+Your assistant
+A browser login on the public server gives the assistant a VeraeTime JWT and a refresh token. The Python client stores that under ~/.verae/oauth/mcp-tokens.json, also mode 600.
+Never
+Do not paste the token into a conversation or into the client config. session shows the username and expiry if you need to confirm the login.