Rightshold™ Sign up

Evidence Delivery · $99 / 30 days · Offers open November 18, 2026 · online purchasing currently unavailable

For MCP servers

Notarized tool calls

When your product is an MCP server, your customers' agents change real records through your tools. Give every tool result a receipt they can check without trusting your logs, and without trusting ours.

How it works

  1. Your server hashes the call. The tool name, the arguments it received, the result it returned and a fresh random salt, as canonical JSON, then SHA-256. Arguments and results never leave your server.
  2. Rightshold signs the digest. POST /v1/tool-calls with your account key returns a receipt signed with the issuer key published at /.well-known/jwks.json, committed to the public ledger.
  3. The result carries the receipt. The tool result gains _meta["com.rightshold/tool-call"]. The caller recomputes the digest from what it sent and received, and checks the signature and the ledger entry.

Add it to your server

// npm install @modelcontextprotocol/sdk ; curl -O https://www.rightshold.com/sdks/rightshold-mcp-notary.cjs
const { McpServer } = require("@modelcontextprotocol/sdk/server/mcp.js");
const { z } = require("zod");
const { notarize } = require("./rightshold-mcp-notary.cjs");

const server = new McpServer({ name: "acme-hr", version: "1.0.0" });
notarize(server, { server: "acme-hr" });   // reads RIGHTSHOLD_API_KEY

server.registerTool("update_salary", { inputSchema: { employee_id: z.string(), amount: z.number() } },
  async (args) => ({ content: [{ type: "text", text: "Salary updated" }] }));
// Every result from this tool now carries a receipt in _meta.

Download the notary module (one file, Node 18+, no dependencies). Without an API key it does nothing. If Rightshold is slow or unreachable, your tool still returns its result, without a receipt.

What the caller receives

"_meta": {
  "com.rightshold/tool-call": {
    "spec": "rs-tool-call/1",
    "id": "tc_…",
    "server": "acme-hr",
    "tool": "update_salary",
    "arguments": { "employee_id": "e-17", "amount": 98000 },
    "salt": "…",
    "call_sha256": "…",
    "receipt_url": "https://www.rightshold.com/v1/tool-calls/tc_…",
    "verify_url": "https://www.rightshold.com/v1/tool-calls/verify"
  }
}

How your customers check it

In code, offline signature check plus the ledger:

const { verifyToolResult } = require("./rightshold-mcp-notary.cjs");
const check = await verifyToolResult(result);   // the CallToolResult your client received
// { valid: true, matches_call: true, id: "tc_…", ledger: { seq, recorded_at }, reasons: [] }

From an agent: the verify_tool_call MCP tool (free, no key) recomputes the digest for models that cannot hash. Over HTTP:

curl -s https://www.rightshold.com/v1/tool-calls/verify -H 'content-type: application/json' \
  -d '{"id": "tc_…", "record": {"tool": "update_salary", "arguments": {"employee_id": "e-17", "amount": 98000}, "result": {"content": [{"type": "text", "text": "…"}]}, "salt": "…"}}'

The record sent to verify is hashed in memory and never stored.

What a receipt proves

The server presented this exact call record (tool, arguments and result, bound by SHA-256) for notarization at issued_at, and the record has not changed since.

It does not prove: That the tool's work was correct, that the server's own systems changed as the result says, or who operates the server.

Privacy and cost

For implementers

The exact record format, canonical JSON rules and endpoints: GET /v1/tool-calls. Any language that can sort JSON keys and compute SHA-256 and Ed25519 can verify a receipt.