Skip to main content

mpesa-daraja-mcp: M-Pesa Daraja MCP server

An MCP server that exposes Safaricom's Daraja APIs as tools, so an agent (Claude Code, Claude Desktop, any MCP client) can test and operate M-Pesa integrations. It pairs with the skills in Agent Skills in this repository: skills teach how to integrate, this server lets the agent call Daraja.

Tools

Tool Daraja API Moves money
mpesa_explain_code — offline error/result code lookup
mpesa_normalize_phone — offline 07… → 2547…
mpesa_generate_stk_password — offline Password + EAT Timestamp
mpesa_parse_callback — offline parse of any callback payload
mpesa_setup_status — offline: what's configured and missing per toolset (no values)
mpesa_check_credentials OAuth token (never returned)
mpesa_get_result Final status by idempotency key or any Daraja ID (from captured callbacks; STK falls back to STK Query)
mpesa_stk_push_and_wait M-Pesa Express: push, then wait for callback / poll query; returns SUCCESS, FAILED or UNKNOWN ✅
mpesa_stk_push / mpesa_stk_query M-Pesa Express, fire-and-forget / status ✅ /
mpesa_c2b_register_urls / mpesa_c2b_simulate C2B v2 (simulate = sandbox only)
mpesa_pull_transactions Pull Transactions query
mpesa_b2c_payment B2C v3, B2Pochi ✅
mpesa_b2b_payment BusinessPayBill, BusinessBuyGoods, BusinessPayToBulk (B2C top-up), PayTaxToKRA ✅
mpesa_b2b_express_checkout B2B USSD push ✅
mpesa_transaction_status / mpesa_account_balance Status / Balance (async result)
mpesa_reverse_transaction Reversal ✅
mpesa_generate_dynamic_qr Dynamic QR, saved as a PNG file (path returned, not the image)
mpesa_ratiba_create_standing_order M-Pesa Ratiba ✅
mpesa_bill_manager_optin / mpesa_bill_manager_send_invoice / mpesa_bill_manager_cancel_invoice Bill Manager

Tool annotations mark money-moving tools as destructiveHint, so MCP clients ask for approval.

Safety

  • Defaults to the sandbox.
  • In production, money-moving tools refuse to run unless MPESA_ALLOW_LIVE_MONEY_MOVEMENT=true.
  • Callback URLs must be HTTPS; C2B URLs with mpesa/safaricom in them are rejected up front.
  • Tokens and secrets are never returned in tool output.
  • Responses with ResponseCode "0" are tagged _note: ACCEPTED for processing only, so the agent does not report them as completed payments.
  • Idempotent money tools. Each request is stored under an idempotency key. Repeating the key returns the stored request (duplicate: true) instead of paying again.
    • Only a definitively FAILED request is re-sent.
    • ACCEPTED or UNKNOWN requests (queue timeouts, network errors) are never re-sent until their result is known.
    • B2C, B2B and B2B Express require an explicit idempotency_key, e.g. refund-order-1042. Reversal, tax and Ratiba derive one from the transaction ID, the PRN and phone + name respectively. For STK the key is optional.

Configuration

Variable Required Notes
MPESA_ENV sandbox (default) or production
MPESA_CONSUMER_KEY, MPESA_CONSUMER_SECRET ✅ From your Daraja app
MPESA_SHORTCODE most tools Paybill / store number (174379 in sandbox)
MPESA_PASSKEY STK Lipa na M-Pesa passkey
MPESA_INITIATOR_NAME B2C/B2B/status/balance/reversal API operator username
MPESA_SECURITY_CREDENTIAL same Pre-encrypted credential, or set the next two
MPESA_INITIATOR_PASSWORD + MPESA_CERT_PATH Server encrypts the password with the cert at startup
MPESA_CALLBACK_BASE_URL e.g. https://abc.ngrok-free.app; tools append /mpesa/stk/callback, /mpesa/b2c/result, …
MPESA_ALLOW_LIVE_MONEY_MOVEMENT true to allow production charges/payouts
MPESA_CALLBACK_LISTEN e.g. 127.0.0.1:8787: starts the built-in callback receiver
MPESA_CALLBACK_TOKEN with receiver 16+ random characters. Callback URLs become <base>/cb/<token>/…
MPESA_STATE_DB SQLite file for requests and results (default ~/.mpesa-mcp/state.db)
MPESA_TOOLSETS Comma list of stk,c2b,payouts,ops,qr,ratiba,billmanager (core is always on). Default: all
MPESA_OUTPUT_DIR Where QR PNGs are saved (default ~/.mpesa-mcp/qr)

Install & run

uvx mpesa-daraja-mcp setup     # guided: keys (hidden input), live check, save, register with your agents
uvx mpesa-daraja-mcp status    # what's configured (masked) + a live key check
uvx mpesa-daraja-mcp           # the MCP server itself, on stdio: what your agent runs

The server needs no flags or environment variables in your agent's config. Settings are read in this order, highest first:

  1. Environment variables, e.g. from the client's env block.
  2. A project .env in the folder the agent starts the server in, or the file named by MPESA_DOTENV. Only MPESA_* lines are read.
  3. The user config file that setup writes: ~/.config/mpesa-daraja-mcp/config.env (Windows: %APPDATA%\mpesa-daraja-mcp\config.env; override the folder with MPESA_CONFIG_DIR). It is readable only by you.

The server starts even when unconfigured. Tools then explain what's missing, and mpesa_setup_status lists the gaps for each toolset without revealing any values.

To register by hand: claude mcp add --scope user mpesa -- uvx mpesa-daraja-mcp. Every other agent is covered in docs/clients.md. The older mpesa-mcp command still works.

Results and callbacks

Every money or async tool returns one shape:

{"status": "ACCEPTED | SUCCESS | FAILED | UNKNOWN", "message": "...", "idempotency_key": "...",
 "duplicate": false, "ids": {"checkout_request_id": "..."}, "receipt": "...", "result_code": "...",
 "explanation": "...", "raw": {}}

To let the agent see final results, enable the built-in receiver:

export MPESA_CALLBACK_LISTEN=127.0.0.1:8787
export MPESA_CALLBACK_TOKEN=$(python -c "import secrets; print(secrets.token_urlsafe(24))")
ngrok http 8787                        # sandbox; use a reverse proxy with TLS in production
export MPESA_CALLBACK_BASE_URL=https://<tunnel-host>

Callbacks are stored in MPESA_STATE_DB:

  • mpesa_get_result(id) reads them.
  • mpesa_stk_push_and_wait returns the final outcome in one call.
  • Queue-timeout callbacks are recorded as UNKNOWN.
  • C2B validation requests are always accepted. Use your own receiver if you need to reject payments.

Without the receiver, mpesa_stk_push_and_wait still works through STK Query. For other APIs, paste a received payload into mpesa_parse_callback.

Context cost

Toolsets Tools Schema tokens (approx.)
all (default) 24 ~6,300
stk 9 ~2,100
stk,c2b 12 ~2,600

Pick the smallest set you need with MPESA_TOOLSETS.

Development

pip install -e ".[dev]"
pytest

Tests use respx to mock Daraja. Nothing hits the network.

License

MIT. Not affiliated with or endorsed by Safaricom PLC; M-Pesa and Daraja are trademarks of Safaricom PLC.

Metadata

Release files for mpesa-daraja-mcp 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mpesa-daraja-mcp 0.1.1
File Size Uploaded Provenance
mpesa_daraja_mcp-0.1.1.tar.gz 50.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for mpesa-daraja-mcp 0.1.1
File Interpreter ABI Platform
mpesa_daraja_mcp-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 88.6 kB

Release files / mpesa_daraja_mcp-0.1.1.tar.gz

Download URL mpesa_daraja_mcp-0.1.1.tar.gz
Size 50.6 kB
Tags Source
SHA-256 checksum
How to use checksums
234d5dcd455b865249e10b27d0ccc62971cbfa0d5b105b28363ad9204bdaedca
BLAKE2b-256 checksum
How to use checksums
96d6e5b5ba9df9d4893ddd503567eed197a6aac17d2c400eb5baaaf6749838e7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / mpesa_daraja_mcp-0.1.1-py3-none-any.whl

Download URL mpesa_daraja_mcp-0.1.1-py3-none-any.whl
Size 37.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9133d18b0d9fe3f0b45abe055d9dead9b9032ca5c1724b0fdbaf843151949be7
BLAKE2b-256 checksum
How to use checksums
5cb1d8e09016e4b6360ce2b9a4a1908d6cb3241a8a693819f320e84e420a728e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for mpesa-daraja-mcp 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for mpesa_daraja_mcp-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page