hip-0069

HIP-69: Service Discovery & Auto-Bridge. Status Active. Hanzo's own standard — read this before implementing against it.

HIP-0069: Service Discovery & Auto-Bridge

Abstract

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.

Specification

Service type

_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.

TXT record

| 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 |

Per-role contracts

Each role MUST accept the listed methods over its declared proto.

role=mcp

resources/list, resources/read

role=iam (Hanzo IAM)

iam.session.refresh, iam.session.revoke

role=kms (key store + sign)

kms.encrypt, kms.decrypt, kms.key.generate/list/delete

role=mpc (threshold signing)

role=base (record store, IAM-native)

base.subscribe

role=engine (LLM serving)

engine.tokenize, engine.models.list

role=browser (extension or browser endpoint)

hanzo.screenshot

role=node (Hanzo Node)

role=desktop (Electron host)

role=gateway (api.hanzo.ai-style ingress, see HIP-0068)

Routes follow the platform's /v1/<role>/* convention.

role=static (CDN-style asset serving)

hanzo-mcp auto-bridge

hanzo-mcp MUST:

  1. On startup, after registering its built-in tools, browse

_hanzo._tcp.local. for ≥ 2 s.

  1. For every peer service whose role appears in the role enum (and

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).

  1. Re-poll every 30 s. Register new peers; deregister vanished peers.
  2. NOT register tools from the local server (skip on server_id match).

For role=mcp peers, tools merge in unprefixed (deduplicated by name) so multiple cooperating MCPs appear as one surface.

Single source of truth

Every binding (Python, TypeScript, Go, Rust, Swift) MUST own:

…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) |

Backwards compatibility

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).

Reference implementation

expand_mcp_with_neighbors for the auto-bridge.

~/work/zap/mdns/SPEC.md.

Security considerations

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=osage services without explicit operator opt-in.

Adoption order

  1. Python: hanzo-mcp, hanzo-tools-browser ✓ (shipped)
  2. TypeScript / Node: hanzo-iam, hanzo-desktop, @hanzo/extension
  3. Go: hanzo-kms, hanzo-base, hanzo-mpc, hanzo-ingress,

hanzo-gateway, hanzo-static

  1. Rust: hanzo-engine, hanzo-node
  2. Swift: future iOS / macOS native clients

Each 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.