Add records to an MCP tool.
When an MCP tool runs, attach a signed PEAC record to the response. Anyone can later verify what the tool did and when, across the boundary, without access to your internal logs.
Carry the record in MCP _meta
PEAC carries a compact JWS plus its reference in transport-neutral metadata keys.
{
"_meta": {
"org.peacprotocol/receipt_jws": "<compact-JWS>",
"org.peacprotocol/receipt_ref": "sha256:<digest-of-jws>"
}
}The carrier key remains receipt_jws for compatibility. It carries a signed PEAC interaction record.
Run the PEAC MCP server
The reference MCP server can verify, inspect, decode, issue, and bundle records.
npx -y @peac/mcp-server --helpVerify independently
A consumer extracts the JWS, confirms receipt_ref == sha256(jws), and verifies the signature against the issuer JWKS. Tampering fails closed.
peac verify <record.jws> --public-key <issuer-jwks.json>Detect replays with createReplayGuard
For online consumers: compose createReplayGuard from @peac/protocol after a successful verifyLocal() to classify records as fresh, replayed, or outside-window. Bounded by maxEntries and TTL.
import { createReplayGuard } from '@peac/protocol';
// create once per server instance
const guard = createReplayGuard({
windowSeconds: 300, // accept records issued in the past 5 minutes
maxClockSkewSeconds: 30, // allow 30s drift
maxEntries: 100_000, // insertion-order cap (not LRU)
});
// per request, after verifyLocal() passes:
const verdict = guard.check({ iss, jti, iat });
// 'fresh' | 'replayed' | 'outside-window'
if (verdict !== 'fresh') {
return { error: `rejected: ${verdict}` };
}Not wired into the stateless verifyLocal() path — compose it only when you need online replay protection.
Carry trace context alongside the record
Use @peac/telemetry-otel to carry W3C Trace Context into the record via the org.peacprotocol/correlation extension. Span attributes (peac.receipt.ref, peac.valid) flow back into your existing OTel backend.
import { extractTraceparentFromHeaders, parseTraceparent } from '@peac/telemetry-otel';
const tp = extractTraceparentFromHeaders(headers);
const parts = tp ? parseTraceparent(tp) : undefined;
const record = await issue({
iss: 'https://service.example.com',
kind: 'evidence',
type: 'org.peacprotocol/payment',
pillars: ['commerce'],
extensions: {
'org.peacprotocol/correlation': {
...(parts ? { trace_id: parts.traceId, span_id: parts.parentId } : {}),
workflow_id: 'order-4821',
},
},
privateKey, kid: 'key-2026-01',
});Working examples and guides
The repository ships runnable MCP examples (tool-call records, gateway records with policy decisions and content digests), an integration-patterns guide, and the full API reference.