Safaricom Daraja MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Safaricom Daraja MCP Serversend 1000 KES to 254708374149 via STK push"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Safaricom Daraja MCP Server
A Model Context Protocol (MCP) server that integrates Safaricom's M-PESA Daraja API with Claude, enabling natural language payment processing and real-time transaction notifications.
π Features
STK Push Payments: Initiate M-PESA payment requests through natural language
Real-time Callbacks: Automatic payment notification handling with Flask server
Payment Tracking: Store and query payment history with read/unread status
Natural Language Interface: Interact with M-PESA through Claude conversations
Sandbox Testing: Full support for Daraja sandbox environment
Automated Testing: Comprehensive test suite for validation
Related MCP server: Daraja MCP
π Table of Contents
Prerequisites
Python 3.10+ installed on your system
Daraja API Account - Register at developer.safaricom.co.ke
ngrok (optional, for testing callbacks) - Download from ngrok.com
Claude Desktop (optional, for MCP integration)
Installation
1. Clone the Repository
# Clone the repository
git clone https://github.com/mboya/daraja-mcp.git
cd daraja-mcp
# Or if you already have the repository, navigate to it
cd daraja-mcp2. Set Up Virtual Environment
# Create virtual environment
python3 -m venv venv
# Activate virtual environment
# macOS/Linux:
source venv/bin/activate
# Windows:
venv\Scripts\activateYou should see (venv) in your terminal prompt.
3. Install Dependencies
# Install all required packages from requirements.txt
pip install -r requirements.txtThis will install:
mcp- Model Context Protocol serverrequests- HTTP library for API callsflask- Web framework for callback serverpython-dotenv- Environment variable managementgunicorn- WSGI HTTP server (for production deployment)
4. Configure Environment Variables
Create a .env file in the project root directory. The repository includes a .env.example file as a template.
Quick Setup:
# Copy the example file
cp .env.example .env
# Edit the .env file with your actual credentials
# Use your preferred text editor (nano, vim, code, etc.)
nano .envThen replace the placeholder values with your actual Daraja API credentials (see Getting Daraja Credentials).
Configuration
Environment Variables
Copy .env.example to .env and fill in your credentials. Key variables:
Variable | Purpose |
| OAuth (all APIs) |
| STK Push |
| B2C, B2B, balance, status, reversal |
|
|
| HTTPS base URL Safaricom can reach (ngrok locally, Railway in prod) |
|
|
| Default |
| IoT SIM Portal (Phase 5) β see |
Never commit .env. For production, set variables in your hosting dashboard (Railway, etc.).
Getting Daraja Credentials
1. Register on Daraja Portal
Create an account
Verify your email
2. Create an App
Navigate to "My Apps" β "Create New App"
Select APIs:
Lipa Na M-PESA Online
M-PESA Express (STK Push)
Submit your app
Get your credentials:
Consumer Key
Consumer Secret
Passkey (in app details)
3. Sandbox Test Credentials
For testing, use these sandbox values:
Business Short Code: 174379 (default sandbox)
Passkey: Check your app details on Daraja portal
Test Phone Numbers: 254708374149 (check Daraja docs for updated test numbers)
Test PIN: Varies by sandbox version (usually simulated automatically)
4. Production Credentials
Test thoroughly in sandbox
Apply for production access through Daraja portal
Complete KYC and business verification
Receive production credentials
Update
.envwith production values and setDARAJA_ENV=production
Usage
Run the server
Scenario | Command | Notes |
Claude Desktop (local) |
| stdio MCP + Flask callbacks on |
HTTP / cloud / Railway |
| See |
Local HTTP smoke test |
| Same routes as production, without gunicorn |
Verify the server:
curl http://127.0.0.1:3000/healthBoth server.py and server_http.py share the same callback routes and MCP tools via daraja_core.py. server.py talks to Claude over stdio and runs Flask in a background thread; server_http.py is a single Flask app for deployment.
For real Safaricom callbacks in sandbox, set PUBLIC_URL to an HTTPS URL (ngrok locally). See Callback setup.
Then configure Claude Desktop.
Testing
All tests are in test_daraja.py.
Command | What it runs |
| Full E2E (local): env, OAuth, MCP, webhooks, optional live API probes |
| CI-safe: no live Safaricom calls (GitHub Actions) |
| Auth + HTTP + callback smoke |
| All 17 webhook routes + MCP storage/retrieval |
| Above + POST webhooks through ngrok |
| Live sandbox: ngrok, real STK, IMSI, IoT |
| Live B2C payout + ngrok callback only |
| Everything: platform tests + live STK/B2C/IoT via ngrok (no skips) |
Exit code 0 on pass, 1 on failure. Warnings (e.g. IMSI sandbox 404) do not fail CI.
Optional: DARAJA_TEST_PHONE (default 254708374149), DARAJA_B2C_TEST_AMOUNT (default 10).
GitHub Actions CI
Workflow: .github/workflows/ci.yml (push/PR to main, workflow_dispatch).
Job | Command / check | Secrets |
compile |
| No |
platform |
| No |
webhooks |
| No |
gunicorn-smoke |
| No |
live-sandbox |
| Daraja + optional |
The live-sandbox job runs on workflow_dispatch or push to main; it runs live tests only when DARAJA_CONSUMER_KEY and DARAJA_CONSUMER_SECRET repository secrets are set (otherwise the job skips those steps).
Integrating with Claude Desktop
1. Locate Configuration File
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
2. Add MCP Server Configuration
{
"mcpServers": {
"daraja": {
"command": "/absolute/path/to/daraja-mcp/venv/bin/python",
"args": ["/absolute/path/to/daraja-mcp/server.py"],
"env": {
"DARAJA_CONSUMER_KEY": "your_consumer_key",
"DARAJA_CONSUMER_SECRET": "your_consumer_secret",
"DARAJA_SHORTCODE": "174379",
"DARAJA_PASSKEY": "your_passkey",
"DARAJA_ENV": "sandbox",
"CALLBACK_PORT": "3000",
"PUBLIC_URL": "https://your-ngrok-url.ngrok.io"
}
}
}
}Important:
Use absolute paths (not relative)
Use virtual environment's Python:
venv/bin/pythonUpdate PUBLIC_URL with your ngrok HTTPS URL
3. Restart Claude Desktop
Completely quit and reopen Claude Desktop to load the MCP server.
4. Verify Integration
In Claude Desktop, ask:
"Is the Daraja callback server working?"Claude should respond with server status information.
Claude Desktop and Railway
This section explains how Claude Desktop relates to a Railway deployment. Read this before pointing PUBLIC_URL at Railway while running Claude locally.
Two servers, two transports
File | Runs on | Protocol | Typical use |
| Your Mac/PC | stdio MCP | Claude Desktop (spawns local process) |
| Railway / VPS | HTTP ( | Production callbacks, curl, your own backend |
Claude Desktop does not connect to Railway as a native MCP server today. It expects a local command (server.py), not https://your-app.railway.app/mcp/call_tool.
Railwayβs HTTP endpoints are a REST-style tool API, not the full MCP stream Claude Desktop uses over stdio (or remote MCP URL/SSE).
Callbacks must hit the same process as Claude
STK payments and async callbacks are stored in memory in the running server process.
Setup | Works for Claude chat + payment history? |
Claude β local | Yes |
Claude β local | No β Safaricom posts to Railway; Claudeβs local process never sees those callbacks |
No Claude; only Railway | Yes for HTTP/callbacks; use |
Claude on Railway | Not supported without adding remote MCP transport to |
Rule: The host in PUBLIC_URL must be the same instance that handles MCP tools and stores payments.
Recommended setups
A β Claude Desktop + local server (recommended for chatting with Claude)
Configure Claude with
server.py(see Integrating with Claude Desktop).Run ngrok (or similar):
ngrok http 3000.Set
PUBLIC_URLin Claudeβsenvto the ngrok HTTPS URL (or in.envif you load it locally).Skip Railway for Claude, or use Railway only for unrelated HTTP integrations.
B β Railway only (no Claude Desktop)
Deploy via
Procfile(gunicorn server_http:app).Set Railway variables (see Railway Deployment), especially:
PUBLIC_URL=https://your-service.up.railway.appVerify:
curl https://your-service.up.railway.app/healthCall tools with HTTP:
curl -X POST https://your-service.up.railway.app/mcp/call_tool \ -H "Content-Type: application/json" \ -d '{"name":"get_notification_summary","arguments":{}}'Register Safaricom callback URLs using your Railway domain (see Callback routes).
C β Railway for callbacks + Claude (common mistake)
Setting Claudeβs local PUBLIC_URL to Railway looks convenient but breaks payment tracking in Claude: STK/B2C results land on Railway, while get_recent_payments reads the local store.
Use setup A instead, or setup B without Claude until shared storage or remote MCP is implemented.
Railway env vars (Claude-free deployment)
Variable | Value |
| Daraja credentials (same as local) |
|
|
|
|
Do not set | Railway sets |
Initiator and IoT variables are optional; see .env.example.
Available Tools
Once configured, Claude can use these tools:
1. stk_push
Initiate an STK Push payment request.
Example:
"Send a payment request for 500 KES to 0712345678 for order #INV-001"Parameters:
phone_number- Customer phone (254XXXXXXXXX or 07XXXXXXXX)amount- Amount in KES (minimum 1)account_reference- Reference like invoice/order numbertransaction_desc- Description of transaction
2. stk_query
Check the status of a payment request.
Example:
"Check the status of checkout request ws_CO_12345"Parameters:
checkout_request_id- ID returned from STK push
3. get_recent_payments
View recent payment notifications.
Example:
"Show me the last 10 payments"Parameters:
limit- Number of payments to retrieve (default: 10, max: 50)
4. get_payment_details
Get details of a specific payment.
Example:
"Show me details for receipt QAR7I8K3LM"Parameters:
checkout_request_id- Or -mpesa_receipt- M-PESA receipt number
5. mark_payment_read
Mark a notification as read.
Example:
"Mark payment ws_CO_12345 as read"6. get_notification_summary
Get summary of all notifications.
Example:
"How many unread payments do I have?"7. get_callback_status
Check if callback server is running.
Example:
"Is the callback server working?"Additional tools (B2C, B2B, C2B, Ratiba, Pull, IMSI, IoT) are listed under API coverage vs Postman.
Phase 1 β B2C, B2B, C2B, balance, status, reversal
Tool | Description |
| Pay customer (B2C) β needs initiator credentials |
| B2Pochi wallet payout |
| Business-to-business transfer |
| Register validation/confirmation URLs |
| Sandbox C2B payment simulation |
| Query paybill balance (async callback) |
| Query by M-PESA transaction ID |
| Reverse a transaction |
| List B2C/B2B/C2B/balance/reversal callbacks |
| Debug OAuth token |
Callback Setup
Safaricom requires HTTPS callback URLs reachable from the internet. Localhost works for simulated webhooks (python test_daraja.py --callbacks); use a tunnel or deployed host for real STK/B2C results.
Automated tests can start ngrok for you (--live, --b2c, --all).
Why You Need ngrok (or Similar Tunneling Service)
The Problem:
M-PESA Daraja API requires HTTPS callbacks (not HTTP)
Safaricom's servers need to reach your callback endpoint from the internet
Your local development server (
localhost:3000) is not accessible from the internetFirewalls and NAT prevent external access to your local machine
The Solution: ngrok creates a secure tunnel that:
β Exposes your local server to the internet via HTTPS
β Provides a public URL that Safaricom can reach
β Automatically handles SSL/TLS encryption
β Allows real-time testing without deploying to production
β Shows all incoming requests in a web interface for debugging
How It Works:
Safaricom Servers β ngrok HTTPS URL β ngrok Tunnel β Your Local Server (localhost:3000)Local Testing with ngrok
1. Install ngrok
# macOS
brew install ngrok
# Linux (using snap)
sudo snap install ngrok
# Windows
# Download from https://ngrok.com/download
# Or use Chocolatey: choco install ngrok
# Or download directly from https://ngrok.com/downloadSign up for free: Visit ngrok.com and create an account to get your authtoken.
2. Authenticate ngrok (First Time Only)
ngrok config add-authtoken YOUR_AUTHTOKEN_HERE3. Start ngrok Tunnel
# Forward HTTPS traffic to your local port 3000
ngrok http 3000Output:
Session Status online
Account Your Name (Plan: Free)
Version 3.x.x
Region United States (us)
Latency 45ms
Web Interface http://127.0.0.1:4040
Forwarding https://abc123.ngrok.io -> http://localhost:3000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00Important: Copy the Forwarding HTTPS URL (e.g., https://abc123.ngrok.io)
4. Update Configuration
Update PUBLIC_URL in your .env file:
PUBLIC_URL=https://abc123.ngrok.ioOr update Claude Desktop config with the ngrok URL.
Note: Free ngrok URLs change each time you restart ngrok. For a static URL, upgrade to a paid plan or use ngrok's reserved domains feature.
5. Restart Server
# Stop the server (Ctrl+C)
# Restart with new PUBLIC_URL
python server.py6. Verify ngrok is Working
Check ngrok web interface:
Open http://localhost:4040 in your browser
You'll see all requests being forwarded through ngrok
Useful for debugging callback issues
Test the tunnel:
# Test health endpoint through ngrok
curl https://abc123.ngrok.io/health
# Should return:
# {"status":"healthy","callback_url":"https://abc123.ngrok.io/mpesa/callback",...}7. Keep ngrok Running
Important: Keep the ngrok terminal window open while testing. If you close it, the tunnel stops and Safaricom won't be able to reach your callback endpoint.
Pro Tip: Run ngrok in a separate terminal or use a process manager like tmux or screen:
# Using tmux
tmux new -s ngrok
ngrok http 3000
# Press Ctrl+B then D to detach (keeps running in background)ngrok Alternatives
If you prefer other tunneling services:
Cloudflare Tunnel (cloudflared) - Free, no account needed for basic use
cloudflared tunnel --url http://localhost:3000localtunnel - Simple npm-based tunnel
npx localtunnel --port 3000serveo - SSH-based tunnel (no installation)
ssh -R 80:localhost:3000 serveo.net
However, ngrok is recommended because:
Most reliable and stable
Best documentation and community support
Web interface for request inspection
Easy to use and configure
Production Callback Setup
For production, deploy to a server with:
Public HTTPS endpoint (SSL certificate required)
Static IP or domain name
Firewall rules allowing incoming HTTPS traffic
Monitoring and logging
Popular options:
AWS EC2 with Elastic IP
DigitalOcean Droplet
Heroku with SSL
Google Cloud Run
Railway (recommended - see deployment guide below)
Example nginx configuration:
server {
listen 443 ssl;
server_name api.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location /mpesa/ {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}Railway Deployment (Quick Start)
Railway is an excellent choice for deploying this MCP server because it:
β Provides HTTPS endpoints automatically
β Handles SSL certificates
β Easy environment variable configuration
β Automatic deployments from Git
β Free tier available for testing
Railway Deployment Steps
Create Railway Account
Visit railway.app
Sign up with GitHub/GitLab
Create New Project
Click "New Project"
Select "Deploy from GitHub repo" (or upload code)
Configure Environment Variables In Railway dashboard, add these environment variables:
DARAJA_CONSUMER_KEY=your_consumer_key DARAJA_CONSUMER_SECRET=your_consumer_secret DARAJA_SHORTCODE=174379 DARAJA_PASSKEY=your_passkey DARAJA_ENV=sandbox CALLBACK_PORT=3000 PUBLIC_URL=https://your-app-name.railway.appNote: On Railway, the app is served by gunicorn which binds to
0.0.0.0:$PORTautomatically; you don't need to setCALLBACK_HOST.Deploy
Railway will automatically detect
Procfileandrailway.jsonThe
Procfileusesserver_http.pywith gunicornRailway will build and deploy automatically
Get Your Public URL
Railway provides a public HTTPS URL (e.g.,
https://your-app.railway.app)Update
PUBLIC_URLenvironment variable with this URLRailway will restart the service automatically
Verify Deployment
# Test health endpoint curl https://your-app.railway.app/health # Should return: # {"status":"healthy","callback_url":"https://your-app.railway.app/mpesa/callback",...}
Important Notes:
Railway automatically provides HTTPS, so no ngrok needed in production
The
PUBLIC_URLmust match your Railway app URL exactlyUse
server_http.py(configured inProcfile) for Railway deploymentsRailway handles port binding automatically via
$PORTenvironment variable
Troubleshooting
Startup
Issue | Fix |
| Set |
Port 3000 in use |
|
|
|
Health check fails | Ensure server is running; |
Common Issues
1. "Failed to get access token"
Causes:
Invalid Consumer Key or Secret
Wrong environment (sandbox vs production)
Network connectivity issues
Solutions:
# Test authentication manually
python -c "
from dotenv import load_dotenv
import os, base64, requests
load_dotenv()
key = os.getenv('DARAJA_CONSUMER_KEY')
secret = os.getenv('DARAJA_CONSUMER_SECRET')
auth = base64.b64encode(f'{key}:{secret}'.encode()).decode()
r = requests.get('https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials',
headers={'Authorization': f'Basic {auth}'})
print(r.json())
"2. "Callback server not responding"
Solutions:
# Check if port 3000 is available
lsof -i :3000
# Kill any process using the port
kill -9 <PID>
# Restart server
python server.py3. "MCP server not found in Claude"
Solutions:
Verify config file path is correct
Use absolute paths in configuration
Ensure virtual environment Python path is correct
Check Claude Desktop logs: Help β View Logs
Restart Claude Desktop completely
4. "No callbacks received"
Solutions:
Verify ngrok is running:
curl https://your-url.ngrok.io/healthCheck PUBLIC_URL environment variable
Ensure ngrok URL is HTTPS (required by Safaricom)
View ngrok request logs: http://localhost:4040
Check firewall settings
5. "Invalid phone number"
Solutions:
Use format: 254XXXXXXXXX (not +254 or 07XX)
Sandbox: Use test numbers from Daraja portal
Remove spaces, dashes, or special characters
Debug Commands
# Check server process
ps aux | grep server.py
# Test callback health
curl http://localhost:3000/health
# Test ngrok forwarding
curl https://your-ngrok-url.ngrok.io/health
# View Python errors
tail -f server.log
# Check Claude logs
# macOS: ~/Library/Logs/Claude/
# Windows: %APPDATA%\Claude\logs\Getting Help
Check Daraja API documentation: developer.safaricom.co.ke/Documentation
Review ngrok request inspector: http://localhost:4040
Check Claude Desktop logs
Verify all environment variables are set correctly
Test each component independently
Security Best Practices
1. Credential Management
β Never commit credentials to version control
β Use
.envfiles with.gitignoreβ Rotate credentials regularly
β Use different credentials for sandbox and production
β Store production secrets in secure vaults (AWS Secrets Manager, etc.)
2. Network Security
β Use HTTPS for all callbacks (required by Safaricom)
β Implement webhook signature verification
β Restrict callback endpoint to Safaricom IPs
β Use firewall rules to limit access
β Enable rate limiting
3. Application Security
β Validate all input data
β Sanitize phone numbers and amounts
β Implement request logging
β Add authentication for sensitive operations
β Use environment-specific configurations
4. Data Privacy
β Don't log sensitive data (PINs, full card numbers)
β Mask phone numbers in logs
β Implement data retention policies
β Comply with data protection regulations
β Encrypt data at rest and in transit
5. Monitoring
β Set up error alerting
β Monitor callback success rates
β Track failed transactions
β Log all API calls
β Implement health checks
Production Deployment
Pre-deployment Checklist
Thoroughly tested in sandbox environment
Obtained production credentials from Daraja
Set up production server with SSL/TLS
Configured firewall and security groups
Implemented proper logging and monitoring
Set up error alerting
Documented deployment process
Created backup and recovery plan
Tested with small amounts first
Configured auto-restart on failure
Deployment Steps
1. Prepare Server
# Update system
sudo apt update && sudo apt upgrade -y
# Install Python
sudo apt install python3.10 python3.10-venv -y
# Install nginx (for reverse proxy)
sudo apt install nginx -y
# Install supervisor (for process management)
sudo apt install supervisor -y2. Deploy Application
# Create application directory
sudo mkdir -p /opt/daraja-mcp
sudo chown $USER:$USER /opt/daraja-mcp
cd /opt/daraja-mcp
# Clone or copy application files
# Set up virtual environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Create production .env
nano .env
# Add production credentials3. Configure Supervisor
Create /etc/supervisor/conf.d/daraja-mcp.conf:
[program:daraja-mcp]
command=/opt/daraja-mcp/venv/bin/python /opt/daraja-mcp/server.py
directory=/opt/daraja-mcp
user=www-data
autostart=true
autorestart=true
stderr_logfile=/var/log/daraja-mcp/error.log
stdout_logfile=/var/log/daraja-mcp/access.log
environment=PRODUCTION="true"4. Configure nginx
Create /etc/nginx/sites-available/daraja-mcp:
server {
listen 80;
server_name api.yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}5. Start Services
# Reload supervisor
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start daraja-mcp
# Enable and restart nginx
sudo ln -s /etc/nginx/sites-available/daraja-mcp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
# Check status
sudo supervisorctl status daraja-mcp
curl https://api.yourdomain.com/healthMonitoring and Maintenance
# View logs
sudo tail -f /var/log/daraja-mcp/error.log
# Restart service
sudo supervisorctl restart daraja-mcp
# Check resource usage
htop
# Monitor nginx access
sudo tail -f /var/log/nginx/access.logPostman collection (API reference)
The repo includes Safaricomβs official Postman collection as the source-of-truth checklist for Daraja endpoints:
File | |
Postman link | |
Sandbox base |
|
Production base |
|
Use this collection when adding MCP tools: each request maps to a Daraja API product. Coverage vs this server is summarized in API coverage below.
API coverage vs Postman
Status | Count | Notes |
Phase 1 (MCP tools) | 10 | STK, B2C, B2Pochi, B2B, C2B register/simulate, balance, status, reversal |
Phase 2 (MCP tools) | 2 | M-PESA Ratiba standing orders (paybill, buy goods) |
Phase 3 (MCP tools) | 3 | Pull API register/query, SFC Verify org lookup |
Phase 4 (MCP tools) | 2 | IMSI / SWAP CheckATI |
Phase 5 (MCP tools) | 14 | IoT SIM Portal messaging and SIM operations |
Helpers | 6 | Payments, async callbacks, summary, access token, callback status |
Postman coverage | Complete | All 35 collection requests have MCP tools |
Initiator APIs need DARAJA_INITIATOR_NAME, DARAJA_INITIATOR, and DARAJA_SECURITY_CREDENTIAL in .env.
Callback routes (prefix with your HTTPS PUBLIC_URL):
Route | Purpose |
| STK Push |
| B2C / B2Pochi |
| B2B |
| C2B |
| Account balance |
| Transaction status |
| Reversal |
| M-PESA Ratiba standing order events |
| Pull API transaction notifications |
Phase 2 β M-PESA Ratiba (standing orders)
Tool | Description |
| Schedule recurring paybill payments from a customer |
| Schedule recurring till/buy-goods payments |
Frequency codes: 1 once, 2 daily, 3 weekly, 4 monthly, 5 bi-monthly, 6 quarterly, 7 half-year, 8 yearly (or aliases like monthly, weekly).
Dates: start_date and end_date as yyyymmdd (e.g. 20260101).
Phase 3 β Pull API & SFC Verify
Tool | Description |
| Register pull callback ( |
| Fetch transactions for a datetime range |
| Look up party/org by identifier type and value |
Pull query dates: YYYY-MM-DD H:MM:SS (e.g. 2024-08-04 8:36:00).
Phase 4 β IMSI / SWAP
Tool | Endpoint |
|
|
|
|
Sandbox note: 404 Not found usually means the IMSI product is not enabled on your Daraja app, or the test MSISDN is not provisioned for IMSI. Enable IMSI CheckATI in the developer portal, confirm sandbox test numbers, and set DARAJA_TEST_PHONE if needed.
Phase 5 β IoT SIM Portal
Tool | Purpose |
| Search messages |
| Filter by date/status |
| Delete thread |
| List messages |
| Send SMS to SIM |
| Delete message by ID |
| List SIMs in VPN group |
| SIM lifecycle |
| Customer info |
| Activate SIM |
| Activation trends |
| Rename asset |
| Location info |
| Suspend/unsuspend |
API Reference
Daraja API Endpoints
Authentication
GET https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials
Authorization: Basic <base64(consumer_key:consumer_secret)>STK Push
POST https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest
Authorization: Bearer <access_token>
Content-Type: application/json
{
"BusinessShortCode": "174379",
"Password": "<base64(shortcode+passkey+timestamp)>",
"Timestamp": "20240108143022",
"TransactionType": "CustomerPayBillOnline",
"Amount": 100,
"PartyA": "254712345678",
"PartyB": "174379",
"PhoneNumber": "254712345678",
"CallBackURL": "https://your-domain.com/callback",
"AccountReference": "Order123",
"TransactionDesc": "Payment for Order123"
}STK Query
POST https://api.safaricom.co.ke/mpesa/stkpushquery/v1/query
Authorization: Bearer <access_token>
Content-Type: application/json
{
"BusinessShortCode": "174379",
"Password": "<base64(shortcode+passkey+timestamp)>",
"Timestamp": "20240108143022",
"CheckoutRequestID": "ws_CO_08012024123456789"
}MCP Server Endpoints
Health Check
GET http://localhost:3000/health
Response:
{
"status": "healthy",
"environment": "sandbox",
"callback_url": "http://localhost:3000/mpesa/callback",
"callback_urls": { "stk": "...", "b2c_result": "...", "ratiba": "...", "pull": "..." },
"unread_payments": 0,
"unread_callbacks": 0
}M-PESA Callback
POST http://localhost:3000/mpesa/callback
Content-Type: application/json
{
"Body": {
"stkCallback": {
"MerchantRequestID": "29115-34620561-1",
"CheckoutRequestID": "ws_CO_08012024123456789",
"ResultCode": 0,
"ResultDesc": "The service request is processed successfully.",
"CallbackMetadata": {
"Item": [
{"Name": "Amount", "Value": 100},
{"Name": "MpesaReceiptNumber", "Value": "QAR7I8K3LM"},
{"Name": "TransactionDate", "Value": 20240108143022},
{"Name": "PhoneNumber", "Value": 254712345678}
]
}
}
}
}Project Structure
daraja-mcp/
βββ venv/ # Virtual environment (not in git)
βββ daraja_core.py # Shared Daraja client, callbacks, MCP tools
βββ daraja_iot.py # IMSI and IoT SIM Portal APIs (Phases 4β5)
βββ server.py # MCP server for local Claude Desktop (stdio)
βββ server_http.py # MCP server for cloud deployment (HTTP)
βββ test_daraja.py # Unified test suite (see Testing)
βββ .github/workflows/ci.yml # CI: platform, webhooks, gunicorn, optional live
βββ Procfile # Railway: gunicorn server_http:app
βββ railway.json # Railway platform configuration
βββ .env.example # Environment template (copy to .env)
βββ requirements.txt # Python dependencies
βββ README.md # This file
βββ Safaricom APIs.postman_collection.json # Postman reference (optional local copy)File | Use |
| Claude Desktop (stdio) |
| Production / HTTP MCP + callbacks |
| Daraja client, callbacks, core MCP tools |
| IMSI + IoT SIM Portal tools |
| All automated tests |
Contributing
Contributions are welcome! Please follow these guidelines:
Fork the repository
Create a feature branch (
git checkout -b feature/amazing-feature)Commit your changes (
git commit -m 'Add amazing feature')Push to the branch (
git push origin feature/amazing-feature)Open a Pull Request
Development Setup
Follow Installation, then run python test_daraja.py --platform before opening a PR.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Safaricom Daraja API - M-PESA API platform
Anthropic MCP - Model Context Protocol
Flask - Web framework for callbacks
ngrok - Secure tunneling for local development
Support
Documentation: developer.safaricom.co.ke/Documentation
Daraja Support: support@safaricom.co.ke
MCP Documentation: modelcontextprotocol.io
Issues: GitHub Issues
Changelog
v1.0.0 (2024-01-08)
Initial release
STK Push implementation
Real-time callback handling
Payment notification storage
Automated testing suite
Claude Desktop integration
Comprehensive documentation
Made with β€οΈ for the M-PESA ecosystem
For questions or support, please open an issue on GitHub or contact the maintainers.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mboya/daraja-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server