The Paystack MCP Server: What It Is and How to Use It
The Paystack MCP server is a local process that exposes Paystack API operations as MCP tools. AI assistants like Claude Code call these tools; the server makes the actual Paystack API calls using your secret key stored in an environment variable. Tools typically include: list_transactions, get_transaction, verify_payment, create_payment_link, list_customers. Configure in Claude Code via Settings → MCP Servers, pointing to the server process and setting PAYSTACK_SECRET_KEY as an environment variable. Always run locally or on your own infrastructure — never use a third-party hosted MCP server with your live key.
What MCP Is and How It Works with Paystack
Model Context Protocol (MCP) is an open standard that lets AI assistants use tools provided by external servers. The architecture has three parts:
- MCP host — the AI assistant (Claude Code, Claude API, another MCP client)
- MCP server — a process you run that exposes tools. For Paystack, this server holds your secret key and makes API calls
- Tools — named operations the AI can call. The AI sees tool names and descriptions; the server executes them
The security model: the AI calls tools by name with parameters. The MCP server validates the call, uses the secret key from its environment, makes the Paystack API request, and returns the result. The AI never sees the key — only the result.
What a Paystack MCP server exposes:
| Tool Name | Paystack Endpoint | Use Case |
|---|---|---|
| list_transactions | GET /transaction | "Show my last 20 transactions" |
| get_transaction | GET /transaction/:id | "Get details of transaction 12345" |
| verify_payment | GET /transaction/verify/:ref | "Verify payment with reference PAY_abc123" |
| list_customers | GET /customer | "How many customers do I have?" |
| create_payment_link | POST /paymentrequest | "Create a NGN 5,000 payment link for consulting" |
| get_balance | GET /balance | "What is my current Paystack balance?" |
Setting Up a Paystack MCP Server
// Simple Paystack MCP server in Node.js
// Install: npm install @modelcontextprotocol/sdk
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
var PAYSTACK_BASE = 'https://api.paystack.co';
var headers = () => ({ Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY });
var server = new Server({ name: 'paystack', version: '1.0.0' }, { capabilities: { tools: {} } });
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'list_transactions',
description: 'List Paystack transactions with optional status and date filters.',
inputSchema: { type: 'object', properties: { perPage: { type: 'number' }, status: { type: 'string' }, from: { type: 'string' }, to: { type: 'string' } } },
},
{
name: 'verify_payment',
description: 'Verify a Paystack payment by reference.',
inputSchema: { type: 'object', properties: { reference: { type: 'string' } }, required: ['reference'] },
},
{
name: 'get_balance',
description: 'Get the current Paystack account balance.',
inputSchema: { type: 'object', properties: {} },
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (req) => {
var args = req.params.arguments || {};
try {
if (req.params.name === 'list_transactions') {
var p = new URLSearchParams(args).toString();
var res = await fetch(PAYSTACK_BASE + '/transaction?' + p, { headers: headers() });
var data = await res.json();
return { content: [{ type: 'text', text: JSON.stringify(data.data, null, 2) }] };
}
if (req.params.name === 'verify_payment') {
var res = await fetch(PAYSTACK_BASE + '/transaction/verify/' + args.reference, { headers: headers() });
var data = await res.json();
return { content: [{ type: 'text', text: JSON.stringify(data.data, null, 2) }] };
}
if (req.params.name === 'get_balance') {
var res = await fetch(PAYSTACK_BASE + '/balance', { headers: headers() });
var data = await res.json();
return { content: [{ type: 'text', text: JSON.stringify(data.data, null, 2) }] };
}
} catch (err) {
return { content: [{ type: 'text', text: 'Error: ' + err.message }], isError: true };
}
});
var transport = new StdioServerTransport();
await server.connect(transport);
Add to Claude Code settings (~/.claude/settings.json):
{
"mcpServers": {
"paystack": {
"command": "node",
"args": ["/absolute/path/to/paystack-mcp-server/index.js"],
"env": {
"PAYSTACK_SECRET_KEY": "sk_test_your_key_here"
}
}
}
}
Learn More
See connecting the Paystack MCP server to Claude Code for configuration walkthrough.
Key Takeaways
- ✓MCP servers run locally and hold the Paystack secret key — AI assistants call tools, not the key directly.
- ✓MCP is a standard protocol: the same server can be used with Claude Code, Claude API agents, and other MCP-compatible clients.
- ✓Start with read-only tools (list, get, verify) before adding write tools (transfer, create_payment_link).
- ✓Always run the MCP server locally or on your own infrastructure — never with a third-party-hosted server.
- ✓MCP tools appear natively in Claude Code — just ask for what you need and the tool is called automatically.
Frequently Asked Questions
- What is the difference between MCP and function calling?
- Function calling (or tool use) is a capability of the LLM itself — the model outputs a structured tool call that your code executes. MCP is a standardized protocol for how tools are discovered and called across different AI clients and servers. MCP uses function calling under the hood, but adds a standard discovery mechanism (tools/list), a transport layer (stdio, HTTP), and a reusable server format that works across Claude Code, Claude API, and other MCP clients without rewriting the tool definitions each time.
- Can I use the same MCP server for both Claude Code development and production agent workflows?
- Yes, but use different keys. In Claude Code development, configure the MCP server with your test key (sk_test_...) in your local settings file. For production agent workflows, deploy the MCP server to your own infrastructure with your live key in a secure secret manager. The same server code works for both; only the key and deployment differ.
- What if Claude Code calls an MCP tool I did not expect?
- MCP servers only expose the tools you define in your ListTools handler. Claude Code can only call tools it knows about. If you expose only read-only tools (list, get, verify), Claude Code cannot trigger transfers or refunds — there is no tool to call. Start with read-only tools and add write tools only when you have safety rails and human-in-the-loop controls in place.
Ready to build real-world apps?
Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.
Apply to the McTaba Marathon