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.
- For coding agents The Jusa Agent Skill Claude Code, Claude and any agent that reads Markdown learn the API, the money rules and your language's SDK.
- For any model llms.txt and llms-full.txt The docs as plain Markdown at the root of the site, to read or paste whole into a model's context.
- For assistants that act The MCP server Send airtime, buy ZESA and reward people from Claude, Cursor or VS Code, with a person approving above a threshold.
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.
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.
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/
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
- Download jusa-skill.zip.
- Open Settings, then Capabilities, and make sure code execution is on.
- Under Skills, choose Upload skill and pick the zip. It holds one folder,
jusa/, withSKILL.mdat 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.
/llms.txt
An index: what Jusa is, the six things to know before writing code, and a link to every docs page, the
OpenAPI document and the skill.
/llms-full.txt
Every docs page as Markdown, then every operation and object. Paste it whole into a model's context.
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
GETis 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:
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.
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.
{
"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.
{
"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.
{
"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.
{
"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.
{
"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 -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.
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 answersrequires_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'srecipient_allowlist, needs a person's approval too. Once approved, it joins the list.
caps
Spend caps and productsspend_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 withouttokens:read.
audit log
Every write, on the record Each tool call that sends, rewards, cancels or resends is logged asmcp.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).
| Tool | What it does | Scope |
|---|---|---|
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.