Docs menuAI agents: Skill, llms.txt and MCP

Start

AI agents: Skill, llms.txt and MCP

Teach a coding agent Jusa, give any model the docs, and let an assistant send with a person in the loop.

An agent gets the same Jusa you do: the same API, the same test mode, the same rules for money. There are three ways to hand it over, from teaching a coding agent how Jusa works to letting an assistant send for a person.

Start each one with a test key. Nothing real moves until a person swaps it for a live one.

Let an agent sendWithin its threshold an AI agent sends on its own. Above it, as here, the send waits until a person approves it with their payment PIN.

The Jusa Agent Skill

An Agent Skill is a folder an agent loads when a task needs it. SKILL.md says when to use it and how Jusa works: test and live keys, Jusa Credit at face value, an Idempotency-Key on every payment, how a send settles, ZESA meters, webhooks, typed errors. The files beside it are read only when a task needs them. The reference files are written from the code that decides them, so they change when the API does.

Download jusa-skill.zip ↓

16 files 83.3 KB sha256 0d3d4b9116bb…

What is inside
jusa/
├── SKILL.md
├── examples/
│   ├── dart.md
│   ├── dotnet.md
│   ├── go.md
│   ├── java.md
│   ├── node.md
│   ├── php.md
│   ├── python.md
│   └── ruby.md
└── reference/
    ├── api.md
    ├── errors.md
    ├── mcp.md
    ├── objects.md
    ├── recipes.md
    ├── test-mode.md
    └── webhooks.md

examples/ has the same job in each language, written as you would ship it: reward a completed survey once, then verify, dedupe and record the webhook that says how it went. Python, Node, PHP, Go, Java, C#, Dart, Ruby.

In Claude Code

Unzip it into your skills folder. Claude Code picks it up when a task mentions Jusa, airtime, ZESA or rewards; say use the jusa skill to be sure.

For you, in every project: ~/.claude/skills/jusa
curl -fsSL https://jusa.localhost.co.zw/developers/ai/jusa-skill.zip -o /tmp/jusa-skill.zip
mkdir -p ~/.claude/skills && unzip -o /tmp/jusa-skill.zip -d ~/.claude/skills/
For the whole team: .claude/skills/jusa in the repository
curl -fsSL https://jusa.localhost.co.zw/developers/ai/jusa-skill.zip -o /tmp/jusa-skill.zip
mkdir -p .claude/skills && unzip -o /tmp/jusa-skill.zip -d .claude/skills/
git add .claude/skills/jusa && git commit -m "Add the Jusa Agent Skill"

In Claude and Claude Desktop

  1. Download jusa-skill.zip.
  2. Open Settings, then Capabilities, and make sure code execution is on.
  3. Under Skills, choose Upload skill and pick the zip. It holds one folder, jusa/, with SKILL.md at its top, as the upload expects.

In any other agent

Put SKILL.md where the agent reads its instructions (an AGENTS.md, a rules folder, a system prompt) and the reference/ and examples/ folders beside it, where it can open them. Its links are relative, so keep the folder as it is. Or give the agent /llms-full.txt.

llms.txt for any model

Two plain-text files at the root of this site, in the llms.txt format, written from the same pages and OpenAPI document as these docs.

Keep a copy next to your code
curl -fsSL https://jusa.localhost.co.zw/llms-full.txt -o docs/jusa.md

The Jusa MCP server

For an assistant that acts for a person: send airtime, buy a ZESA token, reward someone, check the balance. The tools call the same code as the API, and an agent key holds them to limits a person sets.

Endpoint
POST https://jusa.localhost.co.zw/dev/v1/mcp
Transport
Streamable HTTP, answered as JSON. Stateless: no session, and GET is 405.
Key
Authorization: Bearer jusa_ak_…, agent keys only. OAuth is not offered yet.
Protocol
2025-06-18, 2025-03-26, 2024-11-05

First, an agent key

In the dashboard, switch to Test, open Keys and create an Agent key. Give it only the scopes its tools need, an approval threshold and, if you like, spend caps and the numbers it may reach without asking. With a secret key it is one call:

POST /keys
curl https://jusa.localhost.co.zw/dev/v1/keys \
  -H "Authorization: Bearer $JUSA_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "ak",
    "label": "Support assistant",
    "scopes": ["catalog:read", "lookups:read", "sends:read", "sends:write", "credit:read"],
    "approval_threshold": {"USD": "5.00"},
    "spend_caps": {"USD": {"per_send": "5.00", "daily": "25.00", "monthly": "200.00"}},
    "recipient_allowlist": ["0772555001"]
  }'

Then, your client

Claude CodeTerminal · .mcp.json · .claude/settings.json

Add the server for yourself (user scope: every project on this machine). The key is read from your shell when you run the command.

Terminal
export JUSA_AGENT_KEY=jusa_ak_test_…   # an agent key; test mode while you try it
claude mcp add --transport http --scope user jusa https://jusa.localhost.co.zw/dev/v1/mcp \
  --header "Authorization: Bearer $JUSA_AGENT_KEY"
claude mcp get jusa   # then /mcp inside Claude Code lists its tools

Commit .mcp.json at the project root. Claude Code expands ${JUSA_AGENT_KEY} from each person's environment, so the key itself is never committed.

.mcp.json
{
  "mcpServers": {
    "jusa": {
      "type": "http",
      "url": "https://jusa.localhost.co.zw/dev/v1/mcp",
      "headers": {
        "Authorization": "Bearer ${JUSA_AGENT_KEY}"
      }
    }
  }
}

Ask before money moves. Let the read-only tools run and make Claude ask you before every tool that sends, rewards, cancels or resends. The approval threshold still applies on the server.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__jusa__confirm_meter",
      "mcp__jusa__get_balance",
      "mcp__jusa__get_send",
      "mcp__jusa__list_products",
      "mcp__jusa__lookup_phone",
      "mcp__jusa__quote_zesa",
      "mcp__jusa__list_sends",
      "mcp__jusa__list_programs",
      "mcp__jusa__list_recipients",
      "mcp__jusa__get_status",
      "mcp__jusa__zesa_status",
      "mcp__jusa__search_docs"
    ],
    "ask": [
      "mcp__jusa__send_airtime",
      "mcp__jusa__buy_zesa",
      "mcp__jusa__create_reward",
      "mcp__jusa__send_data",
      "mcp__jusa__cancel_send",
      "mcp__jusa__resend_token"
    ]
  }
}
Claude Desktopclaude_desktop_config.json

Settings, Developer, Edit Config (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json; Windows: %APPDATA%\Claude\claude_desktop_config.json), then restart Claude. The mcp-remote bridge (Node 18+) carries the key as a header. Custom connectors on claude.ai sign in with OAuth, which the Jusa MCP server does not offer yet: use Claude Desktop or Claude Code meanwhile.

claude_desktop_config.json
{
  "mcpServers": {
    "jusa": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://jusa.localhost.co.zw/dev/v1/mcp",
        "--header",
        "Authorization:${JUSA_AUTHORIZATION}"
      ],
      "env": {
        "JUSA_AUTHORIZATION": "Bearer jusa_ak_test_…"
      }
    }
  }
}
Cursor.cursor/mcp.json

In the project (.cursor/mcp.json) or for every project (~/.cursor/mcp.json). Cursor reads ${env:JUSA_AGENT_KEY} from the environment it was started in.

.cursor/mcp.json
{
  "mcpServers": {
    "jusa": {
      "url": "https://jusa.localhost.co.zw/dev/v1/mcp",
      "headers": {
        "Authorization": "Bearer ${env:JUSA_AGENT_KEY}"
      }
    }
  }
}
VS Code.vscode/mcp.json

VS Code asks for the key the first time the server starts and keeps it in its secret storage.

.vscode/mcp.json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "jusa-agent-key",
      "description": "Jusa agent key (jusa_ak_test_… while you try it)",
      "password": true
    }
  ],
  "servers": {
    "jusa": {
      "type": "http",
      "url": "https://jusa.localhost.co.zw/dev/v1/mcp",
      "headers": {
        "Authorization": "Bearer ${input:jusa-agent-key}"
      }
    }
  }
}
Any other client, or by handcurl

