Nukez

Docs · MCP

MCP server

15 tools

Examples

JSON-RPC example

Executed MCP client sequence.

These examples mirror the canonical usage guide, executed and verified against the live production server: direct JSON-RPC, local signing, external payment, signed storage, verification, two-phase attestation, and memory.

Setup

Install and define the direct MCP client

Use the canonical raw JSON-RPC transport and local signer setup from the executed notebook.

python
pip install httpx pynacl base58 solders import json, hashlib, os, time, base64, pathlibimport httpxfrom nacl.signing import SigningKeyimport base58 BASE = "https://mcp.nukez.xyz/mcp"HEADERS = {"Content-Type": "application/json", "Accept": "application/json, text/event-stream"}KEYPAIR_PATH = pathlib.Path("/path/to/svm_key.json")RPC_URL = "https://mainnet.helius-rpc.com/?api-key=<API_KEY>" _kp_bytes = json.loads(KEYPAIR_PATH.read_text())_sk = SigningKey(bytes(_kp_bytes[:32]))PUBKEY = base58.b58encode(_sk.verify_key.encode()).decode()_req_id = 0 def rpc(method: str, params: dict = None):    global _req_id    _req_id += 1    payload = {"jsonrpc": "2.0", "id": _req_id, "method": method}    if params:        payload["params"] = params    resp = httpx.post(BASE, json=payload, headers=HEADERS, timeout=120)    ct = resp.headers.get("content-type", "")    if "text/event-stream" in ct:        for line in resp.text.splitlines():            if line.startswith("data: "):                data = json.loads(line[6:])                return data.get("result") or data.get("error")    body = resp.json()    return body.get("result") or body.get("error") def call(tool: str, args: dict = None):    params = {"name": tool}    if args:        params["arguments"] = args    result = rpc("tools/call", params)    if result and "content" in result:        texts = [c["text"] for c in result["content"] if c.get("type") == "text"]        if texts:            try:                return json.loads(texts[0])            except json.JSONDecodeError:                return texts[0]    return result

Code notes

This is the canonical setup from the usage guide and executed notebook: install direct-client dependencies, configure the hosted endpoint, load a local keypair, create JSON-RPC helpers, build signed envelopes, and provide an explicit solders-based Solana transfer helper.

The full guide also defines compute_locker_id(), build_envelope(), and solana_transfer(); those helpers are used by the following examples. pip install nukez-mcp replaces rpc() and call() with a typed client (see the Python package section); the signing and payment helpers remain required.

Signing

Build envelopes and keep payment local

Canonical JSON envelope signing and solders-based payment execution replace removed PyNukez helper methods.

python
def compute_locker_id(receipt_id: str) -> str:    return "locker_" + hashlib.sha256(receipt_id.encode()).hexdigest()[:12] def build_envelope(receipt_id, method, path, ops=None, body=None, ttl=300, query=None):    locker_id = compute_locker_id(receipt_id)    now = int(time.time())    canonical_body = None    if body is not None:        canonical_body = json.dumps(body, separators=(",", ":"), sort_keys=True)        body_hash = hashlib.sha256(canonical_body.encode()).hexdigest()    else:        body_hash = hashlib.sha256(b"").hexdigest()    envelope = {        "v": 1, "locker_id": locker_id, "receipt_id": receipt_id,        "nonce": os.urandom(16).hex(), "iat": now, "exp": now + ttl,        "ops": ops or [], "method": method.upper(), "path": path,        "body_sha256": body_hash, "sig_alg": "ed25519",    }    if query is not None:        envelope["query"] = query  # locker:attest binds to the request query    envelope_json = json.dumps(envelope, separators=(",", ":"), sort_keys=True)    sig = base58.b58encode(_sk.sign(envelope_json.encode()).signature).decode()    env_b64 = base64.urlsafe_b64encode(envelope_json.encode()).decode().rstrip("=")    result = {"headers": {"X-Nukez-Envelope": env_b64, "X-Nukez-Signature": sig}}    if canonical_body is not None:        result["body"] = canonical_body    return result from solders.keypair import Keypair as SoldersKeypairfrom solders.pubkey import Pubkeyfrom solders.system_program import transfer, TransferParamsfrom solders.transaction import Transactionfrom solders.message import Messagefrom solders.hash import Hash _solders_kp = SoldersKeypair.from_bytes(bytes(_kp_bytes[:64])) def solana_transfer(to_address: str, lamports: int) -> str:    bh = httpx.post(RPC_URL, json={        "jsonrpc": "2.0",        "id": 1,        "method": "getLatestBlockhash",        "params": [{"commitment": "finalized"}],    }, timeout=30).json()    blockhash = Hash.from_string(bh["result"]["value"]["blockhash"])    ix = transfer(TransferParams(        from_pubkey=_solders_kp.pubkey(),        to_pubkey=Pubkey.from_string(to_address),        lamports=lamports,    ))    msg = Message.new_with_blockhash([ix], _solders_kp.pubkey(), blockhash)    tx = Transaction.new_unsigned(msg)    tx.sign([_solders_kp], blockhash)    resp = httpx.post(RPC_URL, json={        "jsonrpc": "2.0",        "id": 1,        "method": "sendTransaction",        "params": [            base64.b64encode(bytes(tx)).decode(),            {"encoding": "base64", "skipPreflight": False},        ],    }, timeout=30).json()    if "error" in resp:        raise RuntimeError(f"sendTransaction failed: {resp['error']}")    return resp["result"]

