Build with the local Soterias SDK. Get started with Python and TypeScript.
SoteriasDocsBuild
Core components

Verify a receipt offline

Check the original signature, the host-pinned issuer policy and time. Match the expected operation binding when your application knows it. An authentic historical assertion is not current execution authority.

When to use this

Use this when an auditor or application receives a signed artifact and must check its issuer, time and operation binding offline.

Install the matching API preview

These examples use the API 2 preview, not names promised by the public RC5 release. Existing RC5 entry points remain available. The Python wheel below is verified on Windows x64; it is not a cross-platform release.

shell
python -m pip install https://docs.soterias.io/downloads/api-preview/soterias_local-0.1.0rc5%2Bapi2-cp311-abi3-win_amd64.whl
shell
npm install https://docs.soterias.io/downloads/api-preview/soterias-core-0.1.0-rc.5-api.2.tgz
npm install --save-dev typescript@5.8.3 @types/node@24

Python imports soterias. TypeScript imports @soterias/core. Use Python 3.11+ for this wheel and Node 22.23.4+ for these examples. For a .mts file, compile with npx tsc example.mts --target ES2022 --module NodeNext --moduleResolution NodeNext --skipLibCheck, then run the emitted .mjs file.

Before you run

Set SOTERIAS_RECEIPTS to the public receipt fixture directory containing trust.json, anchor.json, authorization-policy.json, record-0.json and forged-0.json. This teaching capture uses historical time 1300; current receipts normally use the native clock. These public data inputs are distinct from private custody.

Application walkthrough

Choose Python or TypeScript. Create example.py or example.mts and append that language's chunks in order. Each language forms one complete program; indentation and open blocks carry across chunks.

Import the packages

Import the SDK and standard-library helpers. These are the real package exports used by the executable program.

import json
import os
from pathlib import Path
from soterias import audit, VerificationError

Select public trust independently of the receipt

This historical teaching export was evaluated at 1300 milliseconds.

# %% Select public trust independently of the receipt
# This historical teaching export was evaluated at 1300 milliseconds.
root = Path(os.environ["SOTERIAS_RECEIPTS"])
read = lambda name: (root / name).read_bytes()
verifier = audit.Verifier(read("trust.json"), read("anchor.json"),
                          read("authorization-policy.json"))

Verify an original signed receipt offline

This checks the pinned issuer signature and native binding/time rules.

# %% Verify an original signed receipt offline
# This checks the pinned issuer signature and native binding/time rules.
receipt = audit.Receipt(read("record-0.json"))
result = verifier.verify(receipt, at_ms=1300)
assert result.assurance == "pinned_issuer_signature_and_bindings"

Check that a changed signature is refused

Verification authenticates the assertion; it does not grant current permission.

# %% Check that a changed signature is refused
# Verification authenticates the assertion; it does not grant current permission.
try:
    verifier.verify(audit.Receipt(read("forged-0.json")), at_ms=1300)
except VerificationError:
    pass
else:
    raise AssertionError("A changed signature was accepted")
print(json.dumps({"status": "PASS", "verified": 1, "signature_mutations_refused": 1,
                  "expected_binding_checked": result.expected_binding_checked}))

MCP composition

This complete stdio server calls this feature's real SDK operation. Its bounded tool inputs cannot replace host-selected trust, checkpoint or storage paths. Save it as mcp.mjs and configure your MCP client to launch node mcp.mjs. Public data inputs use the same environment settings as the application program. The code is a custom application tool, not a newly claimed built-in Soterias endpoint.

Install the matching adapter with npm install https://docs.soterias.io/downloads/api-preview/soterias-mcp-server-0.1.0-rc.5-api.2.tgz. Its SDK peer dependency shares the same native class identities as your installed preview.

mcp.mjs

Create mcp.mjs and append these chunks in order. Together they form one complete program; indentation carries across chunks.

Step 1

Import the SDK and standard-library helpers. These are the real package exports used by the executable program.

JavaScript
import { Soterias, observe, canonicalize, Metrics, audit, HistoricalPolicyInputs } from '@soterias/core';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { McpServer } from '@modelcontextprotocol/server';
import { serveStdio } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

// Trusted startup: paths, trust and credentials are fixed by the host.
const read = name => fs.readFileSync(path.join(process.env.SOTERIAS_RECEIPTS, name));
const options = {trust: read('trust.json'), anchor: read('anchor.json'), policy: read('authorization-policy.json'), atMs: 1300n};

// Agent input is bounded data. It cannot replace host configuration or trust.
const handle = serveStdio(() => {
  const server = new McpServer({name: 'soterias-receipts', version: '1.0.0'});
  server.registerTool('verify_receipt', {
    description: 'Use receipts through the host-selected native SDK.',
    inputSchema: z.object({receiptJson: z.string().min(1).max(262144)}).strict(),
  }, async input => {
    try {
      const result = await (async () => {
        return audit.verify(Buffer.from(input.receiptJson), options);
      })();
      return {content: [{type: 'text', text: JSON.stringify(result, (_key, value) => typeof value === 'bigint' ? value.toString() : value)}]};

Step 2

Finish outstanding work and release owned resources. Cleanup errors must not silently replace an existing application error.

JavaScript
    } catch {
      return {isError: true, content: [{type: 'text', text: 'feature_request_refused'}]};
    }
  });
  return server;
}, {maxSubscriptions: 0});
process.stdin.once('end', () => {
  void (async () => { await handle.close();  })();
});

Test the tool over a real MCP connection

Save this client next to mcp.mjs, then run node client.mjs. It starts the host, calls the actual feature tool and closes the connection. It does more than list the tool catalog.

client.mjs

Create client.mjs and append these chunks in order. Together they form one complete program; indentation carries across chunks.

Step 1

Import the SDK and standard-library helpers. These are the real package exports used by the executable program.

JavaScript
import fs from 'node:fs';
import path from 'node:path';
import { Client } from '@modelcontextprotocol/client';
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
import { fileURLToPath } from 'node:url';

const client = new Client({name: 'feature-example', version: '1.0.0'});
try {
  await client.connect(new StdioClientTransport({
    command: process.execPath,
    args: [fileURLToPath(new URL('./mcp.mjs', import.meta.url))],
    env: Object.fromEntries(Object.entries(process.env).filter(([, value]) => value !== undefined)),
  }));
  const result = await client.callTool({name: 'verify_receipt', arguments: {receiptJson: fs.readFileSync(path.join(process.env.SOTERIAS_RECEIPTS, 'record-0.json'), 'utf8')}});
  if (result.isError) throw new Error('Feature request refused');
  console.log(JSON.stringify(result));
} finally { await client.close(); }

Check the result

The application program prints a JSON result and preserves native refusals. For protected operations inspect status and target_observed: transport success does not imply a completed effect. The pure examples contain assertions for their exact expected values. Successful startup is not proof of production enrollment, a physical human review or current authority.

Put it into a workflow

Use the AML walkthrough for protected document reads, reviewed writes and signed outcome checks. Use multi-agent workflows for personal and enterprise orchestration. Keep each agent's proposals separate from operator authority.

Search guides, examples and API reference.