Proof of Delegation · how it works

Four things, one name.

Search a well-known product on an app registry and several listings answer to its name. Some may be the company’s; most are other people’s; the listing itself cannot say which is which. Proof of Delegation is the missing piece of paper — a note the company signs, and four questions anyone can ask of it.

registry search: proof.holdings — example4 results
@proof-holdings/mcp-serverby proof.holdings
proof-holdings-mcpby prooff.holdings
proof-mcp-serverby pr00f.holdings
proof-holdings-officialby proof-hodlings.io

Which one does the company stand behind? The listing has nowhere to say it.

one of these is our real package — the look-alikes are invented for this page

The note

The missing piece of paper

The controller of a domain proves that control to the issuer. The issuer writes out a stamped note — this artifact acts for the company, for these capabilities, until this date — and the company can cancel it any day. On the note, the company is the principal; the thing it stands behind is the delegate. Ours looks like this:

who wrote it · principal

The company, named by its domain. The one line a reader should always look at.

who it’s about · delegate

Exactly one artifact, typed and named in full — never a family of things.

until when · iat → exp

The note runs out on its own, and can be cancelled sooner.

what it covers · scope

The capabilities the company put in writing — nothing outside them is being claimed.

Proofproof.holdings · delegation
DelegationNº 2026-0117
principalproof.holdings
delegatepkg:npm/@proof-holdings/mcp-server
scopeproof-verification
issued14 Aug 2026 · expires 14 Aug 2027

revocable anytime — the domain proof stays valid

End to end

The whole trip, in five lines

Everything below is one of these five lines, enlarged.

proveThe company shows it controls its domain — once.
stampThe issuer writes the note: this domain stands behind this one artifact.
travelThe note rides the artifact’s own card, or a one-line DNS record points to where it lives.
readWhoever finds it checks the paper against the domain they expected — no network needed.
askThe issuer answers the one question paper can’t: does it still count today?

Different delegations

One grammar, three kinds of thing

The delegate is typed — an https URL or a package URL — so a note points at exactly one thing. Three notes, identical grammar, three different things to stand behind:

An MCP server
principalproof.holdings
delegatepkg:npm/@proof-holdings/mcp-server
scopeproof-verification
A live agent endpoint
principalteam.management
delegatehttps://team.management/mcp
scoperun-protocols
A Python package
principalproof.holdings
delegatepkg:pypi/proof-sdk
scopeproof-verification

Same stamp, same four questions — only the principal, delegate and scope rows change, and each note is cancellable on its own without touching the domain proof or any sibling note. Both domains here are our own. The first of these notes — the MCP server’s — is the one we are about to write; until a note is issued, it is an illustration, not a record.

The four questions

What anyone can ask

Whoever finds the note — a gateway, a registry, you — can ask four questions of it. None of them is “is this artifact good.” Four smaller ones, each with a yes-or-no answer.

Is the stamp real?

Checked against stamps you chose to trust — the reference verifier ships with an empty trust list, and the note does not get a vote.

needs — the issuer’s published keys · fetched once, cached

Is it from the company you mean?

Read who wrote it. A perfect note from a look-alike name is caught here and only here — by reading it against the domain you expected.

needs — the note + your intent · no network

Is it about this artifact?

The note names one delegate, and the check compares it against the artifact you actually resolved — never against what the note says about itself. A mismatch has a name: delegate_mismatch.

needs — the note + what you fetched · no network

Does it still count today?

The note cannot say — it can be cancelled any day. The issuer is asked, over the published status list and the status endpoint, and silence is a refusal, not a pass.

needs — the issuer · asked every time

and when there is no note at all

Silence is not a verdict either. It means the domain has not spoken for this artifact — so the honest answer is “no note,” never “bad.”

The copy attack

A real note, in the wrong hands

A published note is data, and data can be photocopied into a different listing with its stamp intact — nothing on it was altered. Question 3 is built for this exact move: the check refuses to run unless you supply the artifact you resolved yourself. Run the same four questions twice and watch where the copy fails:

on the listing the note names
note sayspkg:npm/@proof-holdings/mcp-server
you resolvedpkg:npm/@proof-holdings/mcp-server
stampreal — checked against keys you chose to trust
principalproof.holdings · the domain you expected
delegatenames exactly what you resolved
todaythe issuer answers: it still counts

proof.holdings

the honest rendering — the domain, a door, never a checkmark

on a photocopy — a different listing
note sayspkg:npm/@proof-holdings/mcp-server
you resolvedpkg:npm/@example/mcp-serverinvented for this page
stampstill real — copying does not break a signature
principalproof.holdings · the domain you expected
delegatenot what you resolved
todaynever asked — the check stopped at 3
delegate_mismatch

a named failure, before a single network call

The reverse move exists too: any domain owner can sign a genuine note naming someone else’s artifact — the issuer checked their domain, not the artifact’s parentage. That is why a check is only meaningful against the domain you expected: pinned, a note minted by the wrong party fails at question 2; unpinned, the result honestly reads “this domain says so,” and nothing more.

Liveness

The question the note can’t answer about itself

Anyone can check the stamp without asking us. Nobody can check the note still counts without asking.

That is the design, not a limitation. A note that promised “valid forever” could never be taken back — the cancel switch has to live outside the note, with the issuer.

So the check asks twice: a signed status list — fetched whole, so the issuer never learns which note you cared about — and the issuer’s status endpoint, which alone sees the domain proof a note rests on. A no from either is final, and if neither can answer, the check fails closed: unavailable is not the same as valid.

asked while the note stands
status listno cancellation listed
endpointconfirms it

counts today

asked after the company cancels
status listrevoked
endpointnot needed — one no is final

no

asked while the issuer is unreachable
status listno answer
endpointno answer

fails closed — unavailable is not valid

The rendering

Show the domain, not a checkmark

principalproof.holdings
principalprooff.holdingsinvented for this page

Either name can carry a perfectly stamped note — all four questions can answer yes for both. What tells them apart is a person reading the principal against the domain they expected. A checkmark would cover exactly the part that matters, so the honest rendering is the domain itself — a door to the principal’s public profile, never a verdict.

In code

Writing one, in code

One call stands between a proven domain and a published note. Everything else in the surface exists to list them, read one back, and cancel it.

the writejs sdk
import { Proof } from '@proof-holdings/sdk';

const proof = new Proof('pk_live_...');

const delegation = await proof.delegations.create({
  control_proof: 'ph_ctl_...',                  // the domain you proved
  delegate: { type: 'purl', value: 'pkg:npm/@proof-holdings/mcp-server' },
  // or a live endpoint: { type: 'url', value: 'https://team.management/mcp' }
  scope: ['proof-verification'],                // capability tokens, kebab-case
});

console.log(delegation.token);                  // publish this on the artifact
writePOST/api/v1/delegations

Issue a delegation over a url/purl artifact (mints the token)

listGET/api/v1/delegations

List delegations

readGET/api/v1/delegations/:id

Get a delegation incl. its token

cancelPOST/api/v1/delegations/:id/revoke

Revoke a delegation

The token comes back once, on the write. Publish it on the artifact’s own card, or point a one-line DNS record at where it lives.

Withdrawing a delegation is instant. Delivering that withdrawal is not.

Every published route to a revocation — the status lookup, the revocation list, the status list — reaches a verifier who asks. Plenty of callers never ask, and nothing you do at revocation time changes that.

The path that does not depend on the caller is the artifact refusing itself. Install @proof-holdings/delegation-self-refusal in your own MCP server and it checks its delegation on a schedule: once you revoke, every tool call it serves refuses on its own, whether or not anyone was checking.

Fine print

  • The paper questions run before any network call, so a note that fails on them costs zero requests — and the signature algorithm is chosen by the verifier, never read from the note.
  • Read a failure as “this did not verify,” never as evidence about who tried: claims are checked before signatures, so a forged note can be made to produce any failure it likes.
  • A note travels on the artifact’s own card, or a one-line DNS record at the domain points to where it lives — the record carries an address, never the note itself.

Start with the domain you already stand behind. Prove it once, then write a note for each thing that acts under your name — and cancel any of them, any day, on its own.