Skip to main content
Glama
zerotaldev

io.github.zerotaldev/ozow

by zerotaldev

ozow-mcp

An MCP server for Ozow, the South African instant EFT ("pay by bank") gateway. It lets an AI assistant create and track Ozow payment requests.

It is locked to Ozow's staging environment unless production is explicitly unlocked twice over. That is the main design decision; the rest of this file explains it.

Node 20+. One runtime dependency (the MCP SDK) plus zod.

The safety model

An MCP server that wraps a payments API gives a language model the ability to move money. That deserves more care than a typical API wrapper, so:

1. Staging by default. Ozow selects environment by base URL, not a request flag, so a staging-configured server has no route to production. This is structural, not a check that can be forgotten.

2. Production needs two independent keys turned. OZOW_ENV=production and OZOW_ALLOW_PRODUCTION=i-understand-this-moves-real-money. Setting only the first makes the server refuse to start. It never silently downgrades to staging - an operator who believes they are live but is not ends up in a worse position than one who cannot start at all.

3. Per-call confirmation, but only where it means something. In production, ozow_create_payment requires confirm="CONFIRM LIVE PAYMENT" exactly. In staging it does not: confirmation friction on imaginary money teaches people to click through, which is worse than no friction at all. The tool description tells the model, in as many words, not to supply that phrase on its own initiative.

4. An amount ceiling. OZOW_MAX_AMOUNT (default R1000) caps any single request, so a miscounted zero hits a wall instead of a bank account.

5. Honest tool annotations. Read-only tools declare readOnlyHint; payment and cancel tools declare destructiveHint. Clients that surface these can ask the user before the call rather than after.

6. Secrets stay out of output. The environment tool masks the client ID and never returns the secret. There is a test that fails if either leaks.

Related MCP server: Investec OpenAPI MCP Server

Setup

npm install
cp .env.example .env     # fill in from the Ozow Portal
npm run check            # validates config and credentials, moves no money

You need an Ozow merchant account first, then ask Ozow support or your account manager to enable One API clients in the portal, where the client ID and secret are created.

Tools

Tool

Reads/writes

Notes

ozow_environment

read

Which environment, limits, whether money is real. No network call.

ozow_verify_credentials

read

Confirms the client ID and secret get a token.

ozow_create_payment

write

Returns a redirectUrl for the payer. Confirmation required in production.

ozow_get_transactions

read

Whether a payment request was paid.

ozow_cancel_payment

write

Irreversible.

Connecting a client

{
  "mcpServers": {
    "ozow": {
      "command": "node",
      "args": ["/absolute/path/to/ozow-mcp/src/index.mjs"],
      "env": {
        "OZOW_CLIENT_ID": "...",
        "OZOW_CLIENT_SECRET": "...",
        "OZOW_SITE_CODE": "XXX-XXX-XXX",
        "OZOW_ENV": "staging"
      }
    }
  }
}

Tests

npm test

20 tests. The guard tests are pure and need no credentials; the server tests spawn the real binary and speak MCP to it over stdio, checking that the staging default holds, that production refuses to start unacknowledged, that over-ceiling and non-https requests are rejected before any network call, and that secrets never reach the output.

Status and caveats

Early. Written against Ozow's One API (one.ozow.com/v1), not the legacy i-Pay Payment API - confirm with Ozow which applies to your account, as the published docs cover both and disagree.

One correction to Ozow's own docs: their quick-start gives the token endpoint as <api host>/v1/token. That path returns 404 on both hosts. Tokens are actually issued by a separate auth host - auth.ozow.com/token and stagingauth.ozow.com/token - which answer client_credentials with standard OAuth2 errors. This server uses those. The /v1/payments paths in the docs are correct (they return 401, not 404, without a valid token).

Not yet covered: payouts (money out), which Ozow gates behind separate approval and staging tests; refunds, which their docs describe as a dashboard action rather than an API call; and webhook verification for transaction.complete.

Endpoint paths were probed directly and behave as expected for unauthenticated requests. The server has not yet been run against a live Ozow staging account with real credentials, so request and response bodies are built from the documentation rather than from observed traffic. Expect to adjust field names on first contact.

Licence

MIT

Publishing

The order matters: the official MCP Registry is upstream of the directories, so publishing there is what makes the rest happen.

1. GitHub and npm

gh repo create zerotaldev/ozow-mcp --public --source=. --push
npm publish

package.json carries "mcpName": "io.github.zerotaldev/ozow". The registry checks that marker matches the name in server.json; if they drift, the publish is rejected as an ownership failure.

2. The official MCP Registry

