Skip to main content
Glama

notary-mcp

The human approves a hash, not a promise.

An MCP approval gate for agent actions. An agent proposes an action; the server normalizes it to canonical bytes and hashes them into a reviewed revision; a human sees a field-by-field manifest of exactly those bytes and approves that revision — and the agent may then execute only those bytes. Anything drifts by one character, the gate refuses.

Built for Push to Prod: Building at the Frontier (Bengaluru, 8 Aug 2026).

Why

Today, agent approval is a sentence in a chat window: the agent describes what it will do, you say yes, and then it does something — possibly not that thing, because it re-planned, or state moved underneath it, or a prompt injection rewrote its intent. The description you approved and the action that executes are not connected by anything.

notary-mcp makes consent content-addressed:

  • Canonical bytes. Every proposed action is normalized (RFC 8785 JSON canonicalization, NFC Unicode, surrogate rejection, whitespace collapse) so there is exactly one byte representation — nothing to smuggle in formatting.

  • A domain-separated hash of those bytes is the reviewed revision. The human's approval names this hash, not the draft, not the intent.

  • A complete manifest. The review step shows every leaf the hash covers — including values stored but hidden from the public, so approval is never blind.

  • Fail-closed execution. execute_post takes the revision as an argument. Wrong hash, drifted draft, superseded approval, consumed approval: refused. There is no code path from agent input to side effect that skips the human.

  • Idempotency. Operations carry a client operation_id plus a server-computed input fingerprint. Replays return the recorded result; the same id with different input is a terminal conflict. Retries can never double-fire.

The model explains; the hash authorizes. The model never gets to authorize.

Related MCP server: gomission-mcp

Quickstart (zero credentials)

git clone https://github.com/salmanneedsajob/notary-mcp
cd notary-mcp
npm install
npm run prove      # 56 checks — every attack in the table below, refused
npm run demo       # the full loop over a real MCP stdio connection

Connect it to Claude:

claude mcp add notary -- npx tsx /absolute/path/to/notary-mcp/src/main.ts

Then ask Claude to draft a post with propose_post. Approve it yourself — the agent cannot:

npm run review              # list drafts awaiting review
npm run review <draftId>    # see the exact bytes + hash, approve y/N

Only after your approval does execute_post with that exact revision succeed. The published artifact — the approved canonical bytes — lands in out/<slug>.json.

The attack table

Every row is a check in npm run prove, run against the real executor and store:

Attack

Result

Execute before any human approval

APPROVAL_REQUIRED, no side effect

Flip one hex character of the approved revision

STALE_REVISION

Edit the draft after approval, execute the old approved revision

STALE_REVISION — approval names bytes, and those bytes are gone

Execute the drifted bytes without fresh approval

APPROVAL_REQUIRED — every revision needs its own human

Replay a completed operation

Served from the record, replay: true, no second side effect

Reuse an operation_id with different input

OPERATION_ID_CONFLICT, terminal

Publish again with a consumed approval

DRAFT_NOT_EDITABLE, terminal

Prompt injection inside a field ("IGNORE ALL PREVIOUS INSTRUCTIONS…")

It's data. Hashed like everything else. Still needs a human.

Credential (bearer token) in the captured source

PRIVACY_BLOCKED before any draft exists

Unicode smuggling (unpaired surrogates, formatting drift)

Rejected or normalized before hashing

Two posts with identical titles

Distinct permanent slugs — published URLs are never reused

Hidden-from-public field changed after review

Different hash — hidden values are inside the approval boundary

Architecture

agent ──MCP──▶ server.ts ──▶ executor.ts ──▶ ports.ts ──▶ store.ts ──▶ out/
                (contract      (pure           (5-function   (JSON file;
                 boundary)      orchestration)  port)         swap for any DB)
                                    │
                    canonical.ts ───┤  RFC 8785 canonical JSON,
                    review.ts ──────┤  normalization, revision hash,
                    review-manifest ┘  input fingerprint, field manifest

human ──▶ scripts/review.ts  (manifest + y/N → approval of one revision)
  • src/contracts/v1.ts — the versioned tool contract. Strict validation schemas plus permissive transport schemas, so malformed input becomes a structured INVALID_ARGUMENT result instead of a protocol error.

  • src/canonical.ts — canonicalization and the two hash frames (revision + operation fingerprint), both domain-separated and length-prefixed.

  • src/executor.ts — pure orchestration. Every effect flows through the five-function port in src/ports.ts; capability checks, rate ceiling, and retry classification live here.

  • src/store.ts — the standalone port implementation (JSON file). In production this is a set of SECURITY DEFINER Postgres functions; the executor cannot tell the difference, which is the point.

  • The demo action is "publish a post" — the payload schema is an example. The gate pattern (propose → hash → human approves hash → execute exact bytes) applies to any consequential agent action: sending money, merging code, sending email.

Disclosure of prior work

This project comes out of Slopfolio, my invite-only portfolio platform for AI-assisted work, where this mechanism runs in production behind OAuth with a Postgres transactional boundary.

Existed before the hackathon: the underlying capture gateway — the canonicalization scheme, revision-hash and fingerprint framing, the V1 tool contract, the executor orchestration, the review-manifest builder, and the pure-logic checks in prove-contract.ts / prove-executor.ts (lifted from that codebase, renamed).

Built during Push to Prod: the hackathon work spans Slopfolio and this repo. On the Slopfolio side: the agent verification system built on top of the gate, and taking the MCP live for the public. This repo is the third piece — the standalone extraction of the gate mechanism, so it can be run and verified independently of Slopfolio: cutting it free of Supabase/OAuth/Next.js into a product-agnostic gate; the persistence port (ports.ts) and standalone store (store.ts); the stdio server (main.ts); the human review CLI (scripts/review.ts); the end-to-end adversarial gate suite (scripts/prove-gate.ts); and the wire demo (scripts/demo.ts).

License

MIT

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    D
    maintenance
    Human-in-the-Loop authorization gateway for AI Agents. Securely pause MCP workflows and route high-risk actions to human approvers via Slack or Email.
    83
    1
    MIT
  • A
    license
    -
    quality
    C
    maintenance
    Mission MCP is a Trust Graduation gate for AI agents, with visible approval ceremonies and receipt-backed boundaries for consequential actions.
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    Governance circuit-breaker MCP server that enables AI agents to request risk-based decisions, approve or deny actions, and finalize outcomes with full audit receipts.
    4
  • A
    license
    A
    quality
    C
    maintenance
    Enables MCP-capable agents to gate their actions behind human consent, checking consent rules and requesting approval via Telegram before proceeding with high-stakes operations.
    2
    25
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/salmanneedsajob/notary-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server