Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

aid-resolver

A small, faithful AID (Agent Identity & Discovery) v2 resolver and client in TypeScript. Given a domain, it answers the one question AID exists to answer:

"Where is the agent, and which protocol should I speak?"

It implements the DNS-first discovery algorithm, the TXT record format, the .well-known/agent fallback, and PKA endpoint proof (RFC 9421 HTTP Message Signatures keyed by an RFC 7638 JWK thumbprint) from the AID v2.0.0 specification.

Zero runtime dependencies — only Node's built-in dns, crypto, url, and global fetch (Node >= 20).

This is an independent implementation built against the public spec, not the official SDK. For production, see the reference package @agentcommunity/aid.

What AID is

A provider publishes a single DNS TXT record at _agent.<domain>:

_agent.example.com. 300 IN TXT "v=aid2;p=mcp;u=https://api.example.com/mcp;a=oauth2_code;s=Example AI Gateway"

A client resolves that record to learn the endpoint (u), protocol (p), auth hint (a), and optionally an Ed25519 endpoint-proof key (k). Richer protocols (MCP, A2A, OpenAPI, OAuth, …) take over from there.

Record keys (AID v2 §2.1)

Key Alias Required Meaning
version v yes Must be aid2
uri u yes https://, wss://, or local locator (docker:/npx:/pip:)
proto p yes Protocol token (mcp, a2a, openapi, grpc, graphql, websocket, local, zeroconf, ucp)
auth a rec. Auth hint (none,pat,apikey,basic,oauth2_device,oauth2_code,mtls,custom)
desc s opt. Short display text
docs d opt. Absolute https:// docs URL
dep e opt. ISO 8601 UTC deprecation timestamp
pka k opt. Unpadded base64url Ed25519 public key (JWK x, 32 bytes)

Requirements

  • Consuming the built library (dist/): Node >= 20 (uses global fetch, Buffer base64url, and Ed25519 from node:crypto).
  • Developing (running the .ts sources directly via pnpm test / pnpm aid): Node >= 22.18, which strips TypeScript types natively with no extra tooling.

Install

pnpm install        # dev deps only: typescript, @types/node (no build scripts)
pnpm test           # run the test suite (node --test, native TS)
pnpm aid -- resolve supabase.agentcommunity.org   # run the CLI from source

To build the publishable JS + type declarations and run the aid binary:

pnpm build
node dist/cli.js resolve supabase.agentcommunity.org

CLI

aid resolve <domain> [--protocol mcp] [--require-pka] [--no-well-known] [--timeout 5000] [--json]
aid parse "<txt record>" [--allow-unknown-proto] [--json]
aid keyid <base64url-k>          derive the RFC 7638 keyid (thumbprint)
aid pka <domain>                 resolve, then verify endpoint proof over HTTPS

Examples:

aid resolve supabase.agentcommunity.org
aid parse "v=aid2;u=https://api.example.com/mcp;p=mcp;a=pat;s=Example"
aid keyid JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs
# -> poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U

Library

import { discover, parse, AidError } from 'aid-resolver';

try {
  const { record, ttl, queryName, trustSource } = await discover('supabase.agentcommunity.org');
  console.log(record.proto, record.uri, record.desc);
  console.log(`via ${queryName} (${trustSource}, ttl ${ttl}s)`);
} catch (e) {
  if (e instanceof AidError) console.error(e.code, e.errorCode, e.message);
  else throw e;
}

// Parse a raw TXT string without touching DNS:
const rec = parse('v=aid2;u=https://api.example.com/mcp;p=mcp');

PKA endpoint proof

When a record carries k, the resolver computes the expected keyId (RFC 7638 thumbprint). To actually prove the endpoint controls the key, run the nonce-bound handshake:

import { discover, fetchPkaProof } from 'aid-resolver';

const { record } = await discover('example.com', { pkaPolicy: 'require' });
const proof = await fetchPkaProof({ k: record.pka!, uri: record.uri });
console.log(proof.ok ? 'endpoint verified' : `failed: ${proof.reason}`);

verifyPkaResponse() is exposed separately as a pure function (no I/O) if you already hold the response headers — see src/pka.ts.

Error codes (AID v2 §2.3, Appendix A)

Code Name
1000 ERR_NO_RECORD
1001 ERR_INVALID_TXT
1002 ERR_UNSUPPORTED_PROTO
1003 ERR_SECURITY
1004 ERR_DNS_LOOKUP_FAILED
1005 ERR_FALLBACK_FAILED

How it maps to the spec

Spec section Where
§2.1 TXT format, aliases, forbidden keys src/parse.ts, src/registry.ts
§2.3 discovery algorithm, version partition, ambiguity src/resolve.ts (selectFromCandidates)
§2.4 exact-host (no parent walk) src/resolve.ts (normalizeDomain, single query)
§3.3 enterprise PKA policy (if-present/require) src/resolve.ts (enforcePka)
Appendix B PKA handshake (RFC 9421 / 7638) src/pka.ts
Appendix C .well-known/agent fallback src/resolve.ts (resolveViaWellKnown)

Scope & known limitations

Implemented: v2 parse + validation, DNS discovery, version preference, ambiguity detection, exact-host semantics, .well-known fallback with its guardrails (HTTPS-only, no redirects, JSON content-type, 64 KB cap), PKA key decoding + thumbprint, and full RFC 9421 signature verification for the fixed aid-pka-v2 component set.

Deliberately out of scope for this small build:

  • TXT TTL. Node's stdlib DNS API doesn't expose the record TTL, so DNS hits report DNS_TTL_MIN (300s). Swap in a raw DNS library (dns-packet, dns2) to surface the real TTL.
  • DNSSEC validation (dnssec=require) and downgrade detection against retained previous state — the option surface is acknowledged but not enforced.
  • Legacy aid1 PKA (multibase z… keys + i/kid) — aid1 core fields parse, but the v1 endpoint-proof profile is not implemented.
  • local execution — the resolver returns docker:/npx:/pip: locators but never runs them (the spec requires explicit consent + sandboxing).

License

MIT

About

A small, faithful AID (Agent Identity & Discovery) v2 resolver/client in TypeScript — DNS discovery, .well-known fallback, and PKA endpoint proof.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages