The short version. A public scanner checks whether a domain publishes DNS-AID records. It fails Infoblox, whose employees wrote two-fifths of the draft; it fails Cloudflare, which operates the scanner; and it fails its own website. The one domain I found passing was passing with a record type the draft does not define.
I read the IETF draft instead, published one SVCB record, and the check went green. The other two records I had drafted would have been false, and this note spends as much time on those as on the one that worked.
The public scanner at isitagentready.com checks a domain for the discovery surfaces an automated client might look for: llms.txt, an MCP endpoint, OAuth metadata, an A2A agent card. One of its checks is DNS-AID, a DNS record that tells an agent where a domain publishes its agents. On this site it reported fail, so I set out to close it. What follows is what the draft says, the one record I published, and the two I did not.
Who fails the check
First I ran the same scan against the domains you would expect to have solved this already. On August 31, 2026, the check reported fail for all of them:
infoblox.com— two of the draft’s five authors are listed under Infoblox, Inc. on its cover page.cloudflare.com— the scanner is Cloudflare’s. Its own disclaimer reads “Cloudflare assumes no liability for any actions taken or outcomes based on this automated content.”isitagentready.com— that is the scanner’s own site.dns-aid.organddnsaid.orga2aprotocol.aiagenticresourcediscovery.org
One domain in the set passed: turva.dev. I looked at what it publishes, because a single passing example is the only documentation a scanner’s predicate has.
The only domain passing was passing with the wrong record type
turva.dev passed with three HTTPS records (DNS type 65) under underscore-prefixed names: _index._agents, _a2a._agents and _mcp._agents. That is not the record the draft describes, and the substitution is not harmless.
An HTTPS record is a specialization of SVCB whose owner name is the origin being described. RFC 9460 §9.4 is explicit that a client connecting through one sets the TLS SNI and the HTTP :authority to the origin, not to the record’s TargetName. So an HTTPS record at _index._agents.example.com declares an origin whose hostname contains underscores. The draft rules that out and says why — §3.2: “The TargetName MUST be used and MUST not contain underscores as used in DNS-SD labels, as public x.509 certificates will be used in communications with the index.”
In fairness, the check accepts both types: its remediation text says “ServiceMode SVCB/HTTPS records,” and the SVCB record below passed it without objection. But the one domain that had earned a pass had earned it with the shape the draft does not define. Everyone else had published nothing at all.
SVCB and its two modes
SVCB is DNS record type 64, defined in RFC 9460. One record carries a target hostname plus a set of connection parameters: which protocols the endpoint speaks, which port, which address hints.
The first field, SvcPriority, decides which of two modes the record is in. RFC 9460 §2.4.1 makes it binary: zero means AliasMode, anything else means ServiceMode.
AliasMode (§2.4.2) points a service at another name and nothing more. Recipients MUST ignore any SvcParams present. Its primary purpose is aliasing at a zone apex, where CNAME is not allowed.
ServiceMode (§2.4.3) is the mode that carries information. Its SvcParams are the connection parameters a client will act on: alpn, port, ipv4hint, ech.
The distinction is enforced, not stylistic. Inside one RRset, an AliasMode record makes clients ignore every ServiceMode record beside it (§2.4.1). The wrong number does not degrade the answer; it discards the rest of the set.
The HTTPS record is the same machinery specialized for https://. RFC 9460 §9.1 drops the underscore prefixes at port 443, so its owner name is the origin’s hostname itself.
Why an underscored name breaks TLS
Underscore-prefixed labels are a convention, not hostnames. RFC 8552 registers them so attribute records — _dmarc, _acme-challenge, _tcp — can hang under a name without colliding with that name’s own records.
The prefix is the whole point. It puts the record in a namespace no host is meant to occupy, which is why nobody runs a web server on _dmarc.example.com.
That stays harmless until TLS is involved. It is the reason for the §3.2 rule quoted above: the name a client authenticates has to be a name a public certificate can carry.
This domain’s certificate carries two names, and the underscored one is not among them:
echo | openssl s_client -connect visibleorigin.com:443 \
-servername visibleorigin.com 2>/dev/null \
| openssl x509 -noout -subject -ext subjectAltName
# subject=CN=visibleorigin.com
# X509v3 Subject Alternative Name:
# DNS:visibleorigin.com, DNS:*.visibleorigin.comThe record itself does not fail. The handshake it sends the client into does.
An SVCB record at the same name has no such problem, because it never claims to be an origin. RFC 9460 §2.3 says a prefixed query name does not alter the origin or authority for validation.
The draft’s §3.2 sends the agent to the TargetName instead, and bars the DNS-SD underscore labels from it so a public certificate can cover it. Here that name is visibleorigin.com.
Reading the draft instead of the scanner
The document is draft-mozleywilliams-dnsop-dnsaid-02, “DNS for AI Discovery,” dated May 27, 2026 and expiring November 28, 2026. It is an individual submission: the dnsop working group has not adopted it. I read the raw text from ietf.org, not a summary. Three things came out of it.
One name in the draft is written out in full. §3.2: “An SVCB record type query for _index._agents.example.com returns a pointer to an organization-specific registry of all agents.” Every other name I had seen suggested — _mcp._agents, <agent>._agents — appears zero times in the draft. They come from the reference implementation, and from the scanner composing a name out of my own TXT record. Inferred names are not specified names, and I was not going to sign one with DNSSEC.
The SvcParams I wanted do not have numbers yet. §7.1 asks IANA to register six keys — cap, cap-sha256, policy, realm, well-known and bap — and says of all of them that “the numeric SvcParamKey values are deferred to IANA assignment.” The three I would have used are cap, well-known and bap. None can be written without inventing a number.
The ALPN token mcp is a placeholder, and the draft says so. §7.3 asks IANA to register mcp and a2a, then states of its own table that “the entries above are placeholders.” mcp is not in the IANA ALPN registry today, and it does not work — see below.
How to read the SvcParamKeys registry
SvcParams look like text and are not. In presentation format a key is a lowercase string (RFC 9460 §2.1); on the wire it is a two-byte number (§2.2), and the number is what a client parses.
For a key with no assigned number, RFC 9460 offers one escape hatch: the keyNNNNN form, where NNNNN is the numeric value. It does not help here. You still have to know the number.
The registry is public. As of September 1, 2026 the SvcParamKeys registry holds thirteen assignments, numbers 0 through 12, ending at oots. Numbers 13 through 65279 are unassigned; 65280 through 65534 are private use.
The six keys the draft asks for — cap, cap-sha256, policy, realm, well-known, bap — are not in it. They are requests, not entries.
So writing cap= today means inventing a number: an unassigned one, which squats on somebody else’s future key, or a private-use one, which no other party reads.
One mismatch, for anyone reading both. Draft §7.1 gives the policy as Standards Action per RFC 9460 §14.3.2; §14.3.2 is the registry’s initial contents, and §14.3.1 sets the policy as Expert Review.
The ALPN registry reads the same way, and settles the mcp question above: on September 1, 2026 neither mcp nor a2a appears in it.
The one record I published
_index._agents.visibleorigin.com. 300 IN SVCB 1 visibleorigin.com. alpn="h3,h2,http/1.1" port=443SVCB is DNS type 64. ServiceMode, priority 1 (RFC 9460 §2.4.1). Explicit TargetName, no underscores, and the certificate served for that name is CN=visibleorigin.com, valid. Check it:
dig +short SVCB _index._agents.visibleorigin.com @1.1.1.1
# 1 visibleorigin.com. alpn="h3,h2,http/1.1" port=443
dig +dnssec SVCB _index._agents.visibleorigin.com @1.1.1.1 | grep -m1 '^;; flags'
# ;; flags: qr rd ra ad; <- 'ad' means the resolver validated the signatureThe alpn list could most easily have been decoration. h2 and http/1.1 I measured with a TLS handshake against the edge. h3 is declared twice on this domain — by the edge, in the alt-svc: h3=":443" header, and by me, in the apex HTTPS record, alpn="h3,h2", signed in this same zone:
dig +short HTTPS visibleorigin.com @1.1.1.1
# 1 . alpn="h3,h2" ipv4hint=... ech=... ipv6hint=...Caveat: the curl on the box I work from has no HTTP/3, so I did not complete a QUIC handshake myself. For h3 I am taking those two declarations at their word — one of them mine — instead of a measurement, and I would rather say so than let you assume I tested it.
The two records I rejected
This half of the work shows up in no checkbox.
A hostname that does not exist
The obvious next record described an agent at audit.visibleorigin.com. That name does not resolve. The trap is that it looks alive: the wildcard certificate covers it, so TLS completes cleanly and the failure surfaces one layer up, in HTTP. Force a connection to the edge for that hostname, then for a name you made up:
IP=$(dig +short A visibleorigin.com @1.1.1.1 | head -1)
curl -s -o /dev/null -w '%{http_code}\n' \
--resolve audit.visibleorigin.com:443:$IP https://audit.visibleorigin.com/
# 530 (body: "error code: 1016")
curl -s -o /dev/null -w '%{http_code}\n' \
--resolve zzz-does-not-exist.visibleorigin.com:443:$IP https://zzz-does-not-exist.visibleorigin.com/
# 530 (body: "error code: 1016")Byte for byte, the real agent name and the invented one produce the same response. The control request matters here, because this zone answers NOERROR with no data for names that do not exist rather than NXDOMAIN — synthesized “black lie” NSEC — so a missing name never announces itself as missing. Query it with +dnssec and the NSEC type bitmap for audit.visibleorigin.com lists RRSIG NSEC TYPE128 and nothing else: no A, no AAAA.
Publishing that record would have meant signing a false statement with DNSSEC, on the site whose entire pitch is that you can check what it says.
Why NOERROR does not mean the name exists
On this zone, absence does not announce itself. That is why the invented hostname above was queried alongside the real one.
Ask this zone for a name that was never in it and NXDOMAIN never arrives. You get NOERROR, no answer records, and a signed NSEC.
dig @1.1.1.1 +dnssec A zzz-nope-9q2.visibleorigin.com | grep -E 'status|TYPE128'
# ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58331 <- the id differs every run
# zzz-nope-9q2.visibleorigin.com. 1800 IN NSEC \000.zzz-nope-9q2.visibleorigin.com. RRSIG NSEC TYPE128On September 1, 2026, 1.1.1.1, 8.8.8.8 and 9.9.9.9 all returned NOERROR for that invented name.
TYPE128 in the bitmap is not noise. IANA assigned 128 to NXNAME in 2024, the “NXDOMAIN indicator for Compact Denial of Existence.”
It marks a name that does not exist at all, as against one that exists without records of the type asked for. My dig prints a bare number: its type table is older than the assignment.
The effect on anyone auditing from outside is what matters. A typo and a real name with no records of that type return the same status code.
So every negative result needs a control. Query a name you invented, then compare the two answers.
If they come back identical, the name you were checking is indistinguishable from one that was never there. On this zone that is the only signal you get.
Over HTTP the discipline is the same. Every request in the free check is written out as the command that made it, so you get your own answer instead of mine.
That costs one extra query. Skipping it is how an audit reports a clean result it never measured.
An ALPN token the server refuses
The second rejection is alpn="mcp". The draft asks IANA to register the token and calls its own table a placeholder; offer it in the ClientHello and no ALPN is negotiated:
echo | openssl s_client -connect visibleorigin.com:443 -servername visibleorigin.com -alpn mcp 2>/dev/null | grep -i alpn
# No ALPN negotiated
echo | openssl s_client -connect visibleorigin.com:443 -servername visibleorigin.com -alpn h2 2>/dev/null | grep -i alpn
# ALPN protocol: h2Advertising mcp would point a conforming client at a connection this server cannot complete. Leaving it out cost nothing: turva.dev, the only already-passing domain in my set, also publishes a purely transport-level alpn.

