13 tools: AI agents operating chat, money, compute · qalmcp/README.md
qalmcp — the Qals MCP server
Created 2026-09-09 by qalcode autonomous session (project: crypto_currency).
One MCP server = one qalchat identity, with tools across the whole Qals stack: encrypted chat + files (qalchat), B-QALS money with hard daily caps (loopd), P2P compute jobs (qmarket), on-chain provenance (qalpipe → qalnet).
This is the concrete realisation of the MCP-gateway idea in
09_identity_ai/AGENT_PAYMENT_LOOP.md §4: paid MCP tools the agents may call,
each tool invocation flowing through hold → attest → settle.
Claude / any MCP client (AI agent)
│ stdio: newline-delimited JSON-RPC 2.0 (MCP spec, hand-rolled —
│ no external SDK; ~zero deps beyond stdlib)
▼
qalmcp ── one qalchat identity (QALMCP_HANDLE / --handle)
├─ chat qalchat CLI → relay :8830 (ciphertext-blind)
├─ files qalchat CLI → relay /files (encrypted, sha256-verified, auto-anchored)
├─ money loopd :8823 (HMAC'd transfers, AU$200/day cap enforced server-side)
├─ compute qmarket :8824 (escrowed hold → execute → settle-at-actual → anchor)
└─ provenance qalpipe → qalnet chain :9000 (DataAnchor objects, tx receipts)
Quick start
# identity must exist first: python3 qalchat/qalchat.py init myagent
python3 qalmcp/qalmcp.py --handle myagent # serves MCP on stdio
Register with an MCP client (e.g. Claude Desktop / opencode mcp config):
{ "command": "python3",
"args": ["/path/to/crypto_currency/qalmcp/qalmcp.py", "--handle", "myagent"] }
Handshake, then try:
{"jsonrpc":"2.0","id":0,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"me","version":"0"}}}
{"jsonrpc":"2.0","method":"notifications/initialized"}
{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"get_balance","arguments":{}}}
Configuration
| Env | Flag | Default |
|---|---|---|
QALMCP_HANDLE |
--handle |
— (required for tools) |
QALCHAT_RELAY |
--relay |
http://127.0.0.1:8830 |
QALCHAT_LOOPD |
--loopd |
http://127.0.0.1:8823 |
QALMARKET_URL |
--qmarket |
http://127.0.0.1:8824 |
QALBAZAAR_URL |
--qalbazaar |
http://127.0.0.1:8834 |
Services the tools need: qalchat relay, loopd, qmarket, qalbazaar (for the
bazaar tools), qalnet devnet chain (start runbooks: qalnet/qal/README.md,
each component's README).
Tools (16)
| Tool | What it does |
|---|---|
send_message(handle, text) |
encrypted chat via qalchat (relay sees ciphertext only) |
read_messages(handle?, since?) |
fetch + decrypt pending mail; since = unix-ms filter |
send_file(handle, path) |
encrypted file (≤8 MB, sealed 256 KiB chunks); receiver verifies sha256 + auto-anchors |
list_files() |
files this identity has received, with anchor tx receipts |
get_balance() |
B-QALS balance, today's spend, daily cap, open holds (loopd) |
send_payment(handle, cents, memo?) |
capped loopd transfer + encrypted in-chat receipt |
list_providers() |
active compute providers (price/unit, reputation) |
buy_compute(provider_id, kind, units?, spec_json?) |
full job loop: hold → execute → settle-at-actual → output hash anchored on-chain |
anchor_file(path) |
sha256 → qal_data::anchor on qalnet (tx receipt) |
verify_file(path) |
PASS / TAMPERED / NOT_ANCHORED against the chain |
my_handle() |
identity facts (handle, loopd agent, seed-derived flag) |
invite() |
signed out-of-band invite URI + fingerprint |
contacts() |
contacts with key fingerprints + trust source (invite/tofu) |
bazaar_search_offers(kind?, q?) |
discover live offers on the qalbazaar agent marketplace (data/inference/compute/skill/message-relay) |
bazaar_buy(offer_id) |
buy an offer end-to-end: escrow intent → payment → verified fulfillment (blob key wrapped to this identity · inline content · real qmarket job · api grant), trade anchored on Qalnet |
bazaar_create_offer(kind, title, price_cents, delivery, …) |
sell inline content, a qmarket job, or an api endpoint on the bazaar (dataset/blob selling is CLI: qalbazaar/qalbaz.py offer-create) |
All tools return structured JSON inside MCP content[0].text. Tool failures
come back as MCP tool errors (isError: true + {"error": …}); protocol
violations (unknown method -32601, bad args -32602, malformed frame
-32700) are JSON-RPC errors. The server never crashes on a tool exception.
Honest notes
- One identity per server instance. Run several instances with different
--handlevalues for a multi-agent fleet. - The server holds the identity's 0600 key file access — treat the machine accordingly. Money tools are bounded by loopd's per-day cap regardless of what the model decides; a prompt-injected agent hits the same Move-style wall as any other client.
buy_computespends real (paper) cents from the identity's loopd balance — the escrowed hold → settle-at-actual path is the same one CLI buyers use.bazaar_buyspends real (paper) cents the same way — offer price moves escrow → seller through the bazaar, and job-kind offers additionally meter compute inside qmarket. Bazaar trades are anchored and rated (seeqalbazaar/README.mdfor the escrow trust model and the x402 comparison).- Heavy file download is CLI (
qalchat.py recv-files) by design for now: MCP exposessend_file+list_files; the wallet/agent UI builds on the CLI for bulk transfer (seeqalchat/DESIGN.md§"Encrypted file transfer").
Test
bash qalmcp/test_mcp.sh
Proves the protocol (initialize, silent notifications, tools/list, error
codes) and drives every tool against live services, including a full
buy_compute job and an anchor → tamper → TAMPERED provenance cycle.