Code notes

Post-provisioning operations require canonical JSON envelopes signed with the local Ed25519 key. The Solana payment helper is explicit client code: it obtains a blockhash, builds a system transfer, signs with solders, and submits the transaction through the configured RPC.

Envelope ops must match the action: locker:provision, locker:write, locker:list, or locker:read.

Package

nukez-mcp: the typed client

Replace the hand-rolled transport with the official package; signing and payment helpers stay as-is.

python
pip install nukez-mcp from nukez_mcp import NukezMCP, NukezMCPError with NukezMCP() as mcp:    info = mcp.connect()    print(info["serverInfo"])          # {'name': 'nukez', 'version': '1.3.0'}     tools = mcp.list_tools()           # 15 tools    status = mcp.call_tool("nukez_status")    print(status["capabilities"]["payment_rails"]) env = build_envelope(receipt_id, "GET", f"/v1/lockers/{locker_id}/files",                     ops=["locker:list"])files = mcp.call_tool("nukez_retrieve", {"receipt_id": receipt_id, "envelope": env}) v1 = mcp.call_tool("nukez_verify", {"receipt_id": receipt_id, "push": True})spec = v1["envelopes_needed"][0]   # includes a query field the signature must coverattest_env = build_envelope(receipt_id, spec["method"], spec["path"],                            ops=spec["ops"], body=spec["body"], query=spec["query"])v2 = mcp.call_tool("nukez_verify", {"receipt_id": receipt_id, "push": True,                                    "envelope": attest_env})assert v2["attestation"]["push_ok"] try:    mcp.call_tool("nukez_recall", {"receipt_id": receipt_id, "key": "missing"})except NukezMCPError as e:    print(e, e.code, e.data)

Code notes

The official package implements the transport from the setup section: pip install nukez-mcp, import as nukez_mcp, MCP protocol version pinned to 2025-03-26. NukezMCP.rpc and NukezMCP.call_tool replace rpc() and call(); compute_locker_id, build_envelope, and solana_transfer remain required as-is.

Transport is stateless per-call POSTs to https://mcp.nukez.xyz/mcp (constructor accepts endpoint=); both plain-JSON and text/event-stream bodies are parsed. rpc(method, params) is the raw JSON-RPC escape hatch.

Provision

Initialize, quote, pay, and activate the locker

Follow the exact two-step provisioning flow after recording the external payment transaction.

python
init = rpc("initialize", {    "protocolVersion": "2025-03-26",    "capabilities": {},    "clientInfo": {"name": "mcp-client", "version": "1.0"},})tools = rpc("tools/list")assert len(tools["tools"]) == 15 status = call("nukez_status")assert status["capabilities"]["payment_rails"] == ["solana-mainnet", "monad-mainnet"] quote = call("nukez_quote", {"units": 1, "provider": "gcs"})sol_opt = next(o for o in quote["payment_options"] if o["pay_asset"] == "SOL")pay_req_id = quote["pay_req_id"] tx_sig = solana_transfer(sol_opt["pay_to_address"], int(sol_opt["amount"]))pay = call("nukez_pay", {"pay_req_id": pay_req_id, "tx_sig": tx_sig, "chain": "solana-mainnet"}) # SPL payments (BETA/USDC/USDT/WETH): send transferChecked to the option's# token account directly and ALWAYS include "pay_asset" in nukez_pay AND# nukez_provision — otherwise the gateway verifies the tx as native SOL. confirm = call("nukez_provision", {"pay_req_id": pay_req_id, "tx_sig": tx_sig})assert confirm.get("action_required") == "sign_provision_envelope"receipt_id = confirm["receipt_id"]locker_id = confirm["locker_id"] provision_env = build_envelope(    receipt_id, "POST", "/v1/storage/signed_provision",    ops=["locker:provision"], body={"receipt_id": receipt_id},)provision = call("nukez_provision", {"receipt_id": receipt_id, "envelope": provision_env})

Code notes

The notebook starts by initializing the MCP server and confirming exactly 15 tools. It checks pre-setup status, quotes storage, executes a local SOL transfer, records that transaction with nukez_pay, then provisions through the two-step envelope flow.

The expected confirm result includes ok: true, status: payment_confirmed, requires_envelope: true, and envelopes_needed.

Storage

Store inline bytes or direct-upload large files

Use the right byte path for the size and execution environment.

python
body = {"filename": "smoke.txt", "content_type": "text/plain", "ttl_min": 30}env = build_envelope(receipt_id, "POST", f"/v1/lockers/{locker_id}/files", ops=["locker:write"], body=body)store = call("nukez_store", {    "receipt_id": receipt_id,    "envelope": env,    "files": [{"name": "smoke.txt", "data_b64": base64.b64encode(b"smoke test\n").decode()}],}) large_path = pathlib.Path("/path/to/report.pdf")large_bytes = large_path.read_bytes() env = build_envelope(    receipt_id, "POST", f"/v1/lockers/{locker_id}/files",    ops=["locker:write", "file:create", "locker:create_file",         "locker:store", "locker:confirm", "file:confirm"],    body={"filename": large_path.name},)created = call("nukez_create_file", {    "filename": large_path.name,    "content_type": "application/pdf",    "receipt_id": receipt_id,    "envelope": env,}) with httpx.Client(timeout=300, follow_redirects=True) as c:    up = c.put(created["upload_url"], content=large_bytes,               headers={"Content-Type": "application/pdf"})    assert up.status_code in (200, 201), up.status_code confirmed = call("nukez_confirm", {"filename": large_path.name, "receipt_id": receipt_id})assert confirmed.get("ok"), confirmed

Code notes

Small and moderate files can be sent with data_b64 when the client can tolerate bytes in the tool argument. Large local files use the canonical direct-upload path: nukez_create_file returns a signed upload_url, the client PUTs the raw bytes (they never transit the MCP server), then nukez_confirm records size and content hash.

nukez_upload_chunk exists as an advanced fallback for runtimes where a direct PUT is impossible.

Proof

Retrieve, bootstrap, verify, attest, and audit

Use signed list and read envelopes for production state and proof operations.

python
env_list = build_envelope(receipt_id, "GET", f"/v1/lockers/{locker_id}/files", ops=["locker:list"])files = call("nukez_retrieve", {"receipt_id": receipt_id, "envelope": env_list}) env_dl = build_envelope(receipt_id, "GET", f"/v1/lockers/{locker_id}/files/report.pdf", ops=["locker:read"])dl = call("nukez_retrieve", {"receipt_id": receipt_id, "envelope": env_dl, "filenames": ["report.pdf"]})downloaded = base64.b64decode(dl["files"][0]["content"]) status = call("nukez_status", {"receipt_id": receipt_id, "envelope": env_list}) verify_pre = call("nukez_verify", {"receipt_id": receipt_id, "push": False}) v1 = call("nukez_verify", {"receipt_id": receipt_id, "push": True})spec = v1["envelopes_needed"][0]  # includes a query field the signature must coverattest_env = build_envelope(receipt_id, spec["method"], spec["path"],                            ops=spec["ops"], body=spec["body"], query=spec["query"])v2 = call("nukez_verify", {"receipt_id": receipt_id, "push": True, "envelope": attest_env})assert v2["attestation"]["push_ok"] proof = call("nukez_verify", {"receipt_id": receipt_id, "filename": "report.pdf", "push": False})recheck = call("nukez_recompute_verify", {"receipt_id": receipt_id})assert recheck["match"] is True

Code notes

The canonical flow uses signed locker:list envelopes for file listings and session bootstrap, per-file locker:read envelopes for downloads, the two-phase push=true flow for on-chain anchoring, filename for Merkle inclusion proof, and nukez_recompute_verify for byte-level audits.

One per-file read envelope cannot authorize multiple different file paths.

Memory

Remember and recall

Use two-phase plan/execute memory writes for session state and keyless recall for reads.

python
mem = {    "receipt_id": receipt_id,    "key": "mainnet_test_note_1",    "content": json.dumps({"test": "mcp mainnet log"}),    "summary": "MCP mainnet test note - memory round-trip verification",    "namespace": "test",    "tags": "mcp,mainnet,test",}plan = call("nukez_remember", {**mem, "envelope": []})assert plan.get("action_required") == "upload_memory_files" for fkey in ("record_file", "index_file"):    f = plan[fkey]    body = {"filename": f["filename"], "content_type": f["content_type"], "ttl_min": 30}    env = build_envelope(receipt_id, "POST", f"/v1/lockers/{locker_id}/files",                         ops=["locker:write"], body=body)    stored = call("nukez_store", {"receipt_id": receipt_id, "envelope": env,                                  "files": [{"name": f["filename"],                                             "content_type": f["content_type"],                                             "data_b64": f["data_b64"]}]})    assert stored.get("ok"), stored recall = call("nukez_recall", {"receipt_id": receipt_id, "key": "mainnet_test_note_1"})by_tags = call("nukez_recall", {"receipt_id": receipt_id, "namespace": "test", "tags": "mcp"})

Code notes

Memory writes are two-phase: the plan call (empty envelope) returns action_required upload_memory_files with two server-prepared files — the record and the updated index. Store each with a signed locker:write envelope like any other file. Recall reads through the public receipt proxy and needs no envelope.

nukez_remember accepts supersedes=<older-key>; recall hides superseded records unless include_archived=True.

§ next