THE RAILS
Define your agent's Entity Card once. KYA-OS projects it onto every discovery rail your agent needs, so the same identity shows up in MCP server.json, A2A agent cards, and NANDA AgentFacts without rewriting anything.
one identity in · one signed proof · every surface out
Write once, project everywhere
Do I have to rewrite my agent's identity for every registry? No. Define the Entity Card once and call one function per rail - the same code path emits every projection, gated by the same proof posture, so updating the card updates all of them. Think of it as a passport: one document, stamped for every border. KYA-OS does not ask existing ecosystems or protocols to migrate: it projects your identity onto them.
The SDK integration
The @kya-os/mcp/card subpath provides the translators: no hand-formatted schemas, no duplicate identity files.
import { toServerCardMeta, toCatalogEntry, toA2AExtension, toAgentFacts, type EntityCard,} from '@kya-os/mcp/card';// 1. Define the Entity Card onceconst card: EntityCard = { id: 'did:web:agents.example.com:my-agent', entityType: 'agent', name: 'my-agent',};// 2. Project it onto each railtoServerCardMeta(card); // server.json _meta blocktoCatalogEntry(card); // catalog.json entry, always by referencetoA2AExtension(card); // A2A AgentCard extensions[] itemtoAgentFacts(card); // NANDA AgentFacts JSON-LD
Claim minimalism
The card asserts identity, type, declared capabilities, and accountability locators. Everything trust-bearing is proven by referenced, signed credentials that the verifier resolves and checks.
- Delegations are out of band. The card carries a
delegationReflocator, never the credentials: the delegation chain travels as separate signed W3C VC 2.0 credentials, and verifiers resolve and evaluate those credentials themselves. - Levels are recomputed. A self-declared
conformanceLevelis never trusted: the verifier recomputes L1, L2, or L3 in-process from the signatures, proofs, and status lists it resolves itself, and the card builder omits the field on emit.
What the card does not carry, in the spec's own words (section 4.2): "A Card ASSERTS only identity + type + declared capabilities + accountability locators." Delegations are not on the card: delegationRef is a locator, and the delegation chain it points at travels as separate signed credentials (W3C VC 2.0) that a verifier resolves and checks (section 10). The trust level is likewise recomputed by the verifier, never self-claimed (section 9): "the Card's self-declared conformanceLevel is NEVER trusted."
Rail by rail
What each projection emits, how its rail carries it, and where it is specified. Every export, key, and URI below is the reference implementation's (src/card/emit.ts); the standards row grounds each rail's status with evidence.
toServerCardMeta -> _meta["org.kya-os/card"] on server.json: an inline claim-minimal summary, or { byRef: true } for an org.kya-os/cardRef pointertoCatalogEntry -> the catalog.json index row, always by-ref_meta extension point, so core MCP is unchangedunaware clients ignore the key; a registry that strips it degrades to a fetch of the canonical card, never a failuretoA2AExtension -> one AgentCard.capabilities.extensions[] item, required: falsehttps://kya-os.org/a2a/ext/entity-card/v1 is its uri; the extension version is pinned in itparams carry the card's id, its cardUrl, and its proofProfile when the card declares onerequired: false: an unaware peer skips the item without rejecting the card; the A2A-Extensions header activates it, per specrule: entityType: 'agent' only; any other type fails closedtoAgentFacts -> an AgentFacts JSON-LD document: id from the card DID, agent_name from its name, owner from responsibleParty (populated, never re-claimed)@context declares kya: as https://kya-os.org/ns/agentfacts/v1#kya:entityType, kya:proofProfile, and kya:delegationRefconforming NANDA parsers preserve unknown keys, so the kya: axes surviveHow the projections resolve
- One source of truth. Every projection references the same canonical
card.jsonon the entity'sdid:webDID document (theKyaOsEntityCardservice entry anchors it), so a verifier always lands back on one card. - Each rail degrades, none fails. A stripped
_metadegrades to a fetch of the canonical card;required: falselets an unaware A2A peer skip the item; conforming NANDA consumers preserve the unknownkya:keys. - The proof is never projected. The per-request holder-of-key proof rides per-request
_metaonly;proofProfilemerely names the profile a verifier should expect, and a strippedproofProfileis not a failure.
how the projections work
Every projection references the same canonical card.json on the entity's did:web DID document (the KyaOsEntityCard service entry anchors it), so a verifier always lands back on one source of truth. The MCP _meta["org.kya-os/card"] value is either an inline summary that carries the identity axes plus the trust-bearing pointers (delegationRef, revocation) or a by-ref org.kya-os/cardRef; the catalog index row is always by-ref so the index stays cheap. The A2A entry is an AgentCard.capabilities.extensions[] item with required: false - that flag is the graceful-degradation contract: an unaware peer ignores it instead of rejecting the card. The NANDA projection is JSON-LD: it populates NANDA's shipped owner slot from responsibleParty (never re-claiming it) and keeps the uniquely-ours axes under the kya: @context namespace, so unknown keys degrade the same way. The per-request holder-of-key proof is never projected - it rides per-request _meta, and a stripped _meta degrades to a fetch, never a failure.