mcp-publisher login github      # device-code OAuth, grants io.github.zerotaldev/*
mcp-publisher publish --dry-run # validates without publishing
mcp-publisher publish

The GitHub login is what entitles the io.github.zerotaldev/* namespace. If you would rather publish under your own domain as com.ciyane/ozow, use mcp-publisher login dns --domain ciyane.com instead and change name in server.json to match — the namespace must agree with the login method or the publish is refused.

server.json validates against the 2025-12-11 schema. Note the registry caps description at 100 characters.

3. Glama

glama.json in the repo root claims the listing for the zerotaldev maintainer. Glama also discovers servers from GitHub, and you can add one manually with Add MCP Server on their servers page using the repository URL. Their FAQ says most submissions pass automatically within minutes.

4. PulseMCP

Nothing to submit. PulseMCP paused direct submissions while they rework ingestion, and they build listings by scraping the official registry and GitHub. Publishing in step 2 is what gets you there.

Available Tools

5 tools
ozow_cancel_paymentCancel an Ozow payment requestA
DestructiveIdempotent

Cancel a payment request that has not been completed. Irreversible: the payer can no longer use that link.

NameRequiredDescriptionDefault
paymentIdYesThe payment id to cancel

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds the concrete consequence that annotations cannot express: the payer's link becomes unusable and the action is irreversible. It does not describe the failure mode for an already-completed payment, which is the main remaining behavioral question.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the action and followed immediately by the irreversibility warning. No filler or restatement of the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter destructive mutation with no output schema, the description covers purpose, precondition and consequence well. Minor gap: no mention of the error/behavior when cancelling an already-completed payment, and no note on whether the paymentId comes from ozow_create_payment or ozow_get_transactions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter with 100% schema description coverage ('The payment id to cancel'), so the schema carries the semantics. The description adds nothing about the payment id's format or where it comes from, which is acceptable given the coverage baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Cancel a payment request') plus a scope condition ('that has not been completed'). No sibling tool overlaps with cancellation, so an agent can place it immediately relative to ozow_create_payment and ozow_get_transactions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The precondition 'has not been completed' tells the agent when this tool is applicable, which is the key usage signal for a cancel operation. It stops short of saying what happens if the precondition is violated or whether any verification step (e.g. ozow_get_transactions) should precede cancellation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ozow_create_paymentCreate an Ozow payment requestA
Destructive

Create a payment request and return a redirectUrl for the payer to complete in their bank. In production this collects REAL money and requires explicit confirmation from the human you are working for - never supply the confirmation phrase on your own initiative. Amounts are in rands.

NameRequiredDescriptionDefault
amountYesAmount in ZAR, e.g. 149.99
confirmNoRequired in production only. Must be exactly "CONFIRM LIVE PAYMENT".
notifyUrlNohttps URL for the server-to-server notification
returnUrlYeshttps URL the payer returns to after paying
expiresInMinutesNoHow long the request stays valid. Default 30, max 1440.
merchantReferenceYesYour own order reference
beneficiaryReferenceNoLetters and numbers only, max 20. Shown on the bank statement.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructive=true and openWorld=true, and the description goes beyond them by disclosing the real-money consequence, the human-confirmation precondition, the prohibition on self-confirming, and that the result is a redirectUrl the payer completes at their bank. Those are exactly the authorization and side-effect details an agent needs before invoking a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: what it does and returns first, then the critical safety constraint, then the currency unit. No filler and the highest-risk information is front-loaded rather than buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully states that the tool returns a redirectUrl, and it covers the production safety gate. It leaves out the sandbox-vs-production behavior for the confirm parameter and gives no retry/idempotency guidance for a non-idempotent money-moving call, but is otherwise sufficient to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter including amount, confirm, and expiresInMinutes is already documented in the schema. The description adds only 'Amounts are in rands', which largely restates the schema's 'Amount in ZAR, e.g. 149.99', so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Create a payment request') and names a concrete outcome ('return a redirectUrl for the payer to complete in their bank'), which lets an agent tell it apart from siblings like ozow_cancel_payment or ozow_get_transactions. It doesn't explicitly contrast itself with those siblings, keeping it just short of 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operative guidance: in production it collects REAL money and requires explicit confirmation from the human, and the agent must never supply the confirmation phrase itself. This defines when and how to act, but does not name alternative tools or describe the sandbox/test path an agent might use first.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ozow_environmentShow Ozow environmentA
Read-only

Report which Ozow environment this server is connected to, whether it can move real money, and the configured limits. Call this first - and always before any payment - so you know whether you are in staging or production.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and openWorldHint=false, so the safety profile is covered. The description adds meaningful context beyond that: it discloses that the response indicates whether real money can move and what limits are configured, which is the key risk signal an agent needs. It stops short of describing the exact response shape, but that is a minor gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the imperative 'Call this first', zero filler. Every clause carries either purpose or usage instruction.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must convey what comes back, and it does: environment name, real-money flag, and limits. It is slightly underspecified about the exact fields/format of the limits, but the agent has enough to decide to call it and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline 4 applies. The description correctly implies a no-argument introspection call.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Report which Ozow environment this server is connected to') plus the scope of what it reveals (real-money capability, configured limits). An agent can immediately distinguish it from ozow_create_payment or ozow_verify_credentials.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit sequencing guidance: 'Call this first - and always before any payment.' It names the precondition (before payments) and the decision it supports (staging vs production), leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ozow_get_transactionsList transactions for a paymentB
Read-only

List the transactions recorded against a payment request, to check whether it was paid. Read-only.

NameRequiredDescriptionDefault
toDateNoISO date, defaults to now
fromDateNoISO date, defaults to 7 days ago
paymentIdYesThe payment id returned by ozow_create_payment

TDQS

B3.3/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description's only behavioral statement, 'Read-only,' merely restates the readOnlyHint annotation and adds no new context. The openWorldHint=true annotation is never addressed, and nothing is said about pagination, result limits, or what happens with the default date window.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with the verb and scope front-loaded and no wasted clauses. The read-only note is redundant but costs only a few words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description at least conveys what the results mean (transactions tied to a payment, used to confirm payment status). It still omits whether multiple transactions can be returned, ordering, and pagination behavior, leaving gaps for a list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so every parameter (paymentId, fromDate, toDate defaults) is already documented in the schema. The description adds only the loose notion of a 'payment request' and no format or filtering detail beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (List) and resource (transactions recorded against a payment request), and frames the intent ('to check whether it was paid'). It clearly differs from mutation siblings like ozow_create_payment or ozow_cancel_payment, though it doesn't explicitly contrast with ozow_verify_credentials or ozow_environment.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'to check whether it was paid' implies the when: after a payment request exists, to confirm settlement. However, there is no explicit guidance on alternatives (e.g., when to use this versus ozow_verify_credentials) or on prerequisites beyond the indirect mention of a payment request.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ozow_verify_credentialsVerify Ozow credentialsA
Read-only

Check that the configured client ID and secret can obtain an access token. Makes no changes and moves no money.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and openWorldHint, and the description adds meaningful context: it authenticates against the Ozow API using stored client ID/secret and has no side effects on data or funds. That 'no changes, moves no money' guarantee is genuinely useful reassurance beyond the annotation, though it slightly restates readOnlyHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with the core action front-loaded and the safety guarantee as a supporting clause. Nothing is wasted and nothing is missing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, no-output-schema verification tool, the description covers what it does, what it needs (configured credentials), and its side-effect profile. An agent has everything required to decide to call it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the schema baseline of 4 applies. The description correctly implies that credentials come from configuration rather than being passed in, which is useful framing for an empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: checks that configured client ID and secret can obtain an access token. This is clearly distinct from the payment-oriented siblings (create_payment, get_transactions, cancel_payment), so an agent can tell what this tool is for without inspecting the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies the pre-flight use case (validate credentials before transacting) and the closing clause signals it is safe to call casually. It does not explicitly name an alternative or a 'do not use when' condition, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedozow_cancel_payment
    • First observedozow_create_payment
    • First observedozow_environment
    • First observedozow_get_transactions
    • First observedozow_verify_credentials

TDQS

A3.9/5.0

Scored across 5 tools

Disambiguation4/5

Each tool has a clearly distinct role: credential check, environment report, payment creation, transaction lookup, and cancellation. There is slight conceptual overlap between ozow_verify_credentials and ozow_environment (both configuration preflight checks), but the descriptions make the boundary clear.

Naming Consistency4/5

All tools use a consistent ozow_ prefix and snake_case with verb_noun phrasing (verify_credentials, create_payment, get_transactions, cancel_payment). ozow_environment is a noun-only outlier, but overall the pattern is predictable.

Tool Count5/5

Five tools is a tight, well-scoped surface for a payment integration. Every tool earns its place covering a distinct step in the payment flow.

Completeness3/5

The core flow (create, check status, cancel) is covered, but there are notable gaps: no refund, no settlement/payout inspection, no webhook or notification handling, and transaction listing is only scoped per payment request rather than a general ledger. Agents handling post-payment reconciliation would hit dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers