268 lines
13 KiB
HTML
268 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Application Client · Developers</title>
|
|
<meta name="description" content="Non-AI Application Client for Verae timestamps: OpenAPI, Python, TypeScript, curl VeraeTime global, curl MCP local. Digests only.">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,500;9..144,600&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<link rel="icon" href="assets/VeraeFullLogo.png">
|
|
<style>
|
|
:root {
|
|
--ink: oklch(0.21 0.020 310);
|
|
--ink-soft: oklch(0.42 0.018 310);
|
|
--ink-mute: oklch(0.60 0.014 310);
|
|
--paper: oklch(0.992 0.004 90);
|
|
--soft: oklch(0.972 0.008 85);
|
|
--hair: oklch(0.90 0.010 80);
|
|
--purple: oklch(0.32 0.110 310);
|
|
--purple-mid: oklch(0.42 0.130 312);
|
|
--purple-wash: oklch(0.96 0.020 312);
|
|
--gold: oklch(0.80 0.090 85);
|
|
--dark: oklch(0.19 0.022 312);
|
|
--ok: oklch(0.55 0.12 145);
|
|
}
|
|
* { box-sizing: border-box; }
|
|
html { scroll-behavior: smooth; }
|
|
body {
|
|
margin: 0;
|
|
font-family: Inter, -apple-system, BlinkMacSystemFont, sans-serif;
|
|
color: var(--ink);
|
|
background: var(--paper);
|
|
line-height: 1.55;
|
|
}
|
|
a { color: var(--purple); }
|
|
header {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
max-width: 1100px; margin: 0 auto; padding: 28px 28px 0; flex-wrap: wrap; gap: 12px;
|
|
}
|
|
.brand img { height: 46px; width: auto; display: block; }
|
|
nav { display: flex; gap: 22px; font-size: 14px; font-weight: 600; flex-wrap: wrap; }
|
|
nav a { color: var(--ink-soft); text-decoration: none; }
|
|
nav a:hover, nav a.active { color: var(--purple); }
|
|
.hero { max-width: 1100px; margin: 0 auto; padding: 48px 28px 12px; }
|
|
.eyebrow {
|
|
font-size: 13px; font-weight: 700; letter-spacing: 0.14em;
|
|
text-transform: uppercase; color: var(--purple-mid);
|
|
}
|
|
h1 {
|
|
font-family: Fraunces, Georgia, serif; font-weight: 560;
|
|
font-size: clamp(34px, 5vw, 56px); line-height: 1.08;
|
|
letter-spacing: -0.03em; margin: 12px 0 18px; max-width: 22ch;
|
|
}
|
|
.lede { max-width: 46rem; font-size: 18px; color: var(--ink-soft); margin: 0; }
|
|
.gold { height: 3px; width: 72px; background: var(--gold); border: 0; margin: 28px 0; }
|
|
.wrap { max-width: 1100px; margin: 0 auto; padding: 12px 28px 80px; }
|
|
h2.section {
|
|
font-family: Fraunces, Georgia, serif; font-size: 30px; font-weight: 560; margin: 48px 0 8px;
|
|
}
|
|
.section-note { color: var(--ink-soft); max-width: 48rem; margin-top: 0; }
|
|
.card {
|
|
background: white; border: 1px solid var(--hair); border-radius: 16px; padding: 22px; margin-top: 18px;
|
|
}
|
|
.card.featured {
|
|
border-color: color-mix(in oklch, var(--purple) 35%, var(--hair));
|
|
background: linear-gradient(180deg, var(--purple-wash), white 48%);
|
|
}
|
|
.btn-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 14px; }
|
|
.btn {
|
|
display: inline-flex; align-items: center; gap: 8px;
|
|
background: var(--purple); color: white; text-decoration: none; border: 0;
|
|
border-radius: 999px; padding: 12px 18px; font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
|
|
}
|
|
.btn.secondary { background: white; color: var(--purple); border: 1px solid var(--hair); }
|
|
.meta { font-size: 13px; color: var(--ink-mute); margin-top: 12px; }
|
|
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.92em; }
|
|
.path { background: var(--purple-wash); padding: 2px 6px; border-radius: 6px; }
|
|
pre {
|
|
background: var(--dark); color: oklch(0.95 0.01 90); border-radius: 14px;
|
|
padding: 16px 18px; overflow: auto;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; line-height: 1.5; margin: 12px 0 0;
|
|
}
|
|
table.split {
|
|
width: 100%; border-collapse: collapse; margin-top: 16px; font-size: 14px;
|
|
}
|
|
table.split th, table.split td {
|
|
text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--hair); vertical-align: top;
|
|
}
|
|
table.split th {
|
|
color: var(--ink-mute); font-weight: 600; font-size: 12px;
|
|
text-transform: uppercase; letter-spacing: 0.06em;
|
|
}
|
|
footer {
|
|
border-top: 1px solid var(--hair); padding: 28px; color: var(--ink-mute); font-size: 14px;
|
|
}
|
|
footer .inner { max-width: 1100px; margin: 0 auto; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
|
|
@media (max-width: 800px) {
|
|
nav { gap: 14px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<header>
|
|
<a class="brand" href="https://www.verae.com/"><img src="assets/VeraeFullLogo.png" alt="Verae"></a>
|
|
<nav>
|
|
<a href="index.html">Install</a>
|
|
<a href="ways.html">Ways to use</a>
|
|
<a href="developers.html" class="active">Developers</a>
|
|
<a href="sample.html">Sample</a>
|
|
<a href="hasher.html">Hasher</a>
|
|
</nav>
|
|
</header>
|
|
<main>
|
|
<section class="hero">
|
|
<p class="eyebrow">Application Client · OpenAPI</p>
|
|
<h1>Build without an AI host</h1>
|
|
<p class="lede">Stamp, verify, and look up digests from Python, TypeScript, or raw HTTP. Paths in the OpenAPI file are <strong>logical SDK operations</strong> — not deployed REST routes on this host. File bytes never leave the client; only SHA-256 digests are sent.</p>
|
|
<hr class="gold">
|
|
</section>
|
|
<div class="wrap">
|
|
<section id="overview">
|
|
<h2 class="section">Overview</h2>
|
|
<p class="section-note">The Application Client routes by scope: <code>global</code> hits VeraeTime directly; <code>local</code> / <code>shared</code> use MCP Streamable HTTP at <code>/mcp</code>. SDKs refuse content-byte argument names (<code>content</code>, <code>bytes</code>, <code>file</code>, <code>data</code>, <code>path</code>, <code>body</code>, <code>payload</code>, <code>blob</code>, <code>archive</code>).</p>
|
|
<div class="card featured">
|
|
<p style="margin:0;color:var(--ink-soft);font-size:15px">Defaults: MCP <code>https://mcp.verae.ai/mcp</code> · VeraeTime <code>https://api.veraetime.net</code>. Global stamp sends <code>restamp: false</code> (reuse an existing certificate when present).</p>
|
|
<div class="btn-row">
|
|
<a class="btn" href="openapi/application-client.yaml">OpenAPI YAML</a>
|
|
<a class="btn secondary" href="ways.html">Ways to use hub</a>
|
|
<a class="btn secondary" href="sample.html">Browser MCP sample</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section id="transport">
|
|
<h2 class="section">Transport split</h2>
|
|
<p class="section-note">One Application API surface; two backends. Auth ops always use VeraeTime with a caller-held JWT.</p>
|
|
<table class="split">
|
|
<thead>
|
|
<tr>
|
|
<th>Operation</th>
|
|
<th>local / shared</th>
|
|
<th>global</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><code>stamp</code></td>
|
|
<td>MCP tool <code>stamp</code></td>
|
|
<td>VeraeTime <code>POST /api/timestamp</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>verify</code></td>
|
|
<td>MCP tool <code>verify</code></td>
|
|
<td>VeraeTime <code>POST /api/verify</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td><code>hash_report</code></td>
|
|
<td>MCP tool <code>hash_report</code></td>
|
|
<td>VeraeTime <code>GET /api/hash/{sha256}</code></td>
|
|
</tr>
|
|
<tr>
|
|
<td>signup / login / session / create_user</td>
|
|
<td colspan="2">VeraeTime <code>/auth/*</code> (direct; apps do not rely on MCP account tools)</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="openapi">
|
|
<h2 class="section">OpenAPI</h2>
|
|
<p class="section-note">Normative digests-only contract for the Application Client SDKs (OpenAPI 3.1). Download or fetch from this site:</p>
|
|
<pre>https://mcp.verae.ai/openapi/application-client.yaml</pre>
|
|
<div class="btn-row">
|
|
<a class="btn" href="openapi/application-client.yaml">application-client.yaml</a>
|
|
</div>
|
|
<p class="meta">Logical paths such as <code>/stamp</code> document SDK methods; they are not HTTP routes on <code>mcp.verae.ai</code> in this phase.</p>
|
|
</section>
|
|
|
|
<section id="python">
|
|
<h2 class="section">Python</h2>
|
|
<p class="section-note">Package <code>verae-mcp-timestamping-client</code> — <code>ApplicationClient</code> routes by scope.</p>
|
|
<pre>import asyncio
|
|
from verae_mcp_timestamping_client import ApplicationClient
|
|
|
|
async def main():
|
|
client = ApplicationClient()
|
|
print(await client.stamp("<64-hex>", scope="global"))
|
|
print(await client.stamp("<64-hex>", scope="local"))
|
|
|
|
asyncio.run(main())</pre>
|
|
<p class="meta">Install: <code>uv add verae-mcp-timestamping-client</code> or <code>pip install verae-mcp-timestamping-client</code>.</p>
|
|
</section>
|
|
|
|
<section id="typescript">
|
|
<h2 class="section">TypeScript</h2>
|
|
<p class="section-note">Package <code>@verae/timestamping-client</code>. Method names are camelCase (<code>hashReport</code>); OpenAPI stays snake_case.</p>
|
|
<pre>import { ApplicationClient } from "@verae/timestamping-client";
|
|
|
|
const client = new ApplicationClient({ token: process.env.VERAE_GLOBAL_TOKEN });
|
|
|
|
// Global → VeraeTime POST /api/timestamp (restamp: false)
|
|
const global = await client.stamp("a".repeat(64), { scope: "global" });
|
|
|
|
// Local → MCP tools/call stamp
|
|
const local = await client.stamp("a".repeat(64), { scope: "local" });</pre>
|
|
<p class="meta">Install: <code>npm install @verae/timestamping-client</code>.</p>
|
|
</section>
|
|
|
|
<section id="curl-global">
|
|
<h2 class="section">curl · global (VeraeTime)</h2>
|
|
<p class="section-note">Direct HTTPS to <code>api.veraetime.net</code>. Bearer token from env or <span class="path">~/.verae/auth.properties</span>.</p>
|
|
<pre># TOKEN from VERAE_GLOBAL_TOKEN or access_token in ~/.verae/auth.properties
|
|
DIGEST=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
|
|
|
curl -sS -X POST https://api.veraetime.net/api/timestamp \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Accept: application/json' \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-d "{\"data\":\"$DIGEST\",\"digest\":\"$DIGEST\",\"hashAlg\":\"SHA256\",\"restamp\":false}"</pre>
|
|
<p class="meta">On <code>200</code> with <code>certificate</code> / <code>existing</code>, reuse that CID. Otherwise poll <code>GET /api/status/{jobId}</code>.</p>
|
|
</section>
|
|
|
|
<section id="curl-mcp">
|
|
<h2 class="section">curl · MCP local</h2>
|
|
<p class="section-note">Streamable HTTP at <code>/mcp</code>. Capture <code>Mcp-Session-Id</code> from <code>initialize</code>, then <code>notifications/initialized</code>, then <code>tools/call</code>.</p>
|
|
<pre># 1) initialize — note Mcp-Session-Id in response headers
|
|
curl -sS -D - -X POST https://mcp.verae.ai/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Accept: application/json, text/event-stream' \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"dev-curl","version":"1.0.0"}}}'
|
|
|
|
# 2) notifications/initialized (same session)
|
|
curl -sS -X POST https://mcp.verae.ai/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Accept: application/json, text/event-stream' \
|
|
-H 'Mcp-Session-Id: SESSION' \
|
|
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
|
|
|
|
# 3) tools/call stamp (local scope)
|
|
curl -sS -X POST https://mcp.verae.ai/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-H 'Accept: application/json, text/event-stream' \
|
|
-H 'Mcp-Session-Id: SESSION' \
|
|
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"stamp","arguments":{"sha256":"DIGEST_HEX","scope":"local"}}}'</pre>
|
|
</section>
|
|
|
|
<section id="auth">
|
|
<h2 class="section">Auth</h2>
|
|
<p class="section-note">Machine login writes a JWT under <span class="path">~/.verae/auth.properties</span> (mode <code>600</code>). Do not paste tokens into chat or commit the file.</p>
|
|
<div class="card">
|
|
<p style="margin:0 0 8px;color:var(--ink-soft);font-size:15px"><strong>Resolve order</strong> (Application Client / VeraeTime transport): constructor token → <code>VERAE_GLOBAL_TOKEN</code> → <code>access_token</code> / <code>auth_token</code> / <code>id_token</code> in auth.properties (<code>VERAE_AUTH_PROPERTIES</code> overrides the path).</p>
|
|
<pre>uvx verae-mcp-timestamping-server setup
|
|
# writes ~/.verae/auth.properties (mode 600); does not print the token
|
|
uvx verae-mcp-timestamping-server session</pre>
|
|
<p class="meta">Keys typically include <code>access_token</code>, <code>expires_at</code>, and username. Directory <code>~/.verae</code> is mode <code>700</code>.</p>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</main>
|
|
<footer>
|
|
<div class="inner">
|
|
<span>Verae timestamping · <a href="https://www.verae.com/">verae.com</a></span>
|
|
<span><a href="index.html">Install</a> · <a href="ways.html">Ways to use</a> · <a href="developers.html">Developers</a> · <a href="openapi/application-client.yaml">OpenAPI</a> · <a href="sample.html">Sample</a></span>
|
|
</div>
|
|
</footer>
|
|
</body>
|
|
</html>
|