Streamable HTTP answered as plain JSON: POST JSON-RPC 2.0, read JSON back. This lists the tools your key may call.

curl
curl -s https://jusa.localhost.co.zw/dev/v1/mcp \
  -H "Authorization: Bearer $JUSA_AGENT_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'

What keeps an agent in bounds

Every rule is checked on the server, under the same lock as the balance, whatever the client asks for.

Live is off until an owner turns it on A live agent key is refused (agent_live_mode_off) until an owner or admin allows agents on the account. Test agent keys work from the start.

US$10 / ZWG 250

An approval threshold What the key may send in a rolling 24 hours without asking (the default; set your own per key). Above it the tool answers requires_approval with a link, and nothing is sent or charged until an owner or admin approves with their payment PIN.

new number

A recipient allowlist A number or meter that is not one of your recipients, and not on the key's recipient_allowlist, needs a person's approval too. Once approved, it joins the list.

caps

Spend caps and products spend_caps, a daily cap per recipient, and allowed_products and allowed_networks. A key can never raise its own limits.

scopes

Only the tools it may use The key's scopes decide which tools it sees. An agent never mints reward links or releases escrow, and ZESA tokens stay masked without tokens:read.

audit log

Every write, on the record Each tool call that sends, rewards, cancels or resends is logged as mcp.tool_called with the tool's name, whatever came of it. Money tools need your own client_reference or completion_id, so a retry never pays twice.

The tools

18 tools; a key sees the ones its scopes allow. send_data is offered in live mode once live data bundles ship (test mode has simulated ones).

ToolWhat it doesScope
send_airtimemoves money Send Zimbabwean mobile airtime from Jusa Credit, at face value. The network is found from the number. Returns the send (status pending, then delivered or failed), or status requires_approval with an approval_url for a person. sends:write
buy_zesamoves money Buy a ZESA prepaid electricity token for an 11-digit meter, from Jusa Credit, at face value. The meter is confirmed with ZESA first. The token is texted to token_phone once delivered. sends:write
confirm_meter Ask ZESA whether a meter exists and is active. The owner's name is masked (T. M***) and the address is the suburb only. Rationed: do not use it to browse meters. lookups:read
create_rewardmoves money Reward a person from one of the account's programs (its budget and rules apply), paid directly as airtime or ZESA. completion_id is your id for what they did: one reward per completion, forever. rewards:write
get_balance The account's Jusa Credit in each currency: available, reserved and total. credit:read
get_send A send (snd_…) as it is now: pending, delivered, failed_credited …; or an approval request (apr_…). sends:read
list_products What can be sent: airtime, data and ZESA products with their currency, range and availability. catalog:read
send_datamoves money Send a data bundle (bundle_id from the product's bundles) to a Zimbabwean mobile, at the bundle's price. Live data bundles are not available yet: test mode has simulated ones. sends:write
lookup_phone A Zimbabwean mobile's network, its E.164 form and the airtime product for it. Asks no provider. lookups:read
quote_zesa What an amount buys on a meter now, and after the bands reset on the 1st. Confirms the meter with ZESA (rationed); pass the quo_ id to buy_zesa to carry that confirmation. lookups:read
list_sends The account's sends, newest first, optionally by status, type, target, client_reference or recipient. sends:read
cancel_sendmoves money Call off a send that has not gone out (scheduled, or waiting); its Jusa Credit comes back. sends:write
resend_tokenmoves money Send a delivered ZESA token again, only to the phone and email it went to first. A few times a day. sends:write
list_programs The account's reward programs with their budget, what is spent and their state. rewards:read
list_recipients The people the account sends to, newest first, or the one with an external_id. recipients:read
get_status Whether ZESA is answering, each network's state and the providers' health. any agent key
zesa_status Whether ZESA is answering now; while it is down ZESA sends wait (up to max_hold). any agent key
search_docs Search the Jusa developer docs: guides, recipes, error codes and API operations. any agent key

The skill's reference/mcp.md has all of this for an agent to read, and the AI agents recipe shows the approval flow end to end.