What happened when the record went live
The scanner moved dnsAid from fail to pass: serviceRecordCount 0 → 1, dnssecValidated false → true, validServiceMode true, validationIssues empty. My written estimate beforehand was about a 60% chance, and it was not the deciding factor. The stopping rule came first: if the check stayed red, nothing changes — no falling back to _mcp._agents or any other name that exists in no revision of the draft. The record went up because it is true, not because it scores.
| What it measures | Before | After |
|---|---|---|
serviceRecordCount — ServiceMode records found across the nine queries the check makes | 0 | 1 |
dnssecValidated — whether a signature on those records validated | false | true |
aliasRecordCount — AliasMode records found, the other SVCB mode, which this zone does not publish | 0 | 0 |
txtIndexEntryCount — TXT index entries found; the one entry is the dangling reference described below | 1 | 1 |
records[0].validServiceMode — whether the record parses as ServiceMode (priority > 0) | no record | true |
records[0].validationIssues — objections raised against that record | no record | [] (none) |
From the dnsAid check returned by the isitagentready.com scan API, run against https://visibleorigin.com before and after the record was published. Both scans ran on August 31, 2026 — scannedAt 21:12:09Z and 22:19:22Z. The first four values are counters in the check’s details object, aggregated over nine queries across four names. The last two are fields of a record inside details.records, and before publication that array was empty. That is also why dnssecValidated read false: there was no signed service record to validate. The TXT entry is listed as audit:mcp; the scanner strips the agents= prefix off the record on the wire.
Of the nine domains I scanned by hand that day, this is the only one passing with an SVCB record; turva.dev passes with HTTPS. I have not scanned the rest of the internet, so I am not claiming to be first at anything.
What this does not mean
It does not make the site discoverable. The record enables nothing new. It says there is an HTTPS server at visibleorigin.com:443, which the A, AAAA and apex HTTPS records already said. Any sentence of the form “this makes us discoverable to AI agents” has nothing behind it.
It is not “standards compliant.” _agents and _index are not in the IANA underscored node names registry; §7.2 of the draft only requests them. The wording I will keep using: an SVCB record syntactically conformant with RFC 9460, under a name proposed by an active individual Internet-Draft that dnsop has not adopted, whose labels are not yet registered with IANA.
The chain on this domain is not complete, and here is the defect. A TXT record at the same name still reads agents=audit:mcp — announcing an agent called audit whose primary owner is the audit.visibleorigin.com that returns 530 above. That record predates this work. It comes down rather than being made true with a hostname I have no use for, and this paragraph will carry the date it went. Until then the chain has a dangling reference, visible in one query:
dig +short TXT _index._agents.visibleorigin.com @1.1.1.1
# "agents=audit:mcp"That TXT format is not from the draft either. The string agents= appears zero times in the draft text; the encoding it hints at sits in the section titled “Future Work and Experimental Mechanisms,” deferred to a future revision. It comes from the dns-aid-core reference implementation.
What would have to happen
One record on one domain is not adoption. Three things would have to happen before DNS-AID is worth an operator’s attention, and none of them is mine to do.
First, dnsop would have to adopt the draft. It is an individual submission today; the datatracker page carries the current status, and this revision expires on November 28, 2026 unless it is replaced.
Second, IANA would have to register the labels §7.2 asks for. In the underscored node names registry today, the only protocol label registered for SVCB is _dns.
Third, something would have to query it. A record nothing reads is not discovery, and I have no numbers to offer here: query analytics were not part of this work, so I cannot tell you who has asked.
None of the three has a date attached, and this may never matter at all. Nothing on this page assumes otherwise.
I have no standing in any of those three steps. This is John Patzi, working alone with one zone file, a text editor and a copy of the draft.
DNS-AID: frequently asked questions
What is DNS-AID?
DNS-AID, “DNS for AI Discovery,” is a proposal for publishing in DNS where a domain’s agents are and what they speak. It is an Internet-Draft — draft-mozleywilliams-dnsop-dnsaid-02, dated May 27, 2026 — an individual submission that dnsop has not adopted. It is not a standard, and its labels have no IANA registration either: Section 7.2 asks for _agents and _index in the underscored node names registry established by RFC 8552, and a request is all it is.
Does a DNS-AID record make my site discoverable to AI agents?
No. Under a name the draft proposes, it repeats what this domain’s address records and its apex HTTPS record had been publishing all along, so it enables nothing new. Whether anything ever asks for that name I cannot tell you: I have no query data for this zone and did not measure it. Publishing early is a true statement, not a traffic source. What a machine gets when it reads your site over HTTP is a separate question, and the one a free check answers.
What DNS record do I publish for DNS-AID?
For the organizational index, one name is written out in draft-02: _index._agents.{domain}, queried for SVCB. Section 3.2 requires an explicit TargetName carrying no underscores, because the index is reached over TLS and no public certificate can carry an underscored name. The draft writes out other names for other jobs, but _mcp._agents is not among them — it appears zero times. Mine reads: _index._agents.visibleorigin.com. 300 IN SVCB 1 visibleorigin.com. alpn="h3,h2,http/1.1" port=443
SVCB or HTTPS record — which one does DNS-AID use?
SVCB, type 64. Every discovery record the draft defines is SVCB; Section 4 offers TXT only as a fallback it argues against, and the string “HTTPS” occurs three times in the whole document — twice for DNS over HTTPS, once inside a cited RFC title. Never as a record to publish. The reason matters more than the count: under RFC 9460 §9.4 an HTTPS record’s owner name is the origin a client connects to, and an underscored origin is one no public certificate can carry.
Does DNS-AID require DNSSEC?
Not strictly. Section 6.4 says DNS-AID is deployable without DNSSEC, but that its authenticity guarantees depend on a validated path, and that consumers SHOULD refuse to act on records they cannot verify. Signing raises the stakes rather than lowering them: a signed record that is false is a false statement with your zone key on it. Verify with dig +dnssec and look for the ad flag in the response.
Is mcp a registered ALPN protocol ID?
No. Neither mcp nor a2a has an entry in the IANA ALPN registry; Section 7.3 of the draft requests both, then marks its own table of them as placeholders. Measured against this site’s edge on August 31, 2026: offering mcp in the ClientHello negotiated no ALPN, while h2 negotiated h2. A record advertising it would send a conforming client into a handshake this server cannot finish.
The general shape of this
A scoring tool is not a specification. This one is run by a company that fails its own check, scoring domains against a draft whose authors’ employer fails it too, and the only passing domain I could find was passing in a way the draft does not describe. Optimizing against the scanner would have produced two records any stranger with dig and curl could disprove. Reading the primary source produced one that survives those same commands, plus a known defect I would rather write down than leave for you to find.
The transferable part is not the record. It is that a green checkbox and a true statement come apart, and on any site they come apart in the same places: a header set in the CMS that no cache layer ever serves, a rule that returns 403 to a crawler nobody requested the site as, one line of server configuration that took the blame for a fault it did not cause. Finding those from outside, on somebody else’s domain, is the work I do for money.
A record like this is one more place where a site describes itself, and every such place can go stale: I changed one number on one page, and five other places went on saying the old one.
Every command above runs against this domain. If one of them returns something other than what I said it does, that is worth an email. If it is your own domain you want read from outside, that is what the free check is: you send the domain, I request its homepage as five named crawlers, one at a time, and send back a written report of what each one got.



