| Internet-Draft | MCP DNS Discovery | October 2026 |
| Morrison | Expires 12 April 2027 | [Page] |
This document defines a DNS-based mechanism for discovering Model
Context Protocol (MCP) servers, the identity of the organisations
that operate them, and a cryptographic identity envelope bound to an
individual Sovereign-tier ~handle published under the same zone.¶
Three TXT records are defined. _mcp.<domain> advertises an MCP
server's endpoint URL, agent protocol family, transport binding,
cryptographic identity, and capability profile.
_org-alter.<domain> advertises the operator's canonical
organisational identity, including its legal entity, registry
identifier, regions of operation, and any regulatory framework under
which it must refuse external automated access. _alter.<domain>
publishes an Ed25519-signed envelope binding a ~handle to a public
key, an IdentityLog root reference, and a revocation commitment.
DNSSEC validation is REQUIRED for the envelope record, and a DANE
TLSA pin on the MCP endpoint is REQUIRED where resolving an envelope
and opening an MCP session are one recognition transaction.¶
The mechanism complements HTTPS-based discovery, and follows the
precedent set by DKIM, SPF, DMARC, and MTA-STS. A companion
alter: URI scheme is provisionally registered with IANA.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.¶
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."¶
This Internet-Draft will expire on 12 April 2027.¶
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.¶
Model Context Protocol (MCP) [MCP] is an open protocol for structured interaction between AI agents and tool-providing servers. A complete agent-to-organisation-to-individual interaction chain has three distinct discovery requirements:¶
Service discovery. Where is the MCP server endpoint? What
transport does it speak? What cryptographic key authenticates
it? The _mcp.<domain> record answers this.¶
Organisational identity bootstrap. Who is the organisation
operating the server? What is its legal entity? Where is it
registered? Under what regulatory frameworks does it operate,
and which automated access pathways must it refuse to participate
in? The _org-alter.<domain> record answers this.¶
Individual identity recognition. Who is the Sovereign-tier
person bound to a ~handle hosted under the domain? What public
key signs their statements? What append-only log anchors the
lifecycle of their identity? How may their envelope be revoked?
The _alter.<domain> record answers this.¶
The three questions are distinct. An MCP client may need to
discover an endpoint without caring about the operator's identity
or any individual handle. An onboarding wizard installing an
org-alter instance may need to read the operator's identity without
caring (yet) about the MCP endpoint. A recognition verifier
(resolving an alter:~alice URI) needs the individual envelope
without necessarily invoking an MCP session. Conflating any two of
these into a single TXT record would force every consumer to parse
fields it does not need and would crowd the 255-octet
character-string limit. Splitting them across three
underscore-prefixed labels mirrors the pattern established by DKIM
[RFC6376] (<selector>._domainkey.<domain>) and DMARC [RFC9989]
(_dmarc.<domain>), where each record serves a single semantic
purpose. SPF [RFC7208] and MTA-STS [RFC8461] set the same
precedent for carrying policy in a TXT record under a reserved
label.¶
This revision is fully backward-compatible with revisions 01 and 02.
Implementations that consume only the _mcp.<domain> record
continue to work unchanged. Implementations that wish to bootstrap
an org-alter identity may additionally query _org-alter.<domain>.
Implementations that wish to recognise an individual ~handle may
additionally query _alter.<domain>.¶
This document stands alone. All three record formats (Section 5, Section 6, Section 7), all three procedures (Section 12.1, Section 12.2, Section 12.3), the signing input (Section 7.4) and the caching rules (Section 13) are given here in full. An implementer needs no other document in this series. Revisions 01 and 02 are cited where this document records what they said, and are cited informatively, because nothing here depends on fetching them.¶
The envelope published at _alter.<zone> is the
handle-holder's own declaration, signed by their Ed25519 key and
verifiable by any client with access to a DNSSEC-validating recursive
resolver. It also carries a reference to an IdentityLog root, and
Section 10 sets out what that reference does and does not
establish.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
An Ed25519-signed JSON object binding a ~handle to a public
key, an IdentityLog root reference, an inception timestamp, a
revocation hash commitment, a signature algorithm tag, a detached
signature, and a caveats array. The TXT grammar
that carries the seven required envelope fields across DNS, and
the signing input over which they are verified, are specified in
Section 7 of this document.¶
A Sovereign-tier identifier, leading tilde mandatory (e.g.
~alice). Bot-tier handles carry a .bot suffix (e.g.
~example-bot.bot); Instrument-tier handles use the prefix
~cc- (e.g. ~cc-example-model). An Instrument-tier handle
identifies an instrument whose acts are attributed to the Sovereign
that operates it; it is not an independent handle (Section 8.5 of
[MORRISON-IFT]). After the tilde, a handle begins with a letter
and continues with letters, digits, "-" and "."; it never contains
"_". An organisation's handle may therefore be dotted, as in
~example.com. The grammar is the handle-name of
[ALTER-URI], restated in Section 7.2, and the tier is read from
the lexical form alone. A dotted handle is not a domain name, and
the Handle-Domain Confusion consideration of [ALTER-URI] applies.¶
An append-only transparency log recording envelope lifecycle
events (mint, caveat-add, revocation, key-rotation), whose root
the ilr= field of Section 7 references. The log's
cadence, its witness protocol, and the client profile for
checking it are NOT specified by this document and are not yet
specified anywhere a reader can fetch. Section 10 states what a
resolver may and may not conclude from ilr= in the meantime.¶
The act of a resolver observing and verifying an envelope on cryptographic merit. A published record is an assertion the resolver may verify or reject.¶
The act of an authenticating DNS resolver verifying the RRSIG chain from the root trust anchor to the TXT RRset, per [RFC4033], [RFC4034], and [RFC4035], and setting the AD bit on the response delivered to the stub client.¶
A DNS TLSA resource record [RFC6698] binding a server's leaf TLS
certificate (or the public key therein) to the zone that hosts
the envelope. In this document, the pin applies to the MCP
endpoint at mcp.<zone>.¶
alter: URIA URI scheme for dispatchable ~handle references, specified in [ALTER-URI] and provisionally registered with IANA on 5 October 2026 per [RFC7595] Section 4. Handler guidance is given in Section 11 of this document. Where this document names a ~handle in prose as a reference, it is written as an alter: URI, for example alter:~alice. The h field of Section 7.3.2 carries the bare form its grammar defines, and the value ~alice corresponds to the URI alter:~alice.¶
The terms Org-Identity Record, Identity Bootstrap, Canonical Entity Identifier and Regulatory Refusal Marker carry the meanings given by Section 6 and Section 12.2.¶
[DNS-AID] carries its connectivity data in SVCB records, with TXT as a fallback, and [MDNS-ARCHITECT] uses SVCB. This document is the reverse, TXT is the primary carrier. The reason is the payload.¶
An _mcp record's value is almost entirely opaque tokens the
resolver does not interpret, an endpoint URL, a public key, a
capability list, an attestation scope. SVCB is useful when a
resolver or a connection library acts on the parameters directly,
selecting a transport, following an alpn, choosing a port. It
adds a registered SvcParamKey per field and a priority-ordered
target list. For a record whose fields are consumed by an MCP
client after resolution, and not by the resolver, that machinery is
overhead without a matching benefit, and a TXT string is the
lighter carrier.¶
Where a field IS resolver-actionable, this document defers to SVCB
rather than duplicating it. The wire protocol lives in the SVCB or
HTTPS alpn parameter [RFC9460], never in this TXT record, for that reason. An operator who wants SVCB-based transport
selection publishes an HTTPS record for the endpoint host in the
ordinary way, and the two records coexist.¶
_mcp.<domain> (Service Discovery)
This section defines the Discovery Record introduced in revision 00, in full.¶
The Discovery Record is a DNS TXT resource record [RFC1035]
published at the label _mcp prepended to the Policy Domain:¶
_mcp.<policy-domain>. IN TXT "<record-value>"¶
The underscore prefix conforms to the conventions established in [RFC8552] for globally scoped, underscore-prefixed DNS node names.¶
Multiple TXT resource records MAY be published at the same DNS
name. Where multiple records exist, each MUST independently conform
to the syntax defined in this section. Clients MUST evaluate all
returned records and select among them using the priority field
as described below.¶
The record value is a semicolon-delimited sequence of key-value pairs. The following ABNF [RFC5234] defines the syntax:¶
mcp-record = version *( ";" SP field )
version = "v=mcp1"
field = url-field / proto-field / transport-field /
pk-field / epoch-field / cap-field /
attest-field / scope-field / priority-field /
ttl-field / ext-field / unknown-field
url-field = "url=" https-uri
proto-field = "proto=" proto-value
transport-field = "transport=" transport-value
pk-field = "pk=" algo ":" base64url
epoch-field = "epoch=" 1*DIGIT
cap-field = "cap=" cap-csv
attest-field = "attest=" attest-csv
scope-field = "scope=" scope-csv
priority-field = "priority=" 1*DIGIT
ttl-field = "ttl=" 1*DIGIT
ext-field = "ext=" https-uri
unknown-field = token "=" *qtext
https-uri = "https://" *uri-char
uri-char = %x21-3A / %x3C-7E
; printable ASCII, excluding ";" (%x3B) and SP.
; A URI carries no raw space, so admitting one here
; would let a url= value swallow the field after it.
qtext = %x20-3A / %x3C-7E
; printable ASCII and SP, excluding ";" (%x3B),
; which delimits one field from the next. A value
; that could contain ";" could swallow the delimiter.
algo = "ed25519"
base64url = 1*( ALPHA / DIGIT / "-" / "_" )
proto-value = token
transport-value = token
cap-csv = cap-token *( "," cap-token )
cap-token = token
attest-csv = attest-token *( "," attest-token )
attest-token = token
scope-csv = scope-token *( "," scope-token )
scope-token = "tools" / "resources" / "prompts" /
"sampling" / "identity" / token
token = 1*( ALPHA / DIGIT / "-" / "_" )
¶
unknown-field matches ONLY a field name this document does not
define. ABNF has no way to say "any token except these", so the
exclusion is stated here, and it is normative. Where a field name
IS defined above, the field MUST be parsed by that field's own rule.
A record in which a defined field's value does not satisfy its own
rule is MALFORMED, and a client MUST discard it, exactly as
Section 12.1 discards a record whose url is not a valid HTTPS
URI. A client MUST NOT re-read such a field as an unknown-field.
Without this rule the alternation would swallow every defect it was
written to exclude: url=https://x.com priority=5 would parse as an
unknown field named url rather than as the malformed url field
it is.¶
The grammar admits any token in proto and in transport.
Revision 01 admitted any token in proto and records in the wild
carry transport values there, so a resolver MUST be able to PARSE
such a record before it can decide what to do with it, and the
reading rule of Section 5.3.5 is what decides.¶
The values this document DEFINES are enumerated in the field
definitions below. proto has exactly one
defined value, mcp. transport has exactly three,
streamable-http, sse, and stdio-url. Those two sets are
disjoint, so no value is defined for both fields. A transport value
appearing in proto is RECOGNISED there, under Section 5.3.5,
and is not DEFINED there.¶
Protocol version identifier. MUST be the literal string mcp1.
MUST appear as the first field in the record. Clients MUST reject
any record whose v field is absent, is not the first field, or
contains a value other than mcp1.¶
This version gate enables future incompatible revisions of the
record format. A future version mcp2 would indicate breaking
changes to field semantics or discovery flow.¶
The HTTPS URL of the MCP server endpoint. MUST use the https
scheme. MUST be a syntactically valid URI per RFC 3986. This is
the entry point for MCP session establishment.¶
Clients MUST NOT attempt to connect to URLs using schemes other
than https. Servers MUST present a valid TLS certificate for
the hostname in the URL.¶
The agent protocol family the endpoint speaks. Default value:
mcp. For a record published at _mcp.<domain> the only value
defined by this document is mcp; the field is retained because
the same key, with the same meaning, is used by [MDNS-AGENT]
(see Section 3) and a client that reads
several of them should not have to special-case this one.¶
proto does not name a transport. It does not carry
streamable-http, sse, h2, h3, or any other binding. The
transport is carried by the transport field below. A record
published under revision 01 may still carry a transport value
here, and Section 5.3.5 says how to read one.¶
The field is OPTIONAL, but not unconditionally. A publisher that
emits a transport field MUST also emit proto=mcp, for the
interoperability reason given in Section 5.3.5. Omitting
proto is permitted only where transport is also omitted.¶
The MCP transport binding used by the server. Default value:
streamable-http. Defined values:¶
streamable-http, the HTTP-based streaming transport (default).¶
sse, the HTTP+SSE transport of MCP protocol version 2024-11-05,
retained for deployed servers. The Model Context Protocol
specification marks this transport superseded by
streamable-http. It is listed so an existing server stays
discoverable, not as a recommendation for new deployments.¶
stdio-url, a URL pointing to a signed launch descriptor for a
stdio-based server (descriptor format out of scope). This is a
discovery convenience defined by this document, not one of the MCP
specification's own transport names.¶
The field is named transport because that is the term the Model
Context Protocol specification itself uses for this axis, so an
_mcp record and an MCP client configuration name the transport
the same way.¶
Implementations SHOULD support at least streamable-http.
A client that meets a transport value it does not recognise MUST
skip the record and proceed to the next record by priority, or to
HTTPS fallback.¶
The wire protocol beneath the transport (h2, h3, http/1.1)
is NOT carried in this record. It is already expressible as the
alpn service parameter of an SVCB or HTTPS resource record
[RFC9460], and duplicating it in TXT would create two sources of
truth for one fact.¶
Revision 01 of this document defined proto as the transport, so
records in the wild carry proto=streamable-http, proto=sse, or
proto=stdio-url. Revision 01 also admitted ANY token in that
field, and required a client that met a proto value it did not
recognise to SKIP the record. Both of those behaviours are
preserved here. Such records remain valid and MUST be read as
follows.¶
A client reading an _mcp record determines two things, the
protocol family first and the transport second. Taking them in the
other order is what makes an unrecognised value look harmless, so
the order is normative.¶
Step A, the protocol family. The family is mcp where any one
of the following holds:¶
proto is absent;¶
proto carries mcp;¶
proto carries one of the three values defined for transport
in Section 5.3.4. This is the revision 01 form, in
which the transport was written into proto.¶
Where proto carries any other value, it names a protocol family
this document does not define. The client MUST skip the record and
proceed to the next record by priority, or to HTTPS fallback. It
MUST NOT treat the value as a transport, and it MUST NOT apply a
default transport to the record. This holds whether or not a
transport field is also present: a record reading
transport=streamable-http; proto=websocket is skipped, because the
family is unknown, and the presence of a readable transport does not
make an unknown family speakable.¶
Step B, the transport. A client reaches this step only where
Step A yielded the family mcp.¶
Where transport is present and carries one of the three values
defined in Section 5.3.4, that value is the transport,
and any transport value carried in proto MUST be ignored.¶
Where transport is present and carries any other value, the
client MUST skip the record, and MUST proceed to the next record
by priority or to HTTPS fallback (Section 5.3.4).¶
Where transport is absent and proto carries one of the three
defined transport values, that value is the transport. This is
the revision 01 form.¶
Where transport is absent and proto is absent or carries
mcp, the transport is streamable-http.¶
Revision 01 admitted any
token in proto, so proto=websocket was a syntactically legal
record, and every conformant revision 01 client SKIPPED it, because
revision 01 required a skip on an unrecognised proto value. A
client that instead read an unrecognised proto value as a protocol
family, and then applied the default transport, would open a
streamable-http session against a server that never offered one.
That record was unusable under revision 01 and it stays unusable
here, which keeps the two revisions interoperable.¶
A publisher that emits a transport field MUST also emit
proto=mcp. A revision 01 client does not
know the transport field, and its own forward-compatibility rule
tells it to IGNORE any field it does not know, so it reads only
proto. A record carrying transport=streamable-http beside
proto=sse would therefore resolve to streamable-http under this
revision and to sse under revision 01, which is one record and two
transports. Setting proto=mcp alongside transport removes the
divergence, because a revision 01 client then finds no transport it
recognises in proto and skips the record rather than reaching a
different endpoint state than a current client would.¶
Publishers SHOULD move to the two-field form. No flag day is required, because the two forms are distinguishable by inspection, and because no value is defined for both fields (Section 5.2).¶
Ed25519 public key for endpoint verification, encoded as
ed25519:<base64url> where <base64url> is the raw 32-byte
public key encoded per [RFC4648] Section 5, without padding.¶
Where present, the pk field provides a cryptographic binding
between the DNS record and the MCP server. Clients MUST verify
that the key matches at least one of the following:¶
A key in the server's TLS certificate SubjectPublicKeyInfo.¶
The signing key used in HTTP Message Signatures [RFC9421] on MCP responses.¶
The key declared in the Server Card [SEP-1649] served by the endpoint.¶
If verification fails, the client MUST treat the server as untrusted and SHOULD NOT proceed with the MCP session.¶
A monotonic non-negative integer that increments on every key
rotation. Default value: 0.¶
Signed claims or attestations issued by the MCP server carry a key
identifier (kid) of the form <algo>:<pk>#<epoch>. Verifiers
resolve the Discovery Record, extract the current epoch, and apply
the following rules:¶
Claims with epoch == current are valid, subject to temporal
checks.¶
Claims with epoch < current are revoked unless the claim's
expiry timestamp predates the rotation event.¶
Claims with epoch > current MUST be rejected as either
forgeries or evidence of a stale verifier DNS cache.¶
The epoch field enables epoch-based revocation without external Certificate Revocation Lists (CRLs) or Online Certificate Status Protocol (OCSP) infrastructure. Incrementing the epoch revokes all outstanding claims issued under prior epochs, subject to the grace period defined by each claim's expiry.¶
The rules above compare a claim against the record. They do not
compare the record against itself over time. A publisher never
lowers the epoch, because the field is monotonic, so a record whose
epoch is lower than one a client has already observed is not a state
a conformant publisher produces. Section 13.1 states what a
client does when it observes one, and what it does when the pk
changes.¶
Capability tier advertised by the server, expressed as a comma-separated list of tokens. This field provides a coarse hint to clients about the functional scope of the server.¶
No normative semantics are defined for specific capability values in this document. Protocol extensions MAY define capability tokens and their semantics. Clients that do not recognise a capability token MUST ignore it.¶
A comma-separated list of attestation types that the MCP server declares it is authorised to issue. The value enumerates claim types that downstream verifiers will accept from this issuer.¶
Defined values, extensible:¶
employ, current employment affiliation.¶
contract, contractual or freelance engagement.¶
alumnus, former affiliation.¶
director, board or directorial role.¶
member, generic membership (professional body, association).¶
contrib, verified contribution without formal affiliation.¶
Verifiers MUST reject any attestation claim whose type is not
present in the issuer's attest field. This provides a
structural defence against capability creep: the domain's
published attestation scope is the upper bound on what its
claims can assert.¶
Forward compatibility: unknown attestation values MUST be ignored,
not rejected. A verifier encountering attest=employ,fellow
where fellow is undefined treats the record as
attest=employ and proceeds.¶
Comma-separated list of MCP primitives supported by the server. Defined values:¶
tools, the server exposes callable tools.¶
resources, the server exposes readable resources.¶
prompts, the server exposes prompt templates.¶
sampling, the server supports LLM sampling requests.¶
identity, the server supports identity resolution queries.¶
Unknown values MUST be ignored. This field is advisory; the
authoritative capability set is declared during the MCP
initialize handshake.¶
A non-negative integer. Default value: 10. Where multiple
Discovery Records exist at the same DNS name, clients MUST sort
records by priority in ascending order and attempt connection
to lower-valued records first.¶
This field enables multi-server failover without external load balancing. If connection to the highest-priority server fails, the client proceeds to the next record.¶
Advisory TTL in seconds for client-side caching of the parsed
Discovery Record metadata. Clients MAY use this value to avoid
repeated DNS lookups when the DNS TTL is shorter than desired.
The DNS TTL itself remains authoritative for cache expiry of the
raw DNS response; the ttl field applies to post-parse metadata
caching only.¶
An HTTPS URL pointing to a protocol-extension document. The format and semantics of the extension document are defined by the protocol extension, not by this specification.¶
This field enables protocol-specific extensions (identity protocols, payment protocols, agent-to-agent negotiation) to attach additional metadata without consuming space in the DNS TXT record. The extension document MUST be served over HTTPS. Clients that do not recognise or support the extension MUST ignore this field.¶
Implementations MUST ignore unknown fields. A parser encountering a field name that it does not recognise MUST skip that field and continue parsing the remaining fields. This rule ensures that future extensions to the record format do not break existing implementations.¶
Ignoring an unknown FIELD is not the same act as skipping a record on an unrecognised VALUE in a field this document defines. The first is required here; the second is required by Section 5.3.4 and Section 5.3.5.¶
Breaking changes to the semantics of existing fields require a
version bump, for example v=mcp2.¶
DNS TXT resource records are limited to 255 bytes per character-string [RFC1035]. Where a Discovery Record exceeds 255 bytes, the record MUST be split across multiple character-strings within a single TXT RDATA, which the client concatenates, as [RFC7208] Section 3.3 does for SPF.¶
Example of a multi-string record:¶
_mcp.example.com. IN TXT ( "v=mcp1; url=https://mcp.example.com; " "pk=ed25519:LongBase64UrlEncodedPublicKeyValueHere; " "epoch=3; attest=employ,contract,alumnus; scope=tools,identity" )¶
Parsers MUST concatenate all character-strings within a single TXT RDATA before parsing the semicolon-delimited fields. Parsers MUST NOT treat each character-string as an independent record.¶
_org-alter.<domain> (Identity Bootstrap)
This section defines the Org-Identity Record introduced in revision 02. It is given here in full.¶
The Org-Identity Record is a DNS TXT resource record [RFC1035]
published at the label _org-alter prepended to the Policy Domain:¶
_org-alter.<policy-domain>. IN TXT "<record-value>"¶
The underscore prefix conforms to the conventions established in [RFC8552] for globally scoped, underscore-prefixed DNS node names.¶
A domain MAY publish a _mcp.<domain> record without an
_org-alter.<domain> record (service-only deployment), or an
_org-alter.<domain> record without a _mcp.<domain> record
(identity-only deployment), or both (full deployment). The
recommended pattern for any operator running an org-alter instance
is to publish both.¶
Multiple TXT resource records MAY be published at the same DNS name
(e.g., for staged identity rotation). Clients MUST evaluate all
returned records and select the one with the highest epoch field.¶
The record value is a semicolon-delimited sequence of key-value pairs. The following ABNF [RFC5234] defines the syntax:¶
orgalter-record = version *( ";" SP field )
version = "v=alter1"
field = org-field / entity-field / entity-type-field /
founded-field / regions-field / regulated-field /
bootstrap-field / mcp-policy-field /
epoch-field / pk-field / attest-field /
ext-field / unknown-field
org-field = "org=" text-value
entity-field = "entity=" registry ":" text-value
entity-type-field = "entity-type=" text-value
founded-field = "founded=" date-fullyear
regions-field = "regions=" region-csv
regulated-field = "regulated=" framework-csv
bootstrap-field = "bootstrap=" https-uri
mcp-policy-field = "mcp-policy=" policy-token
epoch-field = "epoch=" 1*DIGIT
pk-field = "pk=" algo ":" base64url
attest-field = "attest=" attest-csv
ext-field = "ext=" https-uri
unknown-field = token "=" *qtext
registry = "abn" / "acn" / "ein" / "ch" / "cro" / "lei" / token
text-value = 1*qtext
qtext = %x20-3A / %x3C-7E
; printable ASCII and SP, excluding ";" (%x3B),
; which delimits fields. A legal entity name carries
; spaces, so VCHAR alone cannot express one.
region-csv = region-token *( "," region-token )
region-token = 2ALPHA ; ISO 3166-1 alpha-2
framework-csv = framework-token *( "," framework-token )
framework-token = "disp" / "itar" / "ear" / "hipaa" / "gdpr" /
"soc2" / "iso27001" / "iso42001" / "essential8" /
"aprs" / token
policy-token = "open" / "refuse-automated" / "refuse-tenant" /
"refuse-all" / token
date-fullyear = 4DIGIT [ "-" 2DIGIT [ "-" 2DIGIT ] ]
algo = "ed25519"
base64url = 1*( ALPHA / DIGIT / "-" / "_" )
https-uri = "https://" *uri-char
uri-char = %x21-3A / %x3C-7E
; printable ASCII, excluding ";" (%x3B) and SP.
; A URI carries no raw space.
token = 1*( ALPHA / DIGIT / "-" / "_" )
¶
A legal entity name carries spaces, so text-value admits them and
excludes only the semicolon that separates one field from the next.
Revision 02 defined org, entity and entity-type over 1*VCHAR,
which excludes the space.¶
A URI does not carry a raw space, so bootstrap and ext are
defined over uri-char rather than text-value. Admitting SP in a
URI value would let it run past its own end and consume the field
after it.¶
As in Section 5.2, unknown-field matches ONLY a field name this
document does not define. Where a field name IS defined above, the
field MUST be parsed by that field's own rule, and a record in which
a defined field's value does not satisfy its rule is MALFORMED and
MUST be discarded rather than re-read as an unknown field.¶
Protocol version identifier. MUST be the literal string alter1.
MUST appear as the first field in the record. Clients MUST reject
any record whose v field is absent, is not the first field, or
contains a value other than alter1.¶
The version namespace is independent of the _mcp record's
v=mcp1 namespace. This allows the two record types to evolve
independently.¶
The canonical legal name of the organisation operating the domain.
MUST be the registered legal entity name as it appears in the
operator's primary corporate registry, not a trading name or brand.
For trading names, see the optional entity-type field.¶
Examples:¶
org=Example Pty Ltd org=Example Corporation¶
A globally-disambiguating canonical entity identifier, prefixed by its registry namespace. Defined registries:¶
abn:, Australian Business Number (11 digits, no spaces).¶
acn:, Australian Company Number (9 digits, no spaces).¶
ein:, US Employer Identification Number (NN-NNNNNNN).¶
ch:, UK Companies House number (8 alphanumeric).¶
cro:, Irish Companies Registration Office number.¶
lei:, Legal Entity Identifier (20 alphanumeric per ISO 17442).¶
Additional registries MAY be defined; clients MUST treat unknown registry namespaces as opaque identifiers.¶
Example:¶
entity=abn:12345678901¶
The entity field lets a verifier check the declared name against
the public registry. A domain claiming to be Example Pty Ltd
without an ABN that resolves to that name in ABR Lookup shows as a
mismatch to any verifier with access to that registry.¶
A short human-readable label for the entity's type, drawn from its
jurisdiction's vocabulary. Examples: Pty Ltd, LLC, GmbH,
SAS, non-profit. This field is advisory and is intended for
display to humans; it is not a structured taxonomy.¶
The date the legal entity was founded or registered, as
YYYY or YYYY-MM or YYYY-MM-DD per ISO 8601. This field is
advisory and is used by onboarding wizards and identity verifiers
to display "Founded N years ago" or to detect implausibly young
entities making strong claims.¶
A comma-separated list of ISO 3166-1 alpha-2 country codes indicating the operator's primary regions of operation. This field is advisory. It is used by onboarding wizards to set sane defaults for jurisdiction-specific behaviour (e.g., currency, locale, public registry preference).¶
Example:¶
regions=AU,NZ,SG¶
A comma-separated list of regulatory framework tokens under which the operator is bound. Defined values (extensible):¶
disp, Australian Defence Industry Security Program.¶
itar, US International Traffic in Arms Regulations.¶
ear, US Export Administration Regulations.¶
hipaa, US Health Insurance Portability and Accountability Act.¶
gdpr, EU General Data Protection Regulation.¶
soc2, AICPA SOC 2 Type II.¶
iso27001, ISO/IEC 27001 information security management.¶
iso42001, ISO/IEC 42001 AI management systems.¶
essential8, ASD Essential Eight (ML2 or higher).¶
aprs, Australian Privacy Principles / Privacy Act.¶
A token in this field declares that the operator is bound by the named framework and that automated access crossing the regulated boundary MUST be refused. Onboarding wizards reading this field MUST refuse to attempt authenticated access to data stores covered by the declared framework, regardless of whether credentials are available. A remote agent can read the declaration before it attempts a connection.¶
Forward compatibility: an unknown framework token MUST NOT be ignored. It has the effect that step 4 of Section 12.2 gives any framework token.¶
An HTTPS URL pointing to a JSON document containing additional
identity bootstrap metadata: a directory of public roster members
(if the org chooses to publish one), an organisational logo URL, a
canonical public website URL, an attest profile beyond what fits
in DNS, and any operator-defined extensions.¶
The bootstrap document MUST be served over HTTPS with a valid TLS certificate for the Policy Domain. The document format is operator-defined.¶
A single token declaring how the operator's MCP endpoint relates to external automated access:¶
open, the MCP endpoint accepts queries from any agent with
appropriate authentication.¶
refuse-automated, the MCP endpoint exists for human-mediated
access only. Automated agents SHOULD NOT initiate sessions.¶
refuse-tenant, the MCP endpoint exists, but the operator runs
one or more tenants (e.g., an M365 tenant) into which automated
access is forbidden. This is the typical declaration for an
org-alter instance run by an operator who has DISP-accredited or
ITAR-bound systems alongside their public meta-layer.¶
refuse-all, the MCP endpoint exists for the operator's own
internal use only. External agents MUST NOT attempt connection.¶
Default value, if absent: open.¶
The mcp-policy field complements the regulated field.
regulated=disp; mcp-policy=refuse-tenant is the canonical
declaration for a defence contractor running an org-alter at the
unclassified meta-layer alongside a regulated tenant they will not
allow automated agents to enter.¶
A monotonic non-negative integer that increments on every identity
rotation event (e.g., legal entity restructure, change of control,
move to a new jurisdiction). Default value: 0. Semantics mirror
the epoch field of the _mcp record (Section 5.3.7). A wizard that
has persisted this record's pk and epoch applies the rules of
Section 13.1 when it re-reads the record.¶
Ed25519 public key for endpoint verification, encoded identically to
the _mcp record's pk field (Section 5.3.6). When present, the same key
provides cryptographic binding for both endpoint discovery and
identity bootstrap.¶
A comma-separated list of attestation types the operator declares it
is authorised to issue, identical in semantics to the _mcp
record attest field (Section 5.3.9). Where both records publish an attest field,
the values MUST be consistent. An onboarding wizard SHOULD use the
union of the two.¶
An HTTPS URL pointing to a protocol-extension document, identical in
semantics to the _mcp record ext field (Section 5.3.13). This field is
distinct from bootstrap: ext is for protocol-level extensions
to the discovery format itself; bootstrap is for operator-level
identity metadata.¶
Implementations MUST ignore unknown fields. This rule, identical to
that of the _mcp record (Section 5.4), ensures that future
extensions to the _org-alter record format do not break existing
implementations.¶
_alter.<domain> (Envelope Publication)
This section defines the Envelope Publication record introduced
in revision 03. The record publishes the seven required fields of the
identity envelope (binding a ~handle to its public key,
IdentityLog root, inception timestamp, revocation commitment, and
detached signature, under a protocol version) at an
underscore-prefixed label under the handle's hosting zone. The envelope
schema admits an optional caveats array which is never carried in
DNS; this document specifies no transport and no vocabulary for it,
so under this document the array is always empty and the signature
is computed over an empty array (Section 7.4). The signature
algorithm is not a separate field. It is derived from the pk=
prefix via the registry of Section 16.7, and enters the signing
input under that derivation.¶
The Envelope Record is a DNS TXT resource record [RFC1035]
published at the label _alter prepended to the hosting zone:¶
_alter.<zone>. IN TXT "<record-value>"¶
The underscore prefix conforms to the conventions established in [RFC8552] for globally scoped, underscore-prefixed DNS node names.¶
Publication of a per-individual envelope at this label is NOT RECOMMENDED, for the reasons in Section 7.1.1. That applies to
any number of handles. A zone MUST NOT publish envelopes for more
than one ~handle at this owner name, because a single query there
returns every handle the zone hosts (Section 7.1.1).¶
A domain MAY publish any combination of _mcp.<domain>,
_org-alter.<domain>, and _alter.<domain> records independently
(service-only, identity-only, envelope-only, or any intersection).¶
Publication of a per-individual envelope in DNS is NOT RECOMMENDED for new deployments. Three properties of DNS are the reason.¶
Enumeration. Where a zone co-hosts several handles at one owner name, a single query returns the entire set, and the individuals listed in it cannot each consent to the disclosure of the others. Even with one handle per zone, DNSSEC's authenticated denial of existence permits zone walking unless NSEC3 or a compact denial scheme is deployed, and this document does not require one.¶
Size. A conformant envelope does not fit in a single 255-octet character-string, and no conformant envelope is smaller than the limit. Co-hosting a handful of handles at one owner name exceeds the 1232-octet fragmentation budget that current DNS operational guidance assumes, and the RRset grows without bound in the number of handles. The resolution algorithm of Section 12.3 retrieves the whole RRset and filters client-side, so the cost of resolving one handle grows with the number of handles the zone hosts.¶
Erasure. A DNS record, once published and cached, cannot be recalled. A mechanism that binds a natural person's identifier to a key in public DNS offers that person no way to withdraw the binding from the caches and passive collectors that have already taken it. Revocation, where this document specifies it at all, marks a binding dead from the moment of reveal, along with every claim signed under its key (Section 7.3.6); it does not unpublish it.¶
These properties come from publishing in DNS. They do not apply to the envelope format, its signing input (Section 7.4), or the verification procedure (Section 12.3).¶
The record value is a semicolon-delimited sequence of key-value
pairs. Two grammars are given, because a publisher and a resolver
are held to different rules. alter-record is what a conformant
publisher MUST emit. alter-accepted is what a conformant resolver
MUST accept. Every alter-record is an alter-accepted; the
converse does not hold.¶
The following ABNF (per [RFC5234]) defines the syntax:¶
; Publisher emission. A conformant publisher MUST emit this form.
alter-record = version ";" SP handle-field
";" SP pubkey-field
";" SP ilr-field
";" SP ts-field
";" SP rev-field
";" SP sig-field
*( ";" SP unknown-field )
; Resolver acceptance. A conformant resolver MUST accept this form.
; The version field stays first. The remaining six required fields
; may arrive in any order, each exactly once, interleaved with any
; number of unknown fields.
alter-accepted = version *( ";" SP accepted-field )
accepted-field = handle-field / pubkey-field / ilr-field
/ ts-field / rev-field / sig-field
/ unknown-field
version = "v=alter1"
handle-field = "h=" handle
pubkey-field = "pk=" algo ":" base64url
ilr-field = "ilr=" base64url ; SHA-256 of IdentityLog root
ts-field = "ts=" 1*DIGIT ; inception_ts, Unix seconds
rev-field = "rev=" base64url ; SHA-256 of revocation pre-image
sig-field = "sig=" base64url ; Ed25519 detached signature
unknown-field = token "=" *qtext
handle = "~" handle-name
handle-name = sovereign-name / bot-name / instrument-name
sovereign-name = ALPHA *( ALPHA / DIGIT / "-" / "." )
; Sovereign tier
bot-name = ALPHA *( ALPHA / DIGIT / "-" / "." ) ".bot"
; Bot tier
instrument-name
= "cc-" 1*( ALPHA / DIGIT / "-" / "." )
; Instrument tier
algo = "ed25519"
base64url = 1*( ALPHA / DIGIT / "-" / "_" )
token = 1*( ALPHA / DIGIT / "-" / "_" )
qtext = %x20-3A / %x3C-7E
; printable ASCII and SP, excluding ";" (%x3B),
; which delimits one field from the next.
¶
ABNF alone cannot express "each of these six exactly once, in any order", so the cardinality rule is stated here and is normative. A resolver MUST reject any record in which a required field is absent, or in which any field name appears more than once.¶
ABNF cannot express the exclusion either. As in Section 5.2,
unknown-field matches ONLY a field name this document does not
define. Where a field name IS defined above, the field MUST be
parsed by that field's own rule, and a record in which a defined
field's value does not satisfy its rule is MALFORMED and MUST be
rejected rather than re-read as an unknown field.¶
The seven keys are REQUIRED. Publishers MUST NOT omit or reorder
them, and MUST emit them in the order shown in alter-record.¶
The v field is first for publisher and resolver alike. A resolver
MUST reject a record whose v field is absent or is not the first
field (Section 7.3.1), so the ordering freedom above extends to the
remaining six required fields and to unknown fields, and never to
v. Ordering among those six carries no meaning, and a resolver
MUST NOT derive any from it.¶
Resolvers MUST tolerate unknown fields wherever they appear, and MUST ignore them, per the forward-compatibility rule of Section 7.5.¶
Field order on the wire has no part in signature computation. The signed bytes are the JCS serialisation specified in Section 7.4, which sorts member names in code-point order and is therefore blind to the order the TXT record used.¶
Protocol version identifier. MUST be the literal string alter1.
MUST appear as the first field in the record. Resolvers MUST
reject any record whose v field is absent, is not the first
field, or contains a value other than alter1.¶
The version namespace v=alter1 on _alter.<zone> is independent
of the identically-named v=alter1 on _org-alter.<zone>. The
two namespaces are disambiguated by the enclosing record label and
MUST NOT be conflated. Future versions of either record may
advance independently (e.g. _alter.<zone> may progress to
v=alter2 while _org-alter.<zone> remains at v=alter1, or the
reverse).¶
The Sovereign-, Bot-, or Instrument-tier ~handle to which the
envelope binds. The leading tilde is mandatory. Where a resolver
encounters multiple envelope TXT RRs sharing an owner name, h= is
the sole field it MAY use to disambiguate them. Publishers MUST NOT create that arrangement (Section 7.1); the rule is retained for
resolvers only, so that a record published under revision 04 can
still be read. An Instrument-tier handle has no envelope of its own
(Section 2); a publisher SHOULD NOT publish an envelope whose
h is an Instrument-tier handle.¶
An Ed25519 public key prefixed by its algorithm namespace and encoded in base64url without padding per [RFC4648] Section 5:¶
pk=ed25519:<base64url-no-pad-32-bytes>¶
Resolvers MUST reject records whose algorithm prefix is not
ed25519 until a future revision registers additional algorithms.
The pk value is the verification key for the detached signature
in the sig field.¶
Base64url-no-pad SHA-256 digest of an IdentityLog root that the publisher claims was witnessed at envelope creation. The field carries a root and nothing more, so it cannot establish that this envelope is recorded in that log, and a resolver MUST NOT rely on it to detect substitution. Section 10 states what it can and cannot establish, and Section 14.3 sets out the forgery it permits.¶
Envelope inception timestamp, expressed on the wire as decimal Unix seconds. Resolvers MAY use this field to detect clock skew, evaluate caveat maturity, or reject envelopes with implausibly future inception. In the signing input of Section 7.4 the value is carried as a JSON string of those same decimal digits, never as a JSON number. A resolver that re-types it as a number canonicalises different bytes and every signature fails against it.¶
Base64url-no-pad SHA-256 digest of the revocation pre-image.
Revocation is effected by revealing the pre-image to the
IdentityLog; upon reveal, the envelope is considered revoked and
MUST NOT be honoured by resolvers. The rev field is a
hash commitment: the pre-image is never published in DNS
and is released only at revocation time to the log.¶
Revocation takes effect at once and has no grace period. From the
moment the pre-image is revealed, every claim signed under the
envelope's pk is invalid, whenever it was signed, and a verifier
MUST NOT honour a claim signed under the key of a revoked envelope.
The epoch rotation of the _mcp record differs: a claim issued under
an earlier epoch keeps the grace of its own expiry
(Section 5.3.7), because rotation is routine and revocation
signals compromise.¶
Publishers MUST NOT treat removal of the TXT record as revocation. Absence of a record is indistinguishable from misconfiguration; only pre-image reveal is authoritative.¶
Base64url-no-pad detached signature over the JCS-canonicalised
envelope JSON with the sig field absent. Canonicalisation is
specified by [RFC8785]. The signing input is the envelope JSON
reconstructed from the parsed TXT fields, plus a signature_alg
member derived from the pk= algorithm prefix per the registry of
Section 16.7, plus an EMPTY caveats array. The signature
algorithm itself is the one named by the pk= prefix. The exact
signing input is normative and appears in Section 7.4; it is not
restated by reference elsewhere.¶
Fields not enumerated above MUST be ignored by resolvers per
the forward-compatibility rule (Section 7.5), as the
unknown-field rule of Section 7.2 provides. Future revisions of
this document MAY define additional envelope fields, and MUST introduce a
new field only together with a new envelope version registered under
Section 16.3. This document defines no registry of
envelope fields.¶
The sig input is constructed as follows. This construction is
normative and exhaustive. An implementation that deviates in a key
name, a value type, or the membership of the object will produce
bytes that no other implementation can verify.¶
Parse the TXT RR character-strings into key-value pairs.¶
Derive signature_alg from the algorithm prefix of the pk
value via the Signature Algorithm Registry of Section 16.7. For
pk=ed25519:... the derivation yields the string Ed25519.¶
Construct the envelope JSON object, whose members are exactly
the six parsed fields that are not sig, plus the derived
signature_alg, plus caveats:¶
{
"v": "<v>",
"h": "<h>",
"pk": "<pk>",
"ilr": "<ilr>",
"ts": "<ts>",
"rev": "<rev>",
"caveats": [],
"signature_alg": "<derived>"
}
¶
The keys are the TXT field names, not expanded synonyms. Every
value is a JSON string, ts included, which carries the decimal
digits of the TXT field verbatim and is NOT converted to a JSON
number. caveats is a JSON array and, for any envelope resolved
from DNS under this document, it MUST be the EMPTY array. This
document defines no caveat transport and no caveat vocabulary, so
a non-empty array has no interoperable meaning and an
implementation MUST NOT construct one. sig MUST be absent from
the signing input, and no other member may be present. These
rules make the signed bytes a total function of the TXT record.¶
Apply [RFC8785] JSON Canonicalisation Scheme to the object, which sorts the member names in code-point order. The member order shown above is illustrative and has no effect on the canonical bytes.¶
The resulting byte stream is the signing input for the algorithm named in step 2.¶
Verification reverses this construction and checks the detached
signature in the sig field against the derived byte stream.¶
v is inside the signing input. A resolver that accepted an
envelope whose version was unsigned could be walked down to a
weaker version namespace by an on-path rewrite of the v field
alone, so the version is signed with everything else.¶
Publishers MUST emit TXT fields in the order given in Section 7.2, but the DNS key=value ordering has no role in signature computation: the signed bytes are always the JCS serialisation of the JSON object.¶
Resolvers MUST ignore unknown fields in the _alter.<domain>
record. This rule, identical to that of the _mcp and
_org-alter records (Section 5.4, Section 6.4), ensures that future extensions do not
break existing implementations.¶
Publishers MUST NOT introduce new fields that repurpose or overload the seven required field names; a new field MUST use a new name, and is introduced only together with a new envelope version registered under Section 16.3 (Section 7.3.8).¶
Where the serialised envelope exceeds the 255-octet character-string
limit of [RFC1035] Section 3.3.14, publishers SHOULD split at ;
boundaries between complete key-value pairs where the pair fits. A
publisher MAY split within a key-value pair, and MUST do so where a
single pair exceeds 255 octets on its own, which any signature
algorithm with a large signature will require. Resolvers MUST
concatenate the character-strings of a TXT RR in the order returned
by the DNS library (i.e. the RR wire order) BEFORE parsing, so the
split point is not observable to the parser and carries no meaning.¶
The zone publishing an _alter.<domain> envelope record MUST be
DNSSEC-signed per [RFC4033], [RFC4034], and [RFC4035].
Authoritative servers MUST respond with valid RRSIG coverage for
the TXT RRset. Recursive resolvers handling queries for the
envelope RRset MUST perform DNSSEC validation and MUST set the AD
(Authenticated Data) bit on the response delivered to the stub
client.¶
Stub clients (MCP clients, alter-runtime daemons, onboarding
wizards, recognition verifiers) consuming _alter.<domain>
envelope records MUST reject any response that lacks a set AD bit
or that fails local RRSIG verification when operating in
validating-stub mode. A record obtained over an unvalidated DNS
path MUST be treated as unauthenticated TXT content. Treating it as an
envelope is a downgrade vulnerability (Section 14.1).¶
This requirement is specific to _alter.<domain> records. DNSSEC
is RECOMMENDED but not REQUIRED for _mcp.<domain> and
_org-alter.<domain> records in this revision, for backward
compatibility with revision 01 and revision 02 deployments. Future revisions of
this document MAY promote DNSSEC to REQUIRED for the other two
records once deployment data justifies the promotion.¶
The MCP endpoint associated with a published envelope MUST carry a DANE TLSA resource record [RFC6698] binding the endpoint's leaf TLS certificate or SubjectPublicKeyInfo to the zone. The TLSA record MUST be published at:¶
_443._tcp.mcp.<zone>. IN TLSA <usage> <selector> <matching-type>
<cert-association-data>
¶
Recommended parameters:¶
Usage field. 3 (DANE-EE), pin the end-entity certificate
directly, with no CA chain reliance. A publisher that explicitly
requires CA-chain validation MAY use 1 (PKIX-EE) instead.
Publishers MUST NOT use 0 (PKIX-TA) or 2 (DANE-TA) for the
envelope record; the trust basis of the envelope is the
end-entity leaf.¶
Selector field. 1 (SPKI), pin the SubjectPublicKeyInfo so
that certificate rotations preserving the keypair do not
invalidate the record. Selector 0 (full certificate) MAY be
used but requires more frequent TLSA republication.¶
Matching-type field. 1 (SHA-256). Matching type 2
(SHA-512) is reserved for future revisions.¶
Clients establishing an MCP session at https://mcp.<zone>/ in
conjunction with a resolved envelope MUST fetch and validate the
TLSA record, MUST abort the TLS handshake on mismatch, and MUST NOT
fall back to PKIX-only validation on TLSA failure.¶
The TLSA requirement is scoped to envelopes whose MCP session
establishment is triggered by the resolved envelope (i.e. when the
envelope resolution and the subsequent MCP session are part of a
single recognition transaction). MCP clients that do not resolve
an envelope (e.g. revision 01 clients consuming only _mcp.<domain>)
are out of scope for this requirement and continue to operate
under revision 01 rules.¶
The ilr= field of the _alter.<domain> record carries a
base64url-no-pad SHA-256 digest of an IdentityLog root claimed by
the publisher to have been witnessed at envelope creation.¶
What ilr= can and cannot establish:¶
A resolver that has an independent view of the log MAY confirm
that the root named in ilr= is one the log actually published.¶
A resolver MUST NOT conclude from ilr= that the envelope in
front of it is recorded in that log. The field carries a root
and nothing else. It carries no leaf hash, no audit path, and no
proof of inclusion, so no resolver can perform that check, and
Section 14.3 sets out the forgery this permits.¶
A resolver MUST NOT treat the presence, absence, or successful
lookup of ilr= as a defence against envelope substitution.¶
The field is advisory. It is kept so that the wire format does not change.¶
The log's leaf hashing, tree construction, cadence, and witness protocol are not specified by this document, and a reader should not assume a specification exists.¶
The revocation check also crosses the IdentityLog. Where a
resolver has access to the log's revocation surface, it MUST treat
the envelope as revoked, and MUST NOT honour it regardless of the
freshness of the TXT RRset, if a pre-image whose SHA-256 equals the
rev= field has been revealed there.¶
A reader implementing from this document alone has no such access. The surface that carries reveals is not specified here and is not published anywhere a reader can fetch, so revocation status cannot presently be established from DNS alone.¶
alter: URI Scheme Cross-Reference
The URI scheme alter: provides a dispatchable
surface for ~handle references: operating-system URI handlers
(xdg-mime, LSHandlers, Windows registry, Android intent-filter)
invoke a resolver that retrieves the envelope from DNS and verifies
it per Section 12.3.¶
The scheme is specified in [ALTER-URI]. The registration sought is provisional, per [RFC7595] Section 4, under the procedure of [RFC7595] Section 7.2. The full registration body, scheme syntax, semantics, encoding considerations, interoperability and security considerations, author and change controller, is submitted to IANA separately from this document. The registration reference will be substituted when IANA assigns one.¶
Handlers invoked via alter: URIs MUST perform full envelope
verification, DNSSEC validation (Section 8), and DANE TLSA binding
(Section 9) when establishing any HTTPS session, before acting on
any content or
directive derived from the envelope.¶
The formats these procedures consume are given in full in Section 5, Section 6 and Section 7.¶
_mcp.<domain>
This is the algorithm an MCP client follows to discover an MCP server associated with a given domain. It is the algorithm of [DNSDISC-01], restated here in full. Revision 05 added the reading rule at step 7c, and revision 06 extended step 7b to apply Section 13.1. Every other step is unchanged.¶
The procedure takes a single input, an Origin Domain. The Origin
Domain is typically extracted from an identifier encountered during
agent operation, such as an email address (user@example.com yields
example.com), a URL (https://example.com/path yields
example.com), a handle (~user@example.com yields
example.com), or a bare domain.¶
Normalise. Convert the Origin Domain to its canonical form: lowercase per [RFC4343], and apply IDNA2008 processing where the domain contains non-ASCII labels.¶
Construct query name. Prepend the label _mcp. to the
normalised Origin Domain, yielding _mcp.<origin>..¶
Query DNS. Issue a DNS query for _mcp.<origin>. IN TXT
via the client's configured recursive resolver. Clients SHOULD
prefer DoH ([RFC8484]) or DoT ([RFC7858]) to protect query
privacy (Section 15.2).¶
Handle the DNS response.¶
a. On NOERROR with one or more TXT records, proceed to step 5.¶
b. On NXDOMAIN, or NOERROR with zero TXT records, proceed to step 8 (HTTPS fallback).¶
c. On SERVFAIL or timeout, the client MAY retry with exponential backoff, or proceed to step 8.¶
Parse records. For each TXT RDATA in the response:¶
a. Concatenate all character-strings within the RDATA.¶
b. Split the concatenated string on the ";" delimiter, trimming
leading and trailing whitespace from each field.¶
c. Verify that the first field is v=mcp1. If it is not,
discard this record.¶
d. Extract all recognised fields. Ignore unknown fields, per the forward-compatibility rule of Section 5.4.¶
e. Verify that the url field is present and carries a
syntactically valid HTTPS URL. If it does not, discard this
record.¶
Sort by priority. Collect all valid records and sort them by
priority in ascending order, lowest value first. Records of
equal priority MAY be tried in any order.¶
Connect. For each record in priority order:¶
a. Establish a TLS connection to the host named in the url
field.¶
b. Where the client holds a pinned key binding for the Origin
Domain, apply Section 13.1 first, and verify the endpoint
against the pinned key whether or not the record carries a
pk field. Otherwise, where the record carries a pk field,
verify the key per Section 5.3.6. On failure, skip to the
next record.¶
c. Determine the transport by applying the reading rule of
Section 5.3.5 to the record's transport and proto
fields. Where that rule directs the client to SKIP the
record, skip it and proceed to the next record by priority.
Otherwise, initiate the MCP session over the transport the
rule yields.¶
d. If the MCP initialize handshake succeeds, discovery is
complete.¶
e. If connection or handshake fails, proceed to the next record. If all records are exhausted, proceed to step 8.¶
HTTPS fallback. Attempt HTTPS-based discovery by fetching
https://<origin>/.well-known/mcp/server-card.json per
[SEP-1649], or https://<origin>/.well-known/mcp per
[SEP-1960]. If fallback succeeds, proceed with the MCP session.
If fallback fails, discovery has failed.¶
This procedure does not consume the _alter.<domain> record and
imposes no DNSSEC requirement. A client that resolves an envelope
executes Section 12.3 instead, which does.¶
_org-alter.<domain>
This is the procedure by which an org-alter implementation reads its own DNS records on first install to populate its canonical identity state. It is the algorithm of [DNSDISC-02], unchanged, restated here in full.¶
The procedure takes a single input, the operator's primary domain name, being the Policy Domain under which the operator publishes records.¶
Query _org-alter.<domain> TXT. Issue a DNS query for the
Org-Identity Record.¶
If found, parse and load. Extract org, entity,
entity-type, founded, regions, regulated, and
mcp-policy into the org-alter's identity state. These become
the canonical identity declaration the org-alter uses in all
subsequent self-description and external attestation.¶
If bootstrap= is present, fetch the bootstrap document over
HTTPS. Validate the document's TLS certificate against the
Policy Domain. Merge the document's roster, logo, and extension
fields into the identity state. Reject the bootstrap document if
its TLS certificate is invalid, or if its content does not parse.¶
Honour regulated= and mcp-policy= as immutable structural
constraints on the org-alter instance.¶
a. If regulated carries any framework token, set the
org-alter's boundary policy to refuse, and disable every
automated data ingestion.¶
b. If mcp-policy=refuse-tenant, the org-alter MUST refuse to
install any ingester that requires authenticated access to a
tenant covered by the declared framework, even where
credentials are subsequently provided.¶
c. The wizard SHOULD display these constraints to the operator for confirmation, and MUST NOT allow the operator to override them silently. An operator who wishes to relax a constraint MUST update the DNS record first, then re-run bootstrap.¶
Cross-check _mcp.<domain>. Query the service-discovery
record of Section 5. Where both records exist and both
publish a pk field, the values MUST match. A mismatch
indicates either a configuration error or a key compromise; the
wizard MUST refuse to bootstrap under that condition, and MUST
surface the discrepancy to the operator. Section 14.6
states how this rule relates to the envelope key of
Section 7, which is a distinct key and is not subject to
it.¶
Verify against public registries. Where the entity field
declares a known registry namespace (for example abn:), the
wizard SHOULD query the corresponding free public registry and
verify that the declared entity identifier resolves to the
declared org name. A mismatch is not necessarily fatal,
because names change and registries lag, but the wizard MUST
surface the discrepancy and MUST require operator confirmation
before proceeding.¶
Persist canonical state. Write the resolved identity into the org-alter's local identity state, source-citing each field to its DNS or HTTPS origin.¶
For an operator who has not yet published an _org-alter record at
the time of installation, the wizard MUST fall back to interactive
seeding. It prompts for org, optionally prompts for entity, and
asks whether the operator's environment is regulated. After
interactive seeding, the wizard SHOULD generate a draft DNS record
value for the operator to publish, which completes the bootstrap
loop.¶
_alter.<domain>
The procedure takes two inputs, a zone and the ~handle to be
recognised, and both are REQUIRED. An alter: URI [ALTER-URI] supplies the handle. The zone is never derived from the spelling of the handle. It is supplied by the caller, or taken as Section 3.4 of [ALTER-URI] specifies. A resolver that has only a zone, and no handle,
cannot execute this procedure. Step 4 selects the record whose h=
matches the requested handle, and with no requested handle there is
nothing to match against. Such a resolver has not been asked a
recognition question, and MUST NOT treat whatever record it finds at
the owner name as the answer to one.¶
Given those two inputs, a resolver MUST execute the following steps in order. Steps 1 through 8 and step 10 are FATAL: failure of any of them terminates recognition, and the envelope MUST be treated as unverified. Steps 9, 11 and 12 are ADVISORY: being UNABLE to perform them MUST NOT terminate recognition, because a resolver that cannot reach a surface has learned nothing either way. A POSITIVE finding is different. A revocation observed at step 12 is FATAL and MUST abort (Section 10).¶
Query. Issue a DNS TXT query for _alter.<zone>.. Use
DoH or DoT in preference to UDP/53 where operationally feasible.¶
DNSSEC validation. Validate the RRSIG chain from the root trust anchor to the TXT RRset (Section 8). Confirm the AD bit on the response when relying on an upstream validating resolver, or locally RRSIG-validate in validating-stub mode. On failure, abort.¶
Chunk reassembly. Concatenate character-strings in RR order;
parse ; -separated key-value pairs.¶
Handle disambiguation. Select the record whose h= field
matches the requested ~handle. If no record matches, abort.¶
Field extraction. Confirm presence of the seven required
fields (v, h, pk, ilr, ts, rev, sig). Reject any
record missing any required field, or whose v is not
alter1.¶
Envelope reconstruction. Build the envelope JSON exactly as
Section 7.4 specifies, deriving signature_alg from the pk=
prefix and supplying an empty caveats array.¶
JCS canonicalisation. Apply [RFC8785] JCS to the envelope
with the sig field absent.¶
Ed25519 verification. Verify the detached sig over the
JCS byte stream using the public key in pk. On failure,
abort.¶
IdentityLog cross-reference (ADVISORY). A
resolver with an independent view of the log MAY confirm that the
root named in ilr= is one the log published. A resolver MUST NOT abort on failure, and MUST NOT treat success as evidence that
this envelope is in the log, because ilr= carries no proof of
inclusion (Section 10; Section 14.3).¶
DANE TLSA validation. When establishing an MCP session at
mcp.<zone> as part of the same recognition transaction, fetch
the TLSA record at _443._tcp.mcp.<zone>. and gate the TLS
handshake on the binding (Section 9). On mismatch, abort.¶
Caveats evaluation (OUT OF SCOPE for this document). The
envelope schema admits an optional caveats array, which is
never carried in DNS. This document specifies neither a
transport for it nor a vocabulary, so a resolver implementing
this document alone MUST treat the envelope as having no
caveats, and MUST verify the signature over an empty caveats
array per Section 7.4. A future document may define a caveats
surface, and until one does, an envelope whose signer intended
caveats cannot be distinguished from one that carries none.¶
Revocation check (ADVISORY). Where the resolver has access
to the log's revocation surface, consult it. Being UNABLE to
perform this step MUST NOT terminate recognition, and Section 10
says why a resolver implementing this document alone cannot. If a
pre-image whose SHA-256 equals
rev= has been revealed, the envelope IS revoked, recognition
MUST abort, and the envelope MUST NOT be honoured however fresh
the TXT RRset. The revocation is immediate, and every claim signed
under the envelope's key is invalid from that moment, whenever it was
signed (Section 7.3.6).¶
An envelope is verified when every FATAL step (1 through 8, and 10) has succeeded AND no ADVISORY step has returned a positive failure. A resolver that CANNOT reach a revocation surface proceeds, while a resolver that OBSERVES a revocation MUST abort and MUST NOT treat the envelope as verified. An unverified envelope MUST be refused upstream of any authorisation or trust decision.¶
The rules for the first two records are those of [DNSDISC-01] and [DNSDISC-02], unchanged, with the key continuity rule of Section 13.1 added in revision 06, restated here so that a reader need not fetch either document to cache correctly.¶
For _mcp.<domain>, clients SHOULD cache the parsed record metadata
for the duration of the DNS TTL. Where the record carries a ttl
field, clients MAY extend the metadata cache to that duration, but
MUST re-validate the underlying DNS record when the DNS TTL expires.
A client that has connected to an MCP server and verified its pk
SHOULD cache the verified key binding and re-validate it on
subsequent connections, which is trust on first use with periodic
re-verification against DNS. What the client does when that
re-verification disagrees with what it cached is stated in
Section 13.1.¶
For _org-alter.<domain>, records SHOULD be cached for the duration
of the DNS TTL. An onboarding wizard typically reads the record
once at install time and persists the resolved state locally, so the
DNS record need not be re-read on every invocation. Wizards MAY
re-read it on operator request, on epoch change detected by a
periodic background poll, or on identity verification failure.¶
_alter.<domain> records SHOULD be cached for the duration of the
DNS TTL. Resolvers MUST NOT serve stale envelope TXT past the
RRset TTL unless they are themselves validating caches and can
re-confirm RRSIG coverage on each serve. Recognition verifiers
MAY cache successful verification results locally for a short
interval (bounded above by the RRset TTL or 3600 seconds,
whichever is smaller) to amortise the cost of repeated JCS and
Ed25519 operations. A resolver that is able to perform the
revocation check at all (Section 10 sets out why one working from
this document alone is not) MUST re-run it on each recognition
event, not on each cache refresh.¶
This section states what a client does when re-validation of a cached key binding fails. The mechanism is the one SSH clients apply to host keys.¶
A pinned key binding is the triple a client holds after a successful
verification under Section 5.3.6: the Origin Domain, the pk it
verified, and the epoch the record carried at the time, defaulting
to 0 where the record carried none. On each later resolution of
_mcp.<domain> for which it holds a pin, the client compares the
record it receives with the pin, and the following rules apply in
order.¶
Same key, same epoch. Continuity holds. The client proceeds under Section 12.1.¶
Epoch lower than the pinned epoch. The epoch is monotonic
(Section 5.3.7), so a decrease is never a state a conformant
publisher produces. It indicates a stale or manipulated response,
a publisher restoring an old record, or a new operator of the
domain that began its own count at 0. The client MUST NOT lower
its pinned epoch, and MUST NOT replace its pinned key on the
strength of this record. It SHOULD re-query, bypassing any local
cache it controls. Where the served key equals the pinned key,
the client MAY proceed, and MUST evaluate the kid of any claim
against its pinned epoch rather than the lower served one. Where
the served key differs, the client MUST treat the server as
untrusted, exactly as a failed verification under
Section 5.3.6, and SHOULD surface the discrepancy.¶
Different key, same epoch. The record's own contract is that the epoch increments on every key rotation, so a key that changes without it is an undeclared change. The client MUST treat the server as untrusted, MUST NOT replace its pin, and SHOULD surface the discrepancy.¶
Different key, higher epoch. This is a declared rotation. The client MUST verify the new key per Section 5.3.6 before replacing its pin, and on success MAY replace the pinned key and epoch. A declared rotation is also what a new operator of a lapsed and re-registered domain can publish, because the epoch is self-asserted by whoever controls the zone. A client with access to registration data SHOULD therefore apply the change-of-control signals of Section 13.1.2 before it replaces the pin.¶
Same key, higher epoch. The client MAY raise its pinned epoch. Claims under the lower epoch are then handled per Section 5.3.7.¶
No key. A record that carried a pk when the pin was made
and now carries none has not released the pin. The client MUST
continue to verify the endpoint against the pinned key, as step 7b
of Section 12.1.2 requires. Removing the field is not
a way to rotate a key.¶
A pinned key MUST NOT be replaced automatically under rules 2, 3 or 6. It MAY be replaced by an action of the client's user or operator, taken outside this procedure and after the discrepancy has been surfaced to them.¶
A client that holds a pin and finds no _mcp record, on NXDOMAIN or
on NOERROR with no TXT records, proceeds to the HTTPS fallback of
step 8 of Section 12.1.2. It MUST NOT clear the pin,
and MUST NOT treat the absence as revocation of the binding or of
any claim issued under it. A client that reaches an endpoint for
the same Origin Domain by fallback SHOULD verify it against the
pinned key.¶
This is the position Section 14.4 takes for the envelope record, for the same reason. A zone that is briefly unreachable, through an outage, a registrar incident or a tooling error, must not become a revocation event. A second reason applies to pins alone. If absence cleared a pin, an attacker able to suppress the record for a single resolution would reset the client to first use, and could then publish its own key and have it accepted as though no pin had ever existed.¶
This differs from [DOMAIN-SET], which holds in
its Section 6.4 that removal of a record is revocation. The two
records do different jobs. A domain-set record is an attestation
its publisher withdraws by deleting it. An _mcp record is a
pointer to an endpoint, and a key binding is revoked by rotation,
under rule 4 above, never by the record going away.¶
The epoch cannot distinguish a rotation by the existing operator from a rotation by a new one, because both publish a higher epoch and a new key. Registration data can, in part. [DOMAIN-SET] Section 6.3 gives consumer rules for this case, graded by the strength of the signal, and this document adopts them for the pinned key binding. A client with access to registration data for the Origin Domain, for example through RDAP [RFC9083], SHOULD consume those signals in the order given there, and act on them as follows.¶
Creation date changed. The registry object was deleted and the name registered again, and renewal or restoration never changes it. The domain is now operated by a party the pin says nothing about. The client MUST discard the pin, MUST NOT carry the pinned binding, or any trust its user or operator attached to it, forward to whatever key the record now serves, and SHOULD surface the change. A binding made after that point is a first use, and MUST NOT be presented as a continuation of the earlier one.¶
Lapse indicators. A registry grace status, or an expiry earlier than the observation, means the registration lapsed. Control may have passed without deletion, because names sold on in expiry auctions keep their creation date. A declared rotation under rule 4 observed while a lapse indicator is present MUST NOT replace the pin automatically, and SHOULD be surfaced for the action of the user or operator described above.¶
Transfer indicators. A transfer event, or a change of sponsoring registrar, SHOULD be surfaced as a warning. It does not by itself block a declared rotation.¶
A change of control that leaves no trace in registration data, such as a sale inside one registrar with no lapse, followed by a declared rotation, is not detectable by a client following this document. [DOMAIN-SET] states the same limit for its own records.¶
The security considerations of [DNSDISC-01] Section 7 apply to
the _mcp record, and those of [DNSDISC-02] Section 10 apply to
the _org-alter record. The subsections below cover the
_alter envelope record and the rules this document adds to the
other two records.¶
The mandatory DNSSEC requirement in Section 8 is the primary
defence against on-path manipulation of envelope TXT content. An
attacker who can inject unsigned responses, e.g. via a compromised
resolver or a DNS middlebox that strips RRSIG, would otherwise
be able to substitute an attacker-controlled envelope at the resolver
boundary. Stub clients MUST reject any response lacking AD or
failing local RRSIG verification. Operators MUST NOT downgrade the
_alter. RRset to unsigned during KSK/ZSK rollover (see [RFC6781]
for best-current practice on rollover).¶
The DANE TLSA requirement in Section 9 binds the MCP endpoint's TLS
leaf to a specific hash. Operators rotating certificates MUST
publish the new TLSA record before the new certificate is activated
on the live listener, with a grace window of at least twice the
TLSA RRset TTL. Selector 1 (SPKI) survives rotations that preserve
the keypair; selector 0 requires republication on every rotation.
Loss of the TLS private key forces certificate reissue and
republication of the TLSA record, not silent cert replacement. It
does not engage the rev= reveal path, which revokes the identity
envelope and has no bearing on a TLS leaf.¶
An attacker in control of a domain's DNS can publish an arbitrary
envelope for any ~handle claimed to be hosted under that zone.
The structural defences, and the limit of each, are:¶
IdentityLog witness. This defence does not hold as
specified. ilr= carries a bare tree root and no proof of
anything, so a resolver can confirm that the named root was
witnessed but CANNOT confirm that the envelope in front of it is
a leaf under that root, and no field of Section 7.2 would let it.
A zone attacker therefore mints an envelope, copies any
witnessed root out of the public log, signs, and publishes. The
result satisfies every check the recognition procedure of
Section 12.3 specifies. As specified, ilr= establishes only
that the publisher could read a public value. Implementers MUST NOT rely on ilr= to detect substitution.¶
Ed25519 signature. The detached signature binds the
envelope to a specific Ed25519 key. An attacker who does not
hold the private key cannot forge a valid sig. An attacker
who does hold the private key has already compromised the
handle; the revocation path (Section 10) is the residual mitigation.¶
DNSSEC. Section 8 prevents tampering with the TXT RRset in transit, which prevents third-party substitution. It does not prevent a malicious zone operator from publishing a malicious envelope. Defence (1) does not hold against that attack, and defence (2) holds only where the operator does not hold the private key.¶
Revocation is effected by revealing the pre-image to the
IdentityLog, not by removing the TXT record. Absence of a record
is indistinguishable from misconfiguration; resolvers MUST NOT
treat absence as revocation. A zone
briefly unreachable (DNS outage, registrar incident, tooling error)
must not accidentally become a revocation event.
Section 13.1.1 applies the same position to a pinned
_mcp key binding, and says why it differs from [DOMAIN-SET].¶
The cost is that a compromised zone may continue to serve a valid (but intended-to-be-revoked) envelope until the rightful handle-holder reveals the pre-image. This document does not specify where a reveal is published, and Section 10 says why no such surface can be assumed, so revocation is not presently actionable by a resolver working from this document alone. Handle-holders SHOULD establish a pre-committed revocation reveal procedure at mint time.¶
ts=
The ts= inception timestamp is advisory: resolvers MAY use it to
detect implausibly future envelopes (e.g. minted more than a few
hundred seconds after current wall time) but MUST NOT rely on
local clock for security-critical decisions. This document
specifies no authoritative ordering anchor. ts= is self-asserted
by the publisher and is advisory only.¶
Where all three records (_mcp, _org-alter, _alter) are
published under one zone and each carries a pk field, the values
MUST be evaluated for consistency. Two different rules apply.¶
The _mcp.pk and _org-alter.pk fields are the service key and the
organisational key. Step 5 of Section 12.2, restated from
[DNSDISC-02], requires them to MATCH where both are published, and
requires a bootstrapping wizard to refuse and to surface the
discrepancy where they do not. That rule is unchanged. A mismatch
across that pair indicates a configuration error or a key
compromise.¶
The _alter.pk field is the envelope key. It is a
structurally distinct key with a distinct purpose, it is NOT subject
to the bootstrap match rule, and it MAY differ from both of the
others. A resolver MUST NOT treat a difference between _alter.pk
and either of the other two as evidence of anything.¶
Where a zone operator has bound all three to one Ed25519 key, as a single-operator deployment may do, a later mismatch indicates either a rotation in progress or a compromise, and resolvers SHOULD surface it. A resolver cannot distinguish that deployment from one that intended three distinct keys, because this document publishes no signal of the operator's intent, so the surfacing is advisory and MUST NOT be fatal.¶
A publisher SHOULD NOT ride an inferred trait, a passive-stream
derivative, or a provenance-tagged attribute on the
_alter.<domain> record.¶
This is a recommendation, and nothing in the grammar enforces it.
The ABNF of Section 7.2 admits
unknown-field = token "=" *qtext, which admits arbitrary attributes, and Section 7.5 requires resolvers to
IGNORE unknown fields rather than reject the record. The qtext
rule bounds only the field DELIMITER, so that an unknown field
cannot swallow the semicolon and consume the fields after it. It
bounds nothing about the field's meaning. Nothing in
this document structurally prevents a publisher from riding
additional attributes on this owner name, and a resolver MUST NOT
infer from a record's conformance that it carries nothing else.¶
Two consequences follow. An unknown-field is NOT covered by the signing input of Section 7.4,
which spans the six required fields other than sig, plus the
derived signature_alg and an empty caveats array, and nothing
else. Any attribute riding the record is therefore UNSIGNED, and a
resolver MUST NOT attribute it to the handle-holder. And because a resolver ignores what it does
not recognise, the record is a viable carrier for data the envelope
was never meant to convey. The privacy implications of passive
inference are out of scope for this document.¶
Every record this document defines names its subject by a domain, and a domain can change hands. When a registration lapses and the name is registered again, the new registrant controls the zone and can publish any of the three records. Nothing in the records changes shape when that happens, and no single resolution can tell the new operator from the old one.¶
For the _mcp record, Section 13.1 is the defence. A client
that pinned the prior operator's key refuses an undeclared key change
and an epoch that goes down, keeps its pin when the record
disappears, and, where it can read registration data, discards the
pin on a changed creation date rather than carrying it to the new
operator. A client that has never connected before has no pin, and
for that client a re-registered domain is indistinguishable from any
other first use.¶
For the _alter record, the limit stated in Section 14.3
applies without change. The envelope carries no epoch, and this
document specifies no pin for it. A new registrant can mint an
envelope for a handle under a key of its own and satisfy every FATAL
step of Section 12.3. A resolver that has previously verified an
envelope for the same handle, and now finds a different pk, SHOULD
surface the change. It learns nothing further from this document
about which of the two keys the handle-holder controls.¶
The privacy considerations of [DNSDISC-01] Section 8 apply to the
_mcp record, and those of [DNSDISC-02] Section 11 apply to the
_org-alter record. The subsections below cover the _alter
envelope record.¶
Publishing _alter.<domain> exposes the bound ~handle, its
Ed25519 public key, its IdentityLog root, its inception timestamp,
and its revocation-hash commitment to any DNS observer. Public
verifiability does not require public enumeration, and
Section 7.1.1 sets out why DNS publication brings both.
A handle-holder who requires concealment MUST NOT publish an
_alter.<domain> record. Means of recognition that do not publish
in DNS are outside the scope of this document.¶
A resolver querying _alter.example.com reveals to its recursive
resolver that it intends to verify the envelope hosted under that
zone. Query metadata privacy is addressed at the transport layer:
clients SHOULD prefer DoH ([RFC8484]) or DoT ([RFC7858]) over
UDP/53 where operationally feasible. This consideration is the
same as in revisions 01 and 02, and matters more here because the envelope
names an individual.¶
The rev= field is the SHA-256 of a secret pre-image; publishing
it does not disclose the pre-image. An observer cannot predict
the pre-image or link it back to any identifier. Reveal at
revocation time links the pre-image to the envelope, but only at
the moment of revocation, not during the envelope's active
lifetime.¶
This document requests IANA to update the entries in the "Underscored and Globally Scoped DNS Node Names" registry established by [RFC8552] as follows. Each label is defined by this document, in the section named, and no longer by an earlier revision of it.¶
| RR Type | _NODE NAME | Reference |
|---|---|---|
| TXT |
_mcp
|
Section 5 of this document |
| TXT |
_org-alter
|
Section 6 of this document |
| TXT |
_alter
|
Section 7 of this document |
The _alter label is used to publish envelope records as defined
in Section 7 of this document.¶
alter: URI Scheme Registration
This document cross-references the provisional registration
of alter: per [RFC7595] Section 4, which IANA made on
5 October 2026. The registration template is carried in
[ALTER-URI]. This document
notes that recognition verifiers invoked via alter: URIs MUST
follow Section 12.3 of this document for envelope verification.¶
This document defines the version tag v=alter1 for the
_alter.<domain> record, independent of the identically-named tag
on the _org-alter.<domain> record. Future versions (v=alter2
and beyond) SHOULD be coordinated with implementers and documented in
successor revisions of this draft. Until a working group takes up
identity-envelope DNS publication, the author maintains the version
namespace. A new envelope version is the only way a new envelope field
is introduced (Section 7.3.8).¶
The version tag v=alter1 for the _org-alter.<domain> record is
preserved from revision 02. No changes are requested in this revision.¶
The initial set of entity field registry namespaces (abn,
acn, ein, ch, cro, lei) defined in revision 02 is preserved
unchanged.¶
The initial set of regulated framework tokens (disp, itar,
ear, hipaa, gdpr, soc2, iso27001, iso42001,
essential8, aprs) defined in revision 02 is preserved unchanged.¶
This document defines the initial pk= and sig= algorithm
namespace ed25519 for the _alter.<domain> record. Future
algorithms (e.g. ed448, ml-dsa-65) MAY be registered by
successor documents. Resolvers MUST reject records whose
algorithm prefix is not registered at the resolver's protocol
version.¶
This section provides non-normative examples of Envelope Records for common deployment scenarios.¶
A zone hosting a single Sovereign-tier handle publishes its
envelope at _alter.<zone>.:¶
_alter.example.com. 3600 IN TXT ( "v=alter1; h=~alice; " "pk=ed25519:<EXAMPLE-pubkey-32B-base64url>; " "ilr=<EXAMPLE-identitylog-root-32B-base64url>; " "ts=1729123456; " "rev=<EXAMPLE-revocation-hash-32B-base64url>; " "sig=<EXAMPLE-ed25519-signature-64B-base64url>" )¶
All base64url values in this example are illustrative. Production values are the Ed25519 public key, SHA-256 digests, and 64-byte detached signature encoded per [RFC4648] Section 5 without padding.¶
This example is retained so that a resolver can read the records a revision 04 publisher may already have published. It is NOT a pattern to follow. The shape below IS the enumeration exposure described in the Applicability statement. One query at the owner name returns every handle the zone hosts, and none of the individuals listed can consent on behalf of the others. A publisher MUST NOT create it (Section 7.1).¶
Resolvers disambiguate by the h= field:¶
_alter.example.org. 3600 IN TXT "v=alter1; h=~alice; pk=..." _alter.example.org. 3600 IN TXT "v=alter1; h=~bob; pk=..." _alter.example.org. 3600 IN TXT "v=alter1; h=~carol.bot; pk=..."¶
A resolver asked to verify ~bob at example.org selects the
second RR.¶
_alter record is NOT RECOMMENDED)
A zone operator running an org-alter instance for their own principal handle publishes all three records:¶
_mcp.example.com. IN TXT "v=mcp1; url=https://mcp.example.com/"
_org-alter.example.com. IN TXT "v=alter1; org=Example Org; ..."
_alter.example.com. IN TXT "v=alter1; h=~alice; "
"pk=ed25519:...; ilr=...; "
"ts=...; rev=...; sig=..."
_443._tcp.mcp.example.com. IN TLSA 3 1 1 <sha256-of-spki>
¶
Together these expose: the MCP service endpoint and its
capabilities (_mcp); the legal entity, regulatory posture, and
jurisdictional regions (_org-alter); the Sovereign-tier
envelope for ~alice (_alter); and the DANE TLSA pin on the
MCP endpoint. A resolver may consume any subset according to its
recognition requirement.¶
A domain that publishes only an _mcp.<domain> record published under
revision 01 continues to work with all revision 01, 02, and 03 clients. Where that record
carries a transport value in proto, a client conforming to this
revision reads it under steps A and B of Section 5.3.5 and reaches the
same endpoint over the same transport. No republication is required
for the record to keep working, and none is required for a record
carrying a proto value that no revision recognised, because such a
record was skipped by revision 01 clients and is skipped by these.¶
A domain that publishes _mcp.<domain> and _org-alter.<domain>
(revision 02) continues to work with revision 02 clients and with clients conforming
to this document, unchanged. A client conforming to this document
may additionally query _alter.<domain> and MUST handle its absence
gracefully, which is the common case and the recommended one:
publication of that record is NOT RECOMMENDED
(Section 7.1.1), so a conforming client should expect to
find it absent and MUST NOT treat its absence as an error.¶
A domain that publishes only _alter.<domain> (envelope-only, no
MCP server, no organisational record) is permitted by the grammar.
The configuration is NOT RECOMMENDED per Section 7.1.1.¶
The three records are orthogonal along their semantic axes but share the zone's DNSSEC trust root. A resolver conforming to this document that resolves any subset of the three records treats each resolution as independent and does not fail the resolution of one record because another is absent or malformed.¶
This section records the status of known implementations at the time of publication, per [RFC7942].¶
Deployed and resolvable in the truealter.com zone:¶
_mcp.truealter.com, carrying v=mcp1 with url, proto,
pk, epoch, and cap. This is the only record in the zone
that a resolver can verify against this document today.¶
_alter.truealter.com, carrying v=alter1. It does not carry
the envelope field set (h, ilr, ts, rev, sig) and is
therefore NOT an instance of the Envelope Record of Section 7.
No conformant Envelope Record is published in this zone.¶
_org-alter.truealter.com, carrying v=alter1 with org,
entity, entity-type, founded, regions, mcp-policy,
epoch, pk, and attest. It omits regulated and bootstrap.
Its pk is the same key the _mcp record carries, as step 5 of
Section 12.2.2 requires.¶
The zone is DNSSEC-signed, so the requirement of Section 8 is met by
the operator. truealter.com publishes a key-signing key and a
zone-signing key, both algorithm 13, and the parent zone holds a
corresponding DS record.¶
Implemented in code, and NOT exercised against any conformant envelope, because none is published:¶
A resolver and verification library implementing the JCS
signing-input construction of Section 7.4 and the Ed25519
signature check. It conforms to this revision on the signing
input and the signature check. It does NOT conform on two steps
of the recognition procedure of Section 12.3: it still treats the
IdentityLog cross-reference as fatal, where step 9 now says a
resolver MUST NOT abort, and it still fetches caveats over HTTPS,
which step 11 now places out of scope. Those two steps follow
revision 04. It also does not yet perform the revocation check of
step 12, so it does not refuse a claim signed under a revoked key,
and it does not check the h field against the grammar of
Section 7.3.2.¶
NOT deployed:¶
_443._tcp.mcp.truealter.com does not resolve, so no DANE TLSA
pin is published and the DANE binding of Section 9 is untested in
deployment.¶
There is no signed-tree-head federation and no witness-mirror network.¶
No inclusion proof is generated or checked anywhere. The ilr
field of Section 7.2 is published as a bare root with no proof
attached. Section 14.3 sets out what that permits.¶
The Envelope Record of Section 7 therefore has NO conformant deployment at the time of writing, in this zone or any other known to the author. It is specified, implemented in a verifier, and unpublished.¶
The deployed _alter.truealter.com record carries none of the
envelope fields that Section 7 defines, so it is not an instance of
the Envelope Record and a resolver MUST NOT treat it as one.¶
The key continuity rule of Section 13.1 is new in revision 06. No implementation of it is claimed.¶
The following pseudocode illustrates the combined recognition procedure defined in Section 12.3. It is non-normative; the normative procedure is the twelve-step algorithm in the body of this document.¶
function recognise_envelope(handle, zone):
# Step 1-2: Query + DNSSEC
response = dns_query("_alter." + zone, type=TXT, prefer=DoH)
if not response.ad_bit and not local_rrsig_validate(response):
raise UnauthenticatedResponse
# Step 3-5: Chunk reassembly + handle disambiguation + fields
records = [parse_alter_record(rr) for rr in response.rrset]
record = find(records, lambda r: r.h == handle)
if record is None or record.v != "alter1":
raise RecordNotFound
for f in ["h", "pk", "ilr", "ts", "rev", "sig"]:
if not hasattr(record, f):
raise MalformedRecord
# Step 6-7: Envelope reconstruction + JCS. Keys are the TXT
# field names; every value stays a string, ts included.
alg = signature_alg_for_prefix(record.pk) # Signature Algorithm
# Registry
envelope = {
"v": record.v,
"h": record.h,
"pk": record.pk,
"ilr": record.ilr,
"ts": record.ts,
"rev": record.rev,
"caveats": [],
"signature_alg": alg,
}
signing_input = jcs_canonicalise(envelope)
# Step 8: signature verify under the derived algorithm
if not signature_verify(alg, record.pk, record.sig,
signing_input):
raise SignatureInvalid
# Step 9: IdentityLog cross-ref. ADVISORY. Confirms the ROOT
# was published; cannot confirm THIS envelope is under that
# root, so a failure annotates and never aborts. See 12.3.
ilr_root_seen = identitylog_root_published(record.ilr)
# Step 10: DANE TLSA (if establishing MCP session)
if establishing_mcp_session(zone):
tlsa = dns_query("_443._tcp.mcp." + zone, type=TLSA)
if not tlsa_matches_endpoint(tlsa, "mcp." + zone):
raise TLSAFailure
# Step 11: Caveats are OUT OF SCOPE for this document (Sec 12.3).
# No transport and no vocabulary are specified, so the verified
# envelope carries none and the signature is checked over [].
caveats = []
# Step 12: Revocation
if identitylog_revocation_revealed(record.rev):
raise EnvelopeRevoked
return VerifiedEnvelope(record, caveats, ilr_root_seen)
¶
draft-morrison-mcp-dns-discovery-08 (October 2026):¶
One change to a record format: the handle in the h field now follows the handle-name grammar of [ALTER-URI]. It begins with a letter, admits "." so that an organisation's handle such as ~example.com can be carried, and no longer admits "_". No change to any procedure. Two new requirements: a publisher SHOULD NOT publish an envelope for an Instrument-tier handle (Section 7.3.2), and a verifier MUST NOT honour a claim signed under the key of a revoked envelope (Section 7.3.6).¶
Records in the Abstract, Section 2 and Section 16.2 that IANA provisionally registered the alter: scheme on 5 October 2026, and says in Section 19 that the verifier does not yet perform the step 12 revocation check or check the h grammar.¶
States in Section 7.3.6, the Erasure paragraph of Section 7.1.1 and step 12 of Section 12.3 that revocation takes effect when the pre-image is revealed, with no grace period, and that every claim signed under the revoked envelope's key is invalid from that moment, whenever it was signed. The epoch rotation of the _mcp record keeps its per-claim expiry grace.¶
Says in Section 7.3.8, Section 7.5 and Section 16.3 that a new envelope field is introduced only together with a new envelope version, and that resolvers ignore fields they do not know. Earlier text pointed new fields at a registry that does not exist.¶
Replaces the notes at the head of Section 14 and Section 15, which said the revision 01 and 02 considerations were retained, with sentences citing [DNSDISC-01] Sections 7 and 8 and [DNSDISC-02] Sections 10 and 11. No consideration is added or removed.¶
Strikes the sentence saying this document is what the
[AGENT-AID] mcp protocol token defers to, at the request of the
[AGENT-AID] author, whose registry points that token at the MCP
specification. Section 3 now says only that a client that
learns p=mcp may also look up _mcp.¶
Cites [ALTER-URI] for the alter: scheme, corrects the [RFC7595] section for provisional registration to Section 4, and says in Section 12.3 that an alter: URI supplies the handle and that the zone is never derived from the handle's spelling. Removes editing-history notes from the Introduction and Terminology, and trims wording in Section 3 and Section 4.¶
Rewrites Section 3 to describe each neighbouring draft by what it specifies, without characterising its intent or scope.¶
Moves accounts of earlier revisions out of the body and into this appendix, and removes commentary on the document's own candour.¶
Removes the identity field framing from the Introduction, and
cites [MORRISON-IFT] from the ~handle definition instead. Removes
two terminology notes that were editorial guidance rather than
definitions.¶
Makes entity and regulated proper subsections of
Section 6.3. States the forward-compatibility rule for unknown
regulated tokens by reference to step 4 of Section 12.2.¶
Corrects item 3 of Section 14.3, which said a malicious zone operator is caught by defence (1), which does not hold. Corrects a section reference in Appendix A. Removes the provisional-use sentence from Section 16.1.¶
Corrects the Instrument-tier description in Section 2 to match
Section 8.5 of [MORRISON-IFT], says at the h field of
Section 7.3.2 that an Instrument-tier handle has no envelope of its own,
and removes the Instrument-tier envelope example, which contradicted it.¶
Corrects statements in Section 3, Section 4 and Section 5.3.3 about what neighbouring drafts specify.¶
Removes a schema URL that does not resolve, and a fallback in Section 11 that no procedure defines.¶
Corrects revision references in Section 1, Section 5, Section 12.1 and Section 13, and replaces references to earlier record generations with section numbers.¶
Removes product terms and an undefined term from Section 2, Section 9, Section 12.2.2 and Section 15.1, and replaces a third-party name in an example.¶
Replaces the authoring organisation's own name and ABN in the examples of Section 6.3.3 and the section before it with example values.¶
draft-morrison-mcp-dns-discovery-07 (September 2026):¶
Tracks the current [AGENT-AID] revision and corrects the status
of the alter: URI scheme. No change to any record defined here.¶
Stops describing the alter: URI scheme as provisionally
registered with IANA (Section 2, Section 11,
Section 16.2). Revision 06 said it was,
and it was not. Provisional registration is now requested.¶
Moves the revision summary out of the Abstract. This appendix carries it in full.¶
Names the revision that made each change in four sentences that said "this revision" about revisions 05 and 06.¶
Describes the [AGENT-AID] record in its aid2 format, where
revision 06 still described aid1. The endpoint-proof key is now an
unpadded base64url JWK x value with its JWK thumbprint [RFC7638] as
the signature keyid, and the i rotation identifier is gone. aid1
stays valid through [AGENT-AID]'s compatibility window.¶
Points the [AGENT-AID] reference at draft-nemethi-dawn-aid, the name the document now carries.¶
draft-morrison-mcp-dns-discovery-06 (September 2026):¶
Adds a key continuity rule for the _mcp record, the first
normative change since revision 05, and corrects two statements in
the revision 05 Implementation Status section. No record format
changes and no field is added.¶
Adds Section 13.1. Every earlier revision described the
_mcp key binding as trust on first use with periodic
re-verification, and none said what a client does when the
re-verification disagrees. A client following revision 05 that
had pinned a key would accept a different one on the next
connection, which is the case of a lapsed domain registered again
by someone else. The new section covers a changed key under the
same epoch, an epoch that goes down, a declared rotation, and a
record that drops its pk.¶
States that an epoch decrease is never a conformant publisher
state (Section 5.3.7). The earlier rules covered a claim
whose epoch is below or above the record's, and nothing covered the
record's own epoch going down, which is what a new registrant
publishing epoch=0 over a pinned epoch=2 looks like.¶
Extends step 7b of Section 12.1.2 to apply the rule, and to verify against a pinned key where the record no longer carries one. The procedure's opening sentence no longer claims the algorithm of [DNSDISC-01] unchanged.¶
Adopts the graded change-of-control signals of [DOMAIN-SET] Section 6.3 for the pinned binding (Section 13.1.2), and adds [DOMAIN-SET] and [RFC9083] as informative references. [DOMAIN-SET] already specified a consumer-side rule for a lapsed and re-registered domain, and this document had none.¶
Keeps absence of a record distinct from revocation, and says the difference from [DOMAIN-SET] Section 6.4 is deliberate (Section 13.1.1). That document treats removal of a record as revocation. This one does not, for the envelope record since revision 03 and now for the pinned key binding, because clearing a pin on absence would let one suppressed resolution reset a client to first use.¶
Adds Section 14.8, which states the change-of-control
exposure for all three records, and states for the _alter record
that this document specifies no pin and that a new registrant
passes every FATAL step of Section 12.3.¶
Records in Section 19 that no implementation of the new rule is claimed.¶
The two Implementation Status corrections, both of which understated the deployment:¶
Corrects the DNSSEC statement. Revision 05 said truealter.com was
not DNSSEC-signed and that the parent zone held no DS. The zone was
signed nine days before revision 05 was filed and is signed today,
with a key-signing key and a zone-signing key at algorithm 13 and a
DS in the parent. The consequence revision 05 drew from the
erroneous statement, that no Envelope Record could be relied upon in
this zone, is withdrawn with it.¶
Records _org-alter.truealter.com as deployed. Revision 05 recorded
it as NXDOMAIN, which was accurate when filed. It has since been
provisioned and carries the field set named in the Implementation
Status section.¶
The remaining statements of that section were re-checked against the zone and against the code and are carried forward unchanged. The absent DANE TLSA pin, the absence of any conformant Envelope Record, the two recognition steps on which the verifier still follows revision 04, the absent federation and witness network, and the absence of inclusion proofs all still hold.¶
draft-morrison-mcp-dns-discovery-05 (July 2026):¶
Corrections to -04, and the record formats and procedures restated in full. No new mechanism.¶
Restores the citation of [AGENT-AID], which revision 01 carried and
revisions 02 through 04 dropped, and distinguishes it from [DNS-AID], a
different draft with the same acronym. Revision 05 also said that
this document is what the [AGENT-AID] mcp protocol token defers to.
Revision 08 strikes that sentence at the request of the
[AGENT-AID] author.¶
Gives all three record formats (Section 5, Section 6, Section 7), all three procedures (Section 12.1, Section 12.2, Section 12.3) and the caching rules (Section 13) in full. Revisions 03 and 04 incorporated the first two records and their procedures by reference to revisions 01 and 02.¶
Separates the agent protocol family from the transport binding in
the _mcp record. Revision 01 used proto for the transport.
proto now names the protocol family and transport names the
binding, which is the term the Model Context Protocol specification
uses.¶
States how to read an _mcp record published under revision 01
(Section 5.3.5). A proto value that names neither the protocol
family nor a known transport causes the record to be SKIPPED, as
revision 01 required.¶
Reconciles the _mcp grammar with its prose. The grammar admits
any token in proto and transport; proto has exactly one defined
value and transport exactly three, and the two sets are disjoint.¶
Replaces 1*VCHAR for org, entity and entity-type with a
text-value rule that admits SP and excludes only the field separator
(Section 6.2).¶
Stops every value rule in all three grammars from running past the
end of its own field. unknown-field and https-uri were defined
over *VCHAR, which includes the semicolon. qtext admits SP and
excludes the semicolon; uri-char excludes both.¶
States that unknown-field matches only a field name this document
does not define, so a defined field whose value is malformed makes
the record malformed (Section 5.2). The split-on-semicolon parse in
Section 12.1 already behaved this way.¶
Requires a publisher emitting transport to emit proto=mcp with
it (Section 5.3.5).¶
Cites each label in the IANA table (Section 16.1) to the section of this document that defines it.¶
Rewrites Section 19 against the deployed zone and code. The -04
section claimed an _org-alter record, a DANE TLSA pin, a conformant
envelope record and a signed-tree-head witness federation, none of
which existed.¶
Withdraws the claim in Section 14.3 defence (1) that ilr=
defeats envelope substitution.¶
Fixes the signing input of Section 7.4. The keys are the TXT field
names, v is inside the signed object, and ts is a JSON string.
An envelope signed under -04 does not verify under -05. No envelope
signed under -04 exists.¶
Derives signature_alg from the pk= algorithm prefix via the
registry of Section 16.7.¶
Allows a split within a key-value pair in Section 7.6, so a field longer than 255 octets can be carried.¶
Marks publication of a per-individual envelope in DNS as NOT RECOMMENDED, and forbids more than one handle at one owner name (Section 7.1, Section 7.1.1).¶
Withdraws the IdentityLog witness federation everywhere -04 asserted
it, and makes the cross-reference at step 9 of Section 12.3 advisory.
The ilr= field is kept so the wire format does not change.¶
States that a reader implementing from this document alone cannot check revocation.¶
Repairs every internal cross-reference.¶
Corrects all four references into [DNSDISC-01] and [DNSDISC-02].
The _mcp record format is Section 5 of [DNSDISC-01], not Section 3,
and its discovery procedure is Section 6, not Section 4. The
_org-alter record format is Section 6 of [DNSDISC-02], not Section
4, and its bootstrap procedure is Section 7, not Section 6.¶
Gives the _alter record two ABNF grammars (Section 7.2), one
for publisher emission and one for resolver acceptance, with the
field-cardinality rule stated beside them.¶
Reconciles Section 14.6 with step 5 of
Section 12.2. The _mcp and _org-alter keys must match;
only the envelope key of Section 7 MAY differ.¶
Removes two hand-written reference sections that duplicated the generated ones.¶
Corrects the field count to seven REQUIRED fields.¶
draft-morrison-mcp-dns-discovery-03 (April 2026):¶
Editorial corrections (retiring -02):¶
Removes the third-party-domain worked example used in -02 and replaces all instances with [RFC2606] reserved example-domain forms; no third-party operational domain appears in any illustrative DNS record in this revision.¶
Strips city and locality fields from the author front-matter block, retaining only name, organisation, and email per editorial policy.¶
Substantive additions:¶
Defines v, h, pk, ilr, ts, rev, sig fields for the
new record.¶
Introduces a mandatory DNSSEC validation requirement for
_alter.<domain> responses (Section 8).¶
Introduces a mandatory DANE TLSA [RFC6698] pin on the MCP endpoint (Section 9) for envelope-triggered MCP sessions.¶
Adds the IdentityLog cross-reference requirement (Section 10). Revision 05 withdraws it; see the -05 entry above.¶
Adds a provisional alter: URI scheme cross-reference per
[RFC7595] (Section 11).¶
Adds the envelope recognition procedure (Section 12.3), a twelve-step algorithm.¶
Adds IANA registration for _alter underscore-prefixed label
(Section 16.1) and the independent v=alter1 envelope version
namespace.¶
Adds a Signature Algorithm Registry (Section 16.7) with initial
value ed25519.¶
Adds Security Considerations for DNSSEC downgrade, TLSA pin rotation, envelope substitution, revocation opacity, clock skew, cross-record key consistency, and passive-stream coupling.¶
Adds Privacy Considerations for public handle disclosure, DNS query metadata, and revocation unlinkability.¶
Adds Examples for minimal envelope, multi-handle zone, full ~alter zone with all three records, and Instrument-tier handle.¶
Adds Implementation Status entry for the envelope reference implementation.¶
Incorporated the v01 _mcp.<domain> and v02 _org-alter.<domain>
record specifications by reference, leaving them unchanged.
Revision 05 restates both in full; see the -05 entry above.¶
draft-morrison-mcp-dns-discovery-02 (April 2026):¶
Adds the _org-alter.<domain> Org-Identity Record.¶
Defines org, entity, entity-type, founded, regions,
regulated, bootstrap, mcp-policy, epoch, pk, attest,
ext fields for the organisational record.¶
Adds the Identity Bootstrap procedure.¶
Adds IANA registration for _org-alter underscore-prefixed
label.¶
Adds version tag v=alter1 (org-alter namespace) and registry
namespace and framework token registries.¶
Adds Examples for minimal, full, regulated (DISP), and multi-regulator deployments.¶
Adds Implementation Status entry for the orgalter_discover reference library.¶
v01 _mcp.<domain> record specification is incorporated by
reference and remains unchanged.¶
draft-morrison-mcp-dns-discovery-01 (April 2026):¶
Adds Identity Field Theory grounding for epoch and scope.¶
Refines security considerations for identity assurance decay.¶
Refines privacy considerations for scope as a privacy boundary.¶
Adds Coexistence section with SEP-1959, AID, A2A.¶
Adds Implementation Status section.¶
draft-morrison-mcp-dns-discovery-00 (April 2026):¶