verae-mcp-timestamping-server/site/sample.html
George Lambert c3e0cd3abb feat: add setup, browser login, and an install homepage
setup registers or logs in and writes ~/.verae/auth.properties
without printing the JWT. A caller bearer is used for stamp and
verify instead of the host login. VERAE_MCP_OAUTH=1 serves the
browser account page. site/index.html is the public install guide.
2026-09-23 12:04:15 -04:00

91 lines
4.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Verae timestamping MCP sample</title>
<style>
body { font-family: Georgia, serif; max-width: 42rem; margin: 2rem auto; padding: 0 1rem; line-height: 1.45; }
label { display: block; margin-top: 0.8rem; }
input, select, button, textarea { font: inherit; width: 100%; box-sizing: border-box; }
button { width: auto; margin-top: 1rem; }
pre { white-space: pre-wrap; background: #f4f4f4; padding: 0.8rem; }
code { font-family: ui-monospace, monospace; }
</style>
</head>
<body>
<h1>Verae timestamping MCP sample</h1>
<p>This page calls a <strong>Model Context Protocol</strong> (MCP) server. The three letters are MCP. The server name is <code>verae-timestamping</code>. It stamps a SHA-256 digest. It does not upload a file.</p>
<p>Start the server on this machine, then submit. A page on the public internet cannot reach <code>127.0.0.1</code>.</p>
<pre>VERAE_MCP_CORS=1 VERAE_MCP_TRANSPORT=streamable-http uv run verae-mcp-timestamping-server</pre>
<form id="stamp-form">
<label>Server URL <input id="url" value="http://127.0.0.1:8000/mcp"></label>
<label>SHA-256 <input id="sha" value="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" spellcheck="false"></label>
<label>Scope
<select id="scope">
<option>local</option>
<option>shared</option>
<option>global</option>
</select>
</label>
<label>Tool
<select id="tool">
<option value="stamp">stamp</option>
<option value="verify">verify</option>
<option value="hash_report">hash_report</option>
</select>
</label>
<label>Receipt id (verify) <input id="receipt" placeholder="from a previous stamp"></label>
<button type="submit">Call tool</button>
</form>
<h2>Result</h2>
<pre id="out">Waiting.</pre>
<p>Docs in this repo: <a href="../docs/html/index.html">HTML</a> · <a href="../docs/pdf/standards.pdf">standards PDF</a></p>
<p>Same files on the public host: <a href="/docs/html/index.html">HTML</a> · <a href="/docs/pdf/standards.pdf">standards PDF</a></p>
<script>
const out = document.getElementById("out");
function rpc(id, method, params) {
return { jsonrpc: "2.0", id, method, params };
}
async function post(url, body, session) {
const headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream"
};
if (session) headers["Mcp-Session-Id"] = session;
const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
const text = await res.text();
const sessionId = res.headers.get("mcp-session-id") || session;
let parsed = text;
try { parsed = JSON.parse(text); } catch (e) { /* SSE or plain text */ }
if (!res.ok) throw new Error(res.status + " " + text);
return { parsed, sessionId };
}
document.getElementById("stamp-form").addEventListener("submit", async (ev) => {
ev.preventDefault();
const url = document.getElementById("url").value.trim();
const tool = document.getElementById("tool").value;
const sha = document.getElementById("sha").value.trim();
const scope = document.getElementById("scope").value;
const receipt = document.getElementById("receipt").value.trim();
out.textContent = "Calling " + url + " …";
try {
const init = await post(url, rpc(1, "initialize", {
protocolVersion: "2025-03-26",
capabilities: {},
clientInfo: { name: "verae-mcp-sample-page", version: "0.1.0" }
}));
await post(url, { jsonrpc: "2.0", method: "notifications/initialized" }, init.sessionId);
let args;
if (tool === "verify") args = { receipt_id: receipt, want_scope: scope };
else if (tool === "hash_report") args = { sha256: sha, want_scope: scope };
else args = { sha256: sha, scope };
const call = await post(url, rpc(2, "tools/call", { name: tool, arguments: args }), init.sessionId);
out.textContent = JSON.stringify({ initialize: init.parsed, call: call.parsed }, null, 2);
} catch (err) {
out.textContent = String(err) + "\n\nIf this page is not on the same machine as the server, the browser will block the call.";
}
});
</script>
</body>
</html>