zambo-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zambo_sdk-0.1.0/PKG-INFO +71 -0
- zambo_sdk-0.1.0/README.md +54 -0
- zambo_sdk-0.1.0/pyproject.toml +28 -0
- zambo_sdk-0.1.0/setup.cfg +4 -0
- zambo_sdk-0.1.0/src/zambo_sdk/__init__.py +30 -0
- zambo_sdk-0.1.0/src/zambo_sdk/client.py +202 -0
- zambo_sdk-0.1.0/src/zambo_sdk.egg-info/PKG-INFO +71 -0
- zambo_sdk-0.1.0/src/zambo_sdk.egg-info/SOURCES.txt +8 -0
- zambo_sdk-0.1.0/src/zambo_sdk.egg-info/dependency_links.txt +1 -0
- zambo_sdk-0.1.0/src/zambo_sdk.egg-info/top_level.txt +1 -0
zambo_sdk-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zambo-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zambo Python client — 100+ MCP tools, verifiable receipt for every call, no API key
|
|
5
|
+
Author: Brennan Zambo
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev
|
|
8
|
+
Project-URL: Documentation, https://zambo.dev/docs
|
|
9
|
+
Keywords: zambo,mcp,ai-tools,agents,receipts
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# zambo-sdk
|
|
19
|
+
|
|
20
|
+
Thin Python client for [Zambo](https://zambo.dev) — the trust layer for AI work. 100+ native MCP tools, a verifiable receipt for every call. Free 20 calls/tool/day, no account, no API key. Zero dependencies.
|
|
21
|
+
|
|
22
|
+
> **Name note:** the distribution name is pending final pick (`zambo-sdk`, `zambo-dev`, `zambo-api`, `pyzambo`, `zambodotdev`, `zambopy` are all free on PyPI). The import package is `zambo_sdk` regardless.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install zambo-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quickstart
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from zambo_sdk import Client, verify_receipt
|
|
34
|
+
|
|
35
|
+
z = Client()
|
|
36
|
+
|
|
37
|
+
# 1. Call a tool — plain JSON-RPC, no API key
|
|
38
|
+
result = z.call("live_price", {"symbol": "BTC"})
|
|
39
|
+
print(result.text)
|
|
40
|
+
print("receipt:", result.receipt_id)
|
|
41
|
+
print("audit: ", result.audit_url)
|
|
42
|
+
|
|
43
|
+
# 2. Route any goal through the universal entry point
|
|
44
|
+
job = z.universal("audit https://example.com for AI discoverability", session="demo-1")
|
|
45
|
+
print(job.text)
|
|
46
|
+
|
|
47
|
+
# 3. Search the full 100+ tool catalog
|
|
48
|
+
found = z.search("generate QR code")
|
|
49
|
+
print(found.text)
|
|
50
|
+
|
|
51
|
+
# 4. Verify a receipt client-side (recomputes the sha256 locally)
|
|
52
|
+
v = verify_receipt(result.receipt_id)
|
|
53
|
+
print("verified:", v.verified, v.checks)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
- `Client().call(tool, arguments)` → `CallResult` (`.text`, `.receipt_id`, `.audit_url`, `.receipt`)
|
|
59
|
+
- `Client().list_tools()` → list of tool descriptors
|
|
60
|
+
- `Client().search(query)` → search the full catalog via `capability_search`
|
|
61
|
+
- `Client().universal(goal, session=None)` → multi-step jobs via `zambo_universal`
|
|
62
|
+
- `get_receipt(receipt_id)` → full receipt JSON
|
|
63
|
+
- `verify_receipt(receipt_id)` → `Verification` (`.verified`, `.checks`, `.audit_url`)
|
|
64
|
+
|
|
65
|
+
`verify_receipt` checks three things: the receipt exists, the server marks it `verified`, and — recomputed locally so the server can't fake it — `sha256(canonical_bytes) == output_hash`, plus the presence of the anchor record.
|
|
66
|
+
|
|
67
|
+
## Notes
|
|
68
|
+
|
|
69
|
+
- Endpoint: `https://zambo.dev/api/mcp` (JSON-RPC 2.0 over HTTPS, `streamable_http`-compatible).
|
|
70
|
+
- Receipts: `https://zambo.dev/api/receipt/<uuid>` (JSON), audit page `https://zambo.dev/run/<uuid>`.
|
|
71
|
+
- Need more than 20 calls/tool/day? The $1.49/24h Day Pass is at [zambo.dev](https://zambo.dev).
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# zambo-sdk
|
|
2
|
+
|
|
3
|
+
Thin Python client for [Zambo](https://zambo.dev) — the trust layer for AI work. 100+ native MCP tools, a verifiable receipt for every call. Free 20 calls/tool/day, no account, no API key. Zero dependencies.
|
|
4
|
+
|
|
5
|
+
> **Name note:** the distribution name is pending final pick (`zambo-sdk`, `zambo-dev`, `zambo-api`, `pyzambo`, `zambodotdev`, `zambopy` are all free on PyPI). The import package is `zambo_sdk` regardless.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install zambo-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from zambo_sdk import Client, verify_receipt
|
|
17
|
+
|
|
18
|
+
z = Client()
|
|
19
|
+
|
|
20
|
+
# 1. Call a tool — plain JSON-RPC, no API key
|
|
21
|
+
result = z.call("live_price", {"symbol": "BTC"})
|
|
22
|
+
print(result.text)
|
|
23
|
+
print("receipt:", result.receipt_id)
|
|
24
|
+
print("audit: ", result.audit_url)
|
|
25
|
+
|
|
26
|
+
# 2. Route any goal through the universal entry point
|
|
27
|
+
job = z.universal("audit https://example.com for AI discoverability", session="demo-1")
|
|
28
|
+
print(job.text)
|
|
29
|
+
|
|
30
|
+
# 3. Search the full 100+ tool catalog
|
|
31
|
+
found = z.search("generate QR code")
|
|
32
|
+
print(found.text)
|
|
33
|
+
|
|
34
|
+
# 4. Verify a receipt client-side (recomputes the sha256 locally)
|
|
35
|
+
v = verify_receipt(result.receipt_id)
|
|
36
|
+
print("verified:", v.verified, v.checks)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## API
|
|
40
|
+
|
|
41
|
+
- `Client().call(tool, arguments)` → `CallResult` (`.text`, `.receipt_id`, `.audit_url`, `.receipt`)
|
|
42
|
+
- `Client().list_tools()` → list of tool descriptors
|
|
43
|
+
- `Client().search(query)` → search the full catalog via `capability_search`
|
|
44
|
+
- `Client().universal(goal, session=None)` → multi-step jobs via `zambo_universal`
|
|
45
|
+
- `get_receipt(receipt_id)` → full receipt JSON
|
|
46
|
+
- `verify_receipt(receipt_id)` → `Verification` (`.verified`, `.checks`, `.audit_url`)
|
|
47
|
+
|
|
48
|
+
`verify_receipt` checks three things: the receipt exists, the server marks it `verified`, and — recomputed locally so the server can't fake it — `sha256(canonical_bytes) == output_hash`, plus the presence of the anchor record.
|
|
49
|
+
|
|
50
|
+
## Notes
|
|
51
|
+
|
|
52
|
+
- Endpoint: `https://zambo.dev/api/mcp` (JSON-RPC 2.0 over HTTPS, `streamable_http`-compatible).
|
|
53
|
+
- Receipts: `https://zambo.dev/api/receipt/<uuid>` (JSON), audit page `https://zambo.dev/run/<uuid>`.
|
|
54
|
+
- Need more than 20 calls/tool/day? The $1.49/24h Day Pass is at [zambo.dev](https://zambo.dev).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "zambo-sdk" # Brennan-approved distribution name (2026-09-20). "zambo" is his CLI package.
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Zambo Python client — 100+ MCP tools, verifiable receipt for every call, no API key"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Brennan Zambo" }]
|
|
13
|
+
keywords = ["zambo", "mcp", "ai-tools", "agents", "receipts"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
20
|
+
]
|
|
21
|
+
dependencies = []
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://zambo.dev"
|
|
25
|
+
Documentation = "https://zambo.dev/docs"
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["src"]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""zambo_sdk — thin Python client for zambo.dev.
|
|
2
|
+
|
|
3
|
+
Zambo (https://zambo.dev) is the trust layer for AI work: 100+ native MCP
|
|
4
|
+
tools over plain JSON-RPC, a verifiable receipt for every call. Free
|
|
5
|
+
20 calls/tool/day, no account, no API key. $1.49/24h Day Pass.
|
|
6
|
+
|
|
7
|
+
This is the whole client: call tools, fetch receipts, verify receipts.
|
|
8
|
+
No dependencies beyond the standard library.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from zambo_sdk.client import (
|
|
12
|
+
ZAMBO_API_URL,
|
|
13
|
+
CallResult,
|
|
14
|
+
Client,
|
|
15
|
+
ReceiptNotFound,
|
|
16
|
+
Verification,
|
|
17
|
+
get_receipt,
|
|
18
|
+
verify_receipt,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"ZAMBO_API_URL",
|
|
23
|
+
"CallResult",
|
|
24
|
+
"Client",
|
|
25
|
+
"ReceiptNotFound",
|
|
26
|
+
"Verification",
|
|
27
|
+
"get_receipt",
|
|
28
|
+
"verify_receipt",
|
|
29
|
+
]
|
|
30
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Thin, dependency-free client for the Zambo MCP endpoint.
|
|
2
|
+
|
|
3
|
+
Contract (verified live against https://zambo.dev/api/mcp):
|
|
4
|
+
- POST JSON-RPC 2.0, no auth, no session.
|
|
5
|
+
- ``tools/list`` -> {"tools": [...]}
|
|
6
|
+
- ``tools/call`` {"name", "arguments"} -> {"content": [...], "_receipt": {...}}
|
|
7
|
+
- Server answers JSON or SSE (``data: {...}`` lines); transport flakes are
|
|
8
|
+
retried, JSON-RPC errors are never retried.
|
|
9
|
+
- Receipt JSON: GET https://zambo.dev/api/receipt/<uuid> (Accept: application/json)
|
|
10
|
+
- Human audit page: https://zambo.dev/run/<uuid>
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import base64
|
|
16
|
+
import hashlib
|
|
17
|
+
import http.client as _http_client
|
|
18
|
+
import json
|
|
19
|
+
import time
|
|
20
|
+
import urllib.error
|
|
21
|
+
import urllib.request
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
|
+
from typing import Any, Dict, List, Optional
|
|
24
|
+
|
|
25
|
+
ZAMBO_API_URL = "https://zambo.dev/api/mcp"
|
|
26
|
+
ZAMBO_RECEIPT_API = "https://zambo.dev/api/receipt/{receipt_id}"
|
|
27
|
+
ZAMBO_AUDIT_URL = "https://zambo.dev/run/{receipt_id}"
|
|
28
|
+
|
|
29
|
+
_JSON_HEADERS = {
|
|
30
|
+
"Content-Type": "application/json",
|
|
31
|
+
"Accept": "application/json, text/event-stream",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_TRANSIENT = (
|
|
35
|
+
_http_client.IncompleteRead,
|
|
36
|
+
_http_client.RemoteDisconnected,
|
|
37
|
+
_http_client.BadStatusLine,
|
|
38
|
+
ConnectionResetError,
|
|
39
|
+
BrokenPipeError,
|
|
40
|
+
TimeoutError,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ZamboError(Exception):
|
|
45
|
+
"""A JSON-RPC error returned by the Zambo server."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ReceiptNotFound(ZamboError):
|
|
49
|
+
"""No receipt exists for the given id."""
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass
|
|
53
|
+
class CallResult:
|
|
54
|
+
"""The outcome of one tool call."""
|
|
55
|
+
|
|
56
|
+
tool: str
|
|
57
|
+
text: str
|
|
58
|
+
receipt_id: Optional[str] = None
|
|
59
|
+
audit_url: Optional[str] = None
|
|
60
|
+
receipt: Dict[str, Any] = field(default_factory=dict)
|
|
61
|
+
raw: Dict[str, Any] = field(default_factory=dict)
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def ok(self) -> bool:
|
|
65
|
+
return self.receipt.get("status") == "success" if self.receipt else True
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class Verification:
|
|
70
|
+
"""Client-side verification of a Zambo receipt."""
|
|
71
|
+
|
|
72
|
+
receipt_id: str
|
|
73
|
+
verified: bool
|
|
74
|
+
checks: Dict[str, bool]
|
|
75
|
+
audit_url: str
|
|
76
|
+
receipt: Dict[str, Any] = field(default_factory=dict)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _post_json_rpc(method: str, params: Dict[str, Any], attempts: int = 6) -> Dict[str, Any]:
|
|
80
|
+
body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params}).encode()
|
|
81
|
+
last: Optional[Exception] = None
|
|
82
|
+
for n in range(attempts):
|
|
83
|
+
try:
|
|
84
|
+
req = urllib.request.Request(ZAMBO_API_URL, data=body, headers=_JSON_HEADERS, method="POST")
|
|
85
|
+
with urllib.request.urlopen(req, timeout=60) as resp:
|
|
86
|
+
raw = resp.read().decode().strip()
|
|
87
|
+
break
|
|
88
|
+
except _TRANSIENT as e:
|
|
89
|
+
last = e
|
|
90
|
+
time.sleep(0.6 * (n + 1))
|
|
91
|
+
else:
|
|
92
|
+
raise ZamboError(f"Transport failed after {attempts} attempts: {type(last).__name__}: {last}")
|
|
93
|
+
|
|
94
|
+
if raw.startswith("{"):
|
|
95
|
+
payload = json.loads(raw)
|
|
96
|
+
else: # SSE: data: {...} lines
|
|
97
|
+
payload = None
|
|
98
|
+
for line in raw.splitlines():
|
|
99
|
+
if line.startswith("data:"):
|
|
100
|
+
try:
|
|
101
|
+
payload = json.loads(line[5:].strip())
|
|
102
|
+
break
|
|
103
|
+
except json.JSONDecodeError:
|
|
104
|
+
continue
|
|
105
|
+
if payload is None:
|
|
106
|
+
raise ZamboError(f"Unparseable response: {raw[:200]}")
|
|
107
|
+
if "error" in payload:
|
|
108
|
+
raise ZamboError(json.dumps(payload["error"]))
|
|
109
|
+
return payload["result"]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _get_json(url: str, attempts: int = 4) -> Dict[str, Any]:
|
|
113
|
+
last: Optional[Exception] = None
|
|
114
|
+
for n in range(attempts):
|
|
115
|
+
try:
|
|
116
|
+
req = urllib.request.Request(url, headers={"Accept": "application/json"}, method="GET")
|
|
117
|
+
with urllib.request.urlopen(req, timeout=30) as resp:
|
|
118
|
+
return json.loads(resp.read().decode())
|
|
119
|
+
except urllib.error.HTTPError as e:
|
|
120
|
+
if e.code == 404:
|
|
121
|
+
raise ReceiptNotFound(f"No receipt found: {url}")
|
|
122
|
+
raise ZamboError(f"HTTP {e.code} fetching {url}")
|
|
123
|
+
except _TRANSIENT as e:
|
|
124
|
+
last = e
|
|
125
|
+
time.sleep(0.6 * (n + 1))
|
|
126
|
+
raise ZamboError(f"Transport failed after {attempts} attempts: {type(last).__name__}: {last}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class Client:
|
|
130
|
+
"""Minimal Zambo client. No API key, no account — free 20 calls/tool/day."""
|
|
131
|
+
|
|
132
|
+
def call(self, tool: str, arguments: Optional[Dict[str, Any]] = None) -> CallResult:
|
|
133
|
+
"""Call a Zambo tool. Returns text + the verifiable receipt."""
|
|
134
|
+
result = _post_json_rpc("tools/call", {"name": tool, "arguments": arguments or {}})
|
|
135
|
+
text = "\n".join(
|
|
136
|
+
b.get("text", "") for b in result.get("content", []) if b.get("type") == "text"
|
|
137
|
+
)
|
|
138
|
+
receipt = result.get("_receipt", {}) or {}
|
|
139
|
+
rid = receipt.get("id")
|
|
140
|
+
return CallResult(
|
|
141
|
+
tool=tool,
|
|
142
|
+
text=text,
|
|
143
|
+
receipt_id=rid,
|
|
144
|
+
audit_url=ZAMBO_AUDIT_URL.format(receipt_id=rid) if rid else None,
|
|
145
|
+
receipt=receipt,
|
|
146
|
+
raw=result,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def list_tools(self) -> List[Dict[str, Any]]:
|
|
150
|
+
"""List the tools on the main MCP surface."""
|
|
151
|
+
return _post_json_rpc("tools/list", {}).get("tools", [])
|
|
152
|
+
|
|
153
|
+
def search(self, query: str) -> CallResult:
|
|
154
|
+
"""Search the full 100+ tool catalog."""
|
|
155
|
+
return self.call("capability_search", {"query": query})
|
|
156
|
+
|
|
157
|
+
def universal(self, goal: str, session: Optional[str] = None) -> CallResult:
|
|
158
|
+
"""Route any goal through zambo_universal (the main entry point)."""
|
|
159
|
+
args: Dict[str, Any] = {"goal": goal}
|
|
160
|
+
if session:
|
|
161
|
+
args["session"] = session
|
|
162
|
+
return self.call("zambo_universal", args)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def get_receipt(receipt_id: str) -> Dict[str, Any]:
|
|
166
|
+
"""Fetch the full receipt JSON for a receipt id."""
|
|
167
|
+
return _get_json(ZAMBO_RECEIPT_API.format(receipt_id=receipt_id))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def verify_receipt(receipt_id: str) -> Verification:
|
|
171
|
+
"""Verify a Zambo receipt client-side.
|
|
172
|
+
|
|
173
|
+
Checks:
|
|
174
|
+
- the receipt exists and the server marks it ``verified``
|
|
175
|
+
- sha256 of the canonical bytes matches the claimed ``output_hash``
|
|
176
|
+
(recomputed locally — the server cannot fake this)
|
|
177
|
+
- an anchor record is present
|
|
178
|
+
"""
|
|
179
|
+
receipt = get_receipt(receipt_id)
|
|
180
|
+
checks: Dict[str, bool] = {}
|
|
181
|
+
|
|
182
|
+
checks["exists"] = bool(receipt.get("id"))
|
|
183
|
+
checks["server_marks_verified"] = receipt.get("verification_status") == "verified"
|
|
184
|
+
|
|
185
|
+
claimed = receipt.get("output_hash", "")
|
|
186
|
+
canonical_b64 = receipt.get("canonical_bytes", "")
|
|
187
|
+
try:
|
|
188
|
+
digest = "sha256:" + hashlib.sha256(base64.b64decode(canonical_b64)).hexdigest()
|
|
189
|
+
checks["output_hash_matches"] = bool(claimed) and digest == claimed
|
|
190
|
+
except Exception:
|
|
191
|
+
checks["output_hash_matches"] = False
|
|
192
|
+
|
|
193
|
+
checks["anchor_present"] = bool((receipt.get("anchor") or {}).get("event_id"))
|
|
194
|
+
|
|
195
|
+
verified = all(checks.values())
|
|
196
|
+
return Verification(
|
|
197
|
+
receipt_id=receipt_id,
|
|
198
|
+
verified=verified,
|
|
199
|
+
checks=checks,
|
|
200
|
+
audit_url=ZAMBO_AUDIT_URL.format(receipt_id=receipt_id),
|
|
201
|
+
receipt=receipt,
|
|
202
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zambo-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zambo Python client — 100+ MCP tools, verifiable receipt for every call, no API key
|
|
5
|
+
Author: Brennan Zambo
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://zambo.dev
|
|
8
|
+
Project-URL: Documentation, https://zambo.dev/docs
|
|
9
|
+
Keywords: zambo,mcp,ai-tools,agents,receipts
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# zambo-sdk
|
|
19
|
+
|
|
20
|
+
Thin Python client for [Zambo](https://zambo.dev) — the trust layer for AI work. 100+ native MCP tools, a verifiable receipt for every call. Free 20 calls/tool/day, no account, no API key. Zero dependencies.
|
|
21
|
+
|
|
22
|
+
> **Name note:** the distribution name is pending final pick (`zambo-sdk`, `zambo-dev`, `zambo-api`, `pyzambo`, `zambodotdev`, `zambopy` are all free on PyPI). The import package is `zambo_sdk` regardless.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install zambo-sdk
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quickstart
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from zambo_sdk import Client, verify_receipt
|
|
34
|
+
|
|
35
|
+
z = Client()
|
|
36
|
+
|
|
37
|
+
# 1. Call a tool — plain JSON-RPC, no API key
|
|
38
|
+
result = z.call("live_price", {"symbol": "BTC"})
|
|
39
|
+
print(result.text)
|
|
40
|
+
print("receipt:", result.receipt_id)
|
|
41
|
+
print("audit: ", result.audit_url)
|
|
42
|
+
|
|
43
|
+
# 2. Route any goal through the universal entry point
|
|
44
|
+
job = z.universal("audit https://example.com for AI discoverability", session="demo-1")
|
|
45
|
+
print(job.text)
|
|
46
|
+
|
|
47
|
+
# 3. Search the full 100+ tool catalog
|
|
48
|
+
found = z.search("generate QR code")
|
|
49
|
+
print(found.text)
|
|
50
|
+
|
|
51
|
+
# 4. Verify a receipt client-side (recomputes the sha256 locally)
|
|
52
|
+
v = verify_receipt(result.receipt_id)
|
|
53
|
+
print("verified:", v.verified, v.checks)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## API
|
|
57
|
+
|
|
58
|
+
- `Client().call(tool, arguments)` → `CallResult` (`.text`, `.receipt_id`, `.audit_url`, `.receipt`)
|
|
59
|
+
- `Client().list_tools()` → list of tool descriptors
|
|
60
|
+
- `Client().search(query)` → search the full catalog via `capability_search`
|
|
61
|
+
- `Client().universal(goal, session=None)` → multi-step jobs via `zambo_universal`
|
|
62
|
+
- `get_receipt(receipt_id)` → full receipt JSON
|
|
63
|
+
- `verify_receipt(receipt_id)` → `Verification` (`.verified`, `.checks`, `.audit_url`)
|
|
64
|
+
|
|
65
|
+
`verify_receipt` checks three things: the receipt exists, the server marks it `verified`, and — recomputed locally so the server can't fake it — `sha256(canonical_bytes) == output_hash`, plus the presence of the anchor record.
|
|
66
|
+
|
|
67
|
+
## Notes
|
|
68
|
+
|
|
69
|
+
- Endpoint: `https://zambo.dev/api/mcp` (JSON-RPC 2.0 over HTTPS, `streamable_http`-compatible).
|
|
70
|
+
- Receipts: `https://zambo.dev/api/receipt/<uuid>` (JSON), audit page `https://zambo.dev/run/<uuid>`.
|
|
71
|
+
- Need more than 20 calls/tool/day? The $1.49/24h Day Pass is at [zambo.dev](https://zambo.dev).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
zambo_sdk
|