Skip to main content

A Python library for building NANDA-compatible AI agent registries

Project description

SM Bridge

A Python library for building NANDA-compatible AI agent registries.

NANDA (Network of AI Agents in Decentralized Architecture) is the protocol for federated AI agent discovery and communication. This library provides the primitives needed to make your agent registry interoperable with the NANDA ecosystem.

Features

  • NANDA AgentFacts Models - Pydantic models implementing the projnanda/agentfacts-format specification
  • FastAPI Router - Drop-in endpoints for /nanda/index, /nanda/resolve, /nanda/deltas
  • Delta Store - Change tracking for registry synchronization
  • Converter Interface - Abstract pattern for integrating with your existing registry

Installation

pip install git+https://github.com/Sharathvc23/sm-bridge.git

Or install from source:

git clone https://github.com/Sharathvc23/sm-bridge
cd sm-bridge
pip install -e .

Quick Start

Basic Usage

from fastapi import FastAPI
from sm_bridge import SmBridge, SimpleAgent

# Create the bridge
bridge = SmBridge(
    registry_id="my-registry",
    provider_name="My Company",
    provider_url="https://example.com",
    base_url="https://registry.example.com"
)

# Register agents
bridge.register_agent(SimpleAgent(
    id="my-agent",
    name="My Agent",
    description="An agent that does things",
    namespace="production",
    labels=["chat", "tool-use"],
    skills=[
        {"id": "summarize", "description": "Summarizes text"},
        {"id": "translate", "description": "Translates between languages"}
    ]
))

# Mount routers
app = FastAPI()
app.include_router(bridge.router)            # /nanda/* endpoints
app.include_router(bridge.wellknown_router)   # /.well-known/nanda.json (RFC 8615)

This gives you:

  • GET /nanda/index - List all public agents (with correct total_count for pagination)
  • GET /nanda/resolve?agent=my-agent - Resolve a single agent
  • GET /nanda/deltas?since=0 - Get changes for sync
  • GET /.well-known/nanda.json - Registry discovery (RFC 8615 compliant)

Custom Registry Integration

For existing registries with their own data models:

from sm_bridge import (
    AbstractAgentConverter,
    SmAgentFacts,
    SmProvider,
    SmEndpoints,
    SmCapabilities,
    SmSkill,
    DeltaStore,
    create_sm_router,
)
from typing import Iterator

class MyRegistryConverter(AbstractAgentConverter):
    def __init__(self, db_connection):
        super().__init__(
            registry_id="my-registry",
            provider_name="My Company",
            provider_url="https://example.com"
        )
        self.db = db_connection
    
    def to_sm(self, agent) -> SmAgentFacts:
        return SmAgentFacts(
            id=f"did:web:example.com:agents:{agent.id}",
            handle=self.build_handle(agent.namespace, agent.id),
            agent_name=agent.display_name,
            label=agent.category,
            description=agent.description,
            version=agent.version,
            provider=self.build_provider(),
            endpoints=SmEndpoints(static=[agent.endpoint_url]),
            capabilities=SmCapabilities(modalities=agent.capabilities),
            skills=[SmSkill(id=s.id, description=s.desc) for s in agent.skills],
            metadata={
                "x_my_registry": {
                    "internal_id": agent.internal_id,
                    "created_at": agent.created_at.isoformat(),
                }
            }
        )
    
    def list_agents(self, limit: int, offset: int) -> Iterator:
        return self.db.query_agents(limit=limit, offset=offset)
    
    def get_agent(self, agent_id: str):
        return self.db.get_agent(agent_id)
    
    def is_public(self, agent) -> bool:
        return agent.visibility == "public"

# Create router with custom converter
converter = MyRegistryConverter(db_connection)
delta_store = DeltaStore()

nanda_router, wellknown_router = create_sm_router(
    converter=converter,
    delta_store=delta_store,
    registry_id="my-registry",
    base_url="https://registry.example.com",
    provider_name="My Company",
    provider_url="https://example.com"
)

app = FastAPI()
app.include_router(nanda_router)
app.include_router(wellknown_router)

Models

SmAgentFacts

The core data structure for agent metadata:

from sm_bridge import SmAgentFacts

facts = SmAgentFacts(
    id="did:web:example.com:agents:my-agent",
    handle="@my-registry:production/my-agent",
    agent_name="My Agent",
    label="assistant",
    description="An AI assistant",
    version="1.0.0",
    provider=SmProvider(
        name="My Company",
        url="https://example.com"
    ),
    endpoints=SmEndpoints(
        static=["https://api.example.com/agents/my-agent"]
    ),
    capabilities=SmCapabilities(
        modalities=["text", "tool-use"],
        authentication=SmAuthentication(methods=["did-auth"])
    ),
    skills=[
        SmSkill(
            id="urn:my-registry:cap:summarize:v1",
            description="Summarizes long documents",
            inputModes=["text"],
            outputModes=["text"]
        )
    ],
    metadata={
        "x_my_registry": {
            "custom_field": "custom_value"
        }
    }
)

Handle Format

NANDA handles follow the format @registry:namespace/agent-id:

handle = SmAgentFacts.create_handle(
    registry="my-registry",
    namespace="production", 
    agent_id="my-agent"
)
# Returns: "@my-registry:production/my-agent"

Delta Store

Track changes for registry synchronization:

from sm_bridge import DeltaStore, SmAgentFacts

store = DeltaStore()

# Record an agent creation/update
delta = store.add("upsert", agent_facts)
print(f"Recorded delta with seq={delta.seq}")

# Get all changes since seq 0
deltas = store.since(0)

# Get next sequence number for polling
next_seq = store.next_seq

For production, extend PersistentDeltaStore to persist to a database:

from sm_bridge import PersistentDeltaStore

class PostgresDeltaStore(PersistentDeltaStore):
    def __init__(self, dsn: str):
        super().__init__()
        self.conn = psycopg2.connect(dsn)
    
    def _persist(self, delta):
        # INSERT INTO nanda_deltas ...
        pass
    
    def _load_since(self, seq):
        # SELECT * FROM nanda_deltas WHERE seq > ...
        pass

MCP Tools

Advertise MCP tools that agents can use:

from sm_bridge import SmBridge, SmTool

bridge = SmBridge(
    registry_id="my-registry",
    provider_name="My Company",
    provider_url="https://example.com",
    tools=[
        SmTool(
            tool_id="search",
            description="Search the web",
            endpoint="https://api.example.com/mcp/search",
            params=["query", "limit"]
        ),
        SmTool(
            tool_id="calculate",
            description="Perform calculations",
            endpoint="https://api.example.com/mcp/calculate",
            params=["expression"]
        )
    ]
)

Registry Discovery

The library serves /.well-known/nanda.json at the domain root (RFC 8615) via the separate wellknown_router:

{
  "registry_id": "my-registry",
  "registry_did": "did:web:registry.example.com",
  "namespaces": ["did:web:example.com:*"],
  "index_url": "https://registry.example.com/nanda/index",
  "resolve_url": "https://registry.example.com/nanda/resolve",
  "deltas_url": "https://registry.example.com/nanda/deltas",
  "tools_url": "https://registry.example.com/nanda/tools",
  "provider": {
    "name": "My Company",
    "url": "https://example.com"
  },
  "capabilities": ["agentfacts", "deltas", "mcp-tools"]
}

Federating with NANDA

To join the NANDA network:

  1. Deploy your registry with the NANDA bridge endpoints
  2. Ensure /.well-known/nanda.json is accessible
  3. Contact the MIT NANDA team to register as a federated peer
  4. (Optional) Implement incremental sync or gossip mechanisms for real-time or near-real-time federation

AI Catalog gateway

create_gateway_router serves the AI Catalog discovery endpoints for the agents in a DeltaStore, alongside the /nanda/* router (the two surfaces are independent):

from fastapi import FastAPI
from sm_bridge import DeltaStore, create_gateway_router

delta_store = DeltaStore()

app = FastAPI()
app.include_router(
    create_gateway_router(delta_store, base_url="https://reg.example.com", domain="example.com")
)
Endpoint Returns
GET /.well-known/ai-catalog.json CatalogDocument — all agents
GET /agents/{slug} CatalogEntry — a pointer to the agent's card
GET /cards/{slug}.json A2A AgentCard (full SmAgentFacts included under _meta)

Each SmAgentFacts is translated into a CatalogEntry and an A2A AgentCard whose url is the agent's runtime. Point a NANDA index at base_url (as a hosting_path=registry entry) to make the agents discoverable through the AI Catalog flow.

Related Packages

Package Question it answers
sm-model-provenance "Where did this model come from?" (identity, versioning, provider, NANDA serialization)
sm-model-card "What is this model?" (unified metadata schema — type, status, risk level, metrics, weights hash)
sm-model-integrity-layer "Does this model's metadata meet policy?" (rule-based checks)
sm-model-governance "Has this model been cryptographically approved for deployment?" (approval flow with signatures, quorum, scoping, revocation)
sm-bridge (this package) "How do I expose this to the NANDA network?" (FastAPI router, AgentFacts models, delta sync)

License

MIT


Personal research contributions aligned with Project NANDA standards. Stellarminds.ai

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sm_bridge-0.3.1.tar.gz (20.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sm_bridge-0.3.1-py3-none-any.whl (24.4 kB view details)

Uploaded Python 3

File details

Details for the file sm_bridge-0.3.1.tar.gz.

File metadata

  • Download URL: sm_bridge-0.3.1.tar.gz
  • Upload date:
  • Size: 20.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sm_bridge-0.3.1.tar.gz
Algorithm Hash digest
SHA256 798b761c0c9443280b39a441e0bbd7736d02fca540bbdf81450d8fb2e1f0838b
MD5 03b35e177e9876d5348170b5e8e29c61
BLAKE2b-256 a83389238689e5cf8ac13e72c446e432bf54dd7f5ef9a8dabd42dd3eb9abb1c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_bridge-0.3.1.tar.gz:

Publisher: release.yml on Sharathvc23/sm-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sm_bridge-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: sm_bridge-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 24.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sm_bridge-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a2a30f91c19dd09ed36d5ceae6a954045c6b6a595f0fc7aa636cf3f8be3235ee
MD5 efbb8c24aad4ac08eb5ed05b154dfb03
BLAKE2b-256 bc1fe0980e8eb6aa182951e1e28086ce13bfbbeabe6438334a800a153a105f30

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_bridge-0.3.1-py3-none-any.whl:

Publisher: release.yml on Sharathvc23/sm-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page