HIP-69: Service Discovery & Auto-Bridge. Status Active. Hanzo's own standard — read this before implementing against it.
Every Hanzo-domain service on the local network advertises itself via multicast DNS (RFC 6762) under one canonical service type. hanzo-mcp auto-discovers neighbours, fetches their tool manifests, and exposes each as a namespaced tool family on its own MCP surface. New service joining the LAN → its tools light up in Claude automatically. Service leaves → tools drop on the next refresh.
This HIP closes the gap between HIP-007 (ZAP transport), HIP-0010 (MCP integration) and HIP-0068 (Ingress), removing every hard-coded URL, port range, lockfile registry and service-name env-var from the Hanzo stack.
_hanzo._tcp.local.
ONE type for the entire mesh. Roles differentiate via TXT, not by service-type. A consumer that wants e.g. only role=kms browses once and filters.
| key | required | example | |----------------|----------|----------------------------------------| | role | ✓ | mcp / iam / kms / mpc / base / engine / browser / node / desktop / gateway / static | | server_id | ✓ | kms-laptop.local-12345 | | org | default hanzo | hanzo / lux / zoo / osage | | version | ✓ | 0.5.1 | | proto | ✓ | zap/1 / http/1.1 / grpc/1 | | capabilities | ✓ | sign,verify,encrypt | | agent_label | | kms-prod | | auth | default none | none / iam / mtls |
Each role MUST accept the listed methods over its declared proto.
role=mcptools/list, tools/call, prompts/list, prompts/get, resources/list, resources/read
role=iam (Hanzo IAM)iam.login, iam.token.exchange, iam.user.get, iam.user.list, iam.session.refresh, iam.session.revoke
/v1/iam/*role=kms (key store + sign)kms.kv.get/put/list/delete, kms.sign, kms.verify, kms.encrypt, kms.decrypt, kms.key.generate/list/delete
auth=iam or auth=mtls REQUIREDrole=mpc (threshold signing)mpc.session.start/join/contribute/finalize/statuscapabilities lists supported curves (secp256k1,ed25519,bls12-381)role=base (record store, IAM-native)base.collection.list/get, base.record.list/get/create/update/delete, base.subscribe
role=engine (LLM serving)engine.completion, engine.chat, engine.embed, engine.tokenize, engine.models.list
role=browser (extension or browser endpoint)Page.navigate, Runtime.evaluate, hanzo.listTabs, hanzo.screenshot
role=node (Hanzo Node)node.status, node.peers.list, node.task.submit/statusrole=desktop (Electron host)desktop.window.list/focus, desktop.notify, desktop.shell.openrole=gateway (api.hanzo.ai-style ingress, see HIP-0068)proto=http/1.1; mDNS used only for LAN-local discovery. Routes follow the platform's /v1/<role>/* convention.
role=static (CDN-style asset serving)proto=http/1.1; capabilities: etag,range,gzip,brotlihanzo-mcp auto-bridgehanzo-mcp MUST:
_hanzo._tcp.local. for ≥ 2 s.
whose org matches the local org or is unspecified), open a ZAP handshake, read the tool manifest from MSG_HANDSHAKE_OK, and register every tool under the namespace {role}.{toolName} (e.g. iam.login, kms.sign).
server_id match).For role=mcp peers, tools merge in unprefixed (deduplicated by name) so multiple cooperating MCPs appear as one surface.
Every binding (Python, TypeScript, Go, Rust, Swift) MUST own:
_hanzo._tcp.local.…in ONE module per language. No hand-rolled mDNS records anywhere in the tree.
| language | package | |--------------|-------------------------------------------------------------| | Python | hanzo-zap-mdns (pip install) | | TypeScript | @hanzo/zap-mdns (npm) | | Go | github.com/hanzoai/zap-mdns-go | | Rust | hanzo-zap-mdns (crates.io) | | Swift | HanzoZapMDNS (SwiftPM) |
Through 2026-Q3 a service MAY also advertise _hanzo-zap._tcp.local. (legacy ZAP-only sub-type). After 2026-Q4 the canonical _hanzo._tcp.local. is the only required record.
The hard-coded port ranges and lockfile registries SHOULD be removed once every consumer ships a binding update. The [9999..9995] port-probe in @hanzo/extension MAY remain as a fallback for offline hosts (no mDNS responder running).
~/work/zap/mdns/ — hanzo_zap_mdns package, including expand_mcp_with_neighbors for the auto-bridge.
~/work/zap/mdns/SPEC.md.
Roles that handle secrets (kms, iam, base) MUST set auth=iam or auth=mtls; consumers MUST honour the auth field and refuse unauthenticated requests.
negotiation; consumers MUST verify each call against the peer's actual auth-checked tool list.
org SHOULD be honoured: an org=lux consumer SHOULD NOT auto-bridge org=osage services without explicit operator opt-in.
hanzo-mcp, hanzo-tools-browser ✓ (shipped)hanzo-iam, hanzo-desktop, @hanzo/extensionhanzo-kms, hanzo-base, hanzo-mpc, hanzo-ingress, hanzo-gateway, hanzo-static
hanzo-engine, hanzo-nodeEach adoption lands as a 5-line change in the service's startup path — import the binding, call publish(port, role, server_id, …). The canonical example for each language ships in the binding repo's examples/ directory.