Python SDK for the Network Agent Identity Standard (NAIS).
NAIS lets AI agents publish discoverable identities via DNS TXT records and .well-known/agent.json manifests. Each agent exposes an MCP (Model Context Protocol) endpoint that speaks JSON-RPC 2.0, making it straightforward for any client to find and call agent tools.
This SDK handles the full workflow: resolve a domain, inspect the manifest, and invoke tools -- in three lines of code.
pip install nais-sdkimport nais
# Resolve an agent by domain
agent = nais.resolve("weatheragent.nais.id")
print(agent.name) # "Weather Agent"
print(agent.get_endpoint()) # "https://weatheragent.nais.id/mcp"
print(agent.get_capabilities()) # [{"name": "forecast", ...}]
# Invoke a tool
result = agent.invoke("forecast", {"city": "New York"})
print(result)Resolve a NAIS domain and return a NaisAgent object. Uses the public resolver at https://resolver.nais.id/resolve.php by default.
agent = nais.resolve("weatheragent.nais.id")Convenience function that resolves a domain and returns just the manifest data dictionary.
manifest = nais.get_manifest("weatheragent.nais.id")
print(manifest["name"]) # "Weather Agent"Validate a manifest dictionary. Returns {"valid": True/False, "errors": [...]}.
result = nais.validate_manifest(manifest)
if not result["valid"]:
print("Errors:", result["errors"])Low-level function to invoke an MCP tool directly by endpoint URL. Sends a JSON-RPC 2.0 tools/call request.
result = nais.invoke("https://weatheragent.nais.id/mcp", "forecast", {"city": "NYC"})Returned by nais.resolve(). Wraps the resolver response with convenient accessors.
| Property / Method | Returns | Description |
|---|---|---|
agent.domain |
str |
Agent domain name |
agent.name |
str |
Human-readable name |
agent.description |
str | None |
Agent description |
agent.raw_response |
dict |
Full resolver JSON |
agent.get_manifest() |
dict | None |
Parsed manifest data |
agent.get_endpoint() |
str | None |
MCP endpoint URL |
agent.get_capabilities() |
list[dict] |
Advertised capabilities |
agent.get_capability(name) |
dict | None |
Single capability by name |
agent.get_auth_methods() |
list[str] |
Supported auth methods |
agent.get_payment_methods() |
list[str] |
Supported payment methods |
agent.requires_auth() |
bool |
True if "none" is not in auth methods |
agent.has_free_tier() |
bool |
True if a free tier is available |
agent.get_wallet() |
str | None |
Wallet address |
agent.invoke(method, params=None, headers=None, timeout=30) |
any |
Invoke an MCP tool |
For repeated calls, NaisClient reuses an HTTP session for better performance.
from nais import NaisClient
client = NaisClient()
agent = client.resolve("weatheragent.nais.id")
result = client.invoke("weatheragent.nais.id", "forecast", {"city": "NYC"})| Method | Returns | Description |
|---|---|---|
client.resolve(domain) |
NaisAgent |
Resolve a domain |
client.get_manifest(domain) |
dict |
Get manifest data |
client.invoke(domain, method, params=None, headers=None, timeout=30) |
any |
Resolve + invoke in one call |
All exceptions inherit from NaisError.
| Exception | When |
|---|---|
NaisError |
Base class for all SDK errors |
ResolveError |
Domain resolution fails |
ManifestError |
Manifest fetch/validation fails |
InvokeError |
MCP invocation fails (has .response_data attribute) |
from nais import ResolveError
try:
agent = nais.resolve("nonexistent.example.com")
except ResolveError as e:
print(f"Resolution failed: {e}")NAIS agents declare their supported auth and payment methods in their manifest.
agent = nais.resolve("weatheragent.nais.id")
if agent.requires_auth():
# Pass auth headers when invoking
result = agent.invoke("forecast", {"city": "NYC"}, headers={
"Authorization": "Bearer <token>"
})
else:
result = agent.invoke("forecast", {"city": "NYC"})
if agent.has_free_tier():
print("This agent has a free tier!")
print("Auth methods:", agent.get_auth_methods()) # ["wallet", "none"]
print("Payment methods:", agent.get_payment_methods()) # ["x402", "free"]- HTTP-only MCP transport: The SDK calls MCP endpoints over HTTP POST. Streaming and WebSocket transports are not yet supported.
- No automatic auth flows: The SDK does not handle wallet-based signing or token exchange. You must supply auth headers manually.
- No retry/backoff: Failed requests are not retried. Implement retries in your own code if needed.
- Resolver dependency: Resolution relies on the hosted resolver at
resolver.nais.id. Direct DNS TXT lookups are not performed client-side.
MIT