Signed capability labels · Ed25519
Capability labels
InterfaceDelta is an independent record of what agent services expose and when that changed. When enabled, it issues signed capability labels: versioned statements of observed facts about one service. When a later observation finds a breaking change, the label is withdrawn. Only a later observation classified unchanged, non-breaking or informational can reopen it. This page explains what a label says, what it does not say, and how to check that a label is genuine.
1. What a label is
A label states facts observed at one named time about one exact origin, meaning a scheme and hostname. The origin is a technical anchor. It is not a claim about who runs the service. Each label lists:
- Protocols. Which of MCP, A2A, ARD, OpenAPI, Server Card and WebMCP were observed, each with its status and the protocol revision seen.
- Tool counts. How many tools were observed per protocol, excluding MCP resources and prompts, and how many inventories were incomplete.
- AI readings by effect. For some capabilities, a reading of the primary effect: reads, creates, changes, deletes, sends a message, moves money, runs code, or calls another service. The label aggregates qualifying reading counts; individual probabilities are not included.
- Declared versus observed. Where a publisher's own declarations, such as a read-only hint, disagree with the reading, the label shows both as facts.
- Description facts. Counts from fixed pattern checks on tool names, descriptions and input schemas, with where each pattern occurred. Publisher text itself is not republished.
- Sign-in schemes. The allowlisted sign-in scheme types declared by the service; these are declarations, not proof that authentication works.
- Revision and last change. The observation time, a fingerprint of the normalized facts, and the change class against the previous observation.
Calibration. A reading counts only when three things hold. The model that produced it must be the model named in that check's calibration record. The kind of service must be one of that record's calibrated populations. The probability must clear a fixed threshold chosen on a held-out set of cases where the right answer is known. Readings from uncalibrated models or populations stay in shadow and appear in no label. Only calibrated readings count because only they come with a measured error rate. An uncalibrated model output is a guess, and a label states facts.
2. What a label is not
- Not a certification. InterfaceDelta observes. It does not approve.
- Not a security assessment. A label makes no statement about whether a service is safe to use, and it never claims to find or exclude vulnerabilities.
- Not an endorsement. A listed service is not recommended by us.
- Not a score. There are no grades, rankings, quality percentages, or "unsafe" labels, by policy.
Why no scores: a score would compress observations that differ in kind, such as a removed tool, a changed schema, or a new sign-in requirement, into one number. That would imply a standard we do not measure against. Our checks produce findings and counts, deliberately not a score. Two services with the same fingerprint can still behave differently, because a fingerprint says only that the observed structure is the same.
3. When a label is withdrawn and reissued
"Breaking" has a narrow meaning here: a change that can break a program built against the previously observed interface. The rule catalog classifies every change:
- Breaking. A capability disappears from a complete inventory; an endpoint disappears; an endpoint that answered without sign-in now requires sign-in or payment; an optional input becomes required.
- Non-breaking. A new capability or protocol appears; a formerly sign-in-required endpoint becomes publicly observable.
- Indeterminate. The inventory was incomplete, the server was unreachable, or only a schema hash changed. Indeterminate means no claim, not breaking.
Two short examples. First: a service listed a tool named translate, and a later complete inventory no longer contains it. That is breaking: the old label is withdrawn; a later qualifying observation is required to issue a current label. Second: a previously public endpoint starts answering HTTP 401 and now requires sign-in. That is breaking for callers that used it without signing in, and the old label is withdrawn the same way. When evidence is missing, such as a failed observation or a truncated inventory, InterfaceDelta suppresses the claim rather than guessing.
Disputes and removal also withdraw a label. A publisher who disputes a fact, or asks for removal, can have the entry removed from InterfaceDelta's pages. A verified report can lead to removal, a fix to the methodology, or a note. Observations themselves are never edited.
4. How to verify a label
Each label is a small JSON document. Verification:
- The JSON is canonical: object keys are sorted in a fixed order, so the same facts always produce the same bytes.
- The SHA-256 digest of those bytes identifies the label's content.
- InterfaceDelta signs the canonical document using a detached compact Ed25519 / EdDSA JWS. Its signing input is the protected header, a dot, and the base64url-encoded canonical document. The fingerprint is a separate digest.
- The matching public keys are published at /.well-known/interfacedelta-label-keys.json on InterfaceDelta's domain.
To verify a label, canonicalize it, hash it, and check the signature against a published key. Success proves the label is exactly the document InterfaceDelta signed and that nothing in it has changed since. It proves where the label came from. It proves nothing about the service the label describes.
The snippet uses the repository’s RFC 8785 canonicalJson helper from packages/common/src/canonical-json.ts. Outside the workspace, use an RFC 8785 implementation such as canonicalize in its place. Pin the intended issuer, target and expected origin, and apply your own freshness limit to observedAt. A retained signature remains valid after withdrawal: fetch the latest JSON. Archive public keys before rotation; the live JWKS publishes the active key.
// Node 22+, from the InterfaceDelta workspace.
import { canonicalJson } from '@ai-plumbing/common';
import { createHash, createPublicKey, verify } from 'node:crypto';
const issuer = 'https://interfacedelta.com'; // Pin the issuer you intend to trust.
const targetKey = 'sha256:REPLACE_WITH_TARGET_KEY';
const response = await fetch(issuer + '/labels/' + encodeURIComponent(targetKey) + '.json', { cache: 'no-store' });
if (!response.ok) throw new Error('Label unavailable');
const { label, fingerprint, signature } = await response.json();
const keysResponse = await fetch(issuer + '/.well-known/interfacedelta-label-keys.json');
if (!keysResponse.ok) throw new Error('Keys unavailable');
const { keys } = await keysResponse.json();
const parts = signature.split('.');
if (parts.length !== 3 || parts[1] !== '') throw new Error('Not a detached JWS');
const [protectedHeader, , sig] = parts;
const header = JSON.parse(Buffer.from(protectedHeader, 'base64url'));
if (header.alg !== 'EdDSA' || header.typ !== 'interfacedelta-label+jws' || Object.keys(header).sort().join(',') !== 'alg,kid,typ')
throw new Error('Unsupported header');
const matches = keys.filter(k => k.kid === header.kid && k.kty === 'OKP' && k.crv === 'Ed25519' && k.alg === 'EdDSA');
if (matches.length !== 1) throw new Error('Unknown or ambiguous key');
const bytes = Buffer.from(canonicalJson(label));
const key = createPublicKey({ key: matches[0], format: 'jwk' });
if (!verify(null, Buffer.from(protectedHeader + '.' + bytes.toString('base64url')), key, Buffer.from(sig, 'base64url')))
throw new Error('Invalid signature');
if (createHash('sha256').update(bytes).digest('hex') !== fingerprint)
throw new Error('Fingerprint mismatch');
if (label.version !== 'interfacedelta-capability-label-v1' || label.subject.targetKey !== targetKey)
throw new Error('Wrong version or subject');
if (label.status !== 'current') throw new Error('Label withdrawn: ' + label.reason);
console.log(label);5. For publishers
- Verify ownership. You can prove control of your hostname with a DNS TXT record or a well-known file. Verification enables replies and disputes on your service record; it does not add an ownership claim to the signed label. It is a fact about control of the domain, not a recommendation.
- Embed the badge. Once ownership is verified, you can embed a badge that links to your service's label record.
- Reply to a fact. Declarations such as the read-only and destructive hints are yours to set. Where a declaration disagrees with a reading, the label shows both, because either side can be the wrong one.
- Dispute. Submit a fact dispute from the verified publisher page. An operator reviews it; an upheld dispute withdraws the label with PUBLISHER_DISPUTE. Rejection leaves the label unchanged.
- Ask for removal. Email support to suppress your hostname. Suppression stops collection and removes the entry from InterfaceDelta's pages. Removal is not deletion: retained evidence stays append-only.
6. Limits, honestly
- We see only public metadata. Observation is passive: public protocol surfaces and declared catalogs and endpoints that are reachable without credentials. What sits behind sign-in or payment is out of view.
- Behavior changes behind an unchanged schema are invisible. If the interface stays identical and the behavior changes, we record no change.
- AI readings can be wrong. Calibration bounds the error rate. It does not drive it to zero. The label counts only qualifying readings, and a disagreement with your declaration is shown as a fact, never a verdict.
- Description checks are patterns. They are fixed phrase and character checks reported as counts. They establish that text matched a pattern. They do not establish intent, and they miss phrasings outside the list.
- Coverage is still growing. Discovery sources are partial, and re-observation of one service can be days apart. A label speaks for its observation time, not for today.

