Skip to content
1-hour integration

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.

json — tool result _meta
{
  "_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.

shell
npx -y @peac/mcp-server --help

Verify independently

A consumer extracts the JWS, confirms receipt_ref == sha256(jws), and verifies the signature against the issuer JWKS. Tampering fails closed.

shell
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.

typescript — replay guard
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.

typescript — correlation
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.