ask-only-pay-mcp
Click on "Deploy 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., "@ask-only-pay-mcpAsk to pay 19.00 EUR to Example Shop for a domain renewal"
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.
ask-only-pay-mcp
An MCP server that lets an AI agent ask for a payment or an account signup, but never do it.
A person approves each ask on a recap that a separate process, the approver, renders itself. The agent gets back only an id and a state: never a card, a password, or the recap.
AI agent ──MCP──▶ ask-only-pay-mcp ──HTTPS + mTLS──▶ approver ──▶ person at a terminal
"pay 19.00 EUR mints the id, stores the ask, reads the recap,
to Example Shop" checks every field shows the recap types approve / deny
◀── {approval_id, state} ────────◀── {approval_id, state, ref} ──┘Why
Agents that browse the web reach checkouts and signup forms. Letting one type a card number or a password is how money and accounts get lost, and a prompt-injected page can talk an agent into almost anything. The usual fix is a rule in the prompt: "ask before you pay". A rule can be argued with.
This project makes the agent's side powerless by construction instead:
property | how it is enforced |
It can only ask. | The client has three methods: ask to pay, ask to create an account, read a status. There is no approve, cancel or execute method, and the approver has no HTTP endpoint for one. Approval happens only on the approver's own console. |
Nothing secret comes back. | Every answer from the approver is parsed against a strict schema. An extra field (a recap, a card, a token) fails the parse, and the agent gets an error code instead of the data. The two short codes it may pass on ( |
What the person approves is what is recorded. | The approver renders the recap from the ask it stored. URLs are stored as the browser resolves them, so the URL shown is the URL passed on. An ask cannot be changed after it was made, and a decision is final. |
It cannot replay an ask. | The server mints the request id, never the agent. The approver refuses an id it has seen. |
Errors are codes. | A failure returns |
No secrets in arguments. | A card is a handle ( |
No silent fallback. | mTLS is required, and there is no switch to turn it off. Missing, unreadable or invalid certificates stop the server before it serves anything. |
The recap also defends the person against text the agent wrote:
No fake recaps. The approver cuts every line to 76 terminal columns itself (counting any character that is not plain ASCII as two columns, as wide as CJK or emoji get) and marks each further line with
>, so a fake[ask …]block hidden in a long reason can never begin a line. A decision is answered with what was decided (approved: PAY 19.00 EUR at shop.example), from the stored ask.No hidden characters. Control, bidi, zero-width, tag and other invisible characters, and stacks of combining marks, are shown as
\u{…}escapes, and runs of spaces become one.No look-alike sites. The site is shown in punycode, so
shop.exаmplewith a Cyrillicаshows asxn--…. A host too long for one line is shown by its end (....evil.com), which names who owns it.
Related MCP server: @looppause/mcp
Quick start
Needs Node.js 22.12 or later, and openssl for the certificates. The package is
on npm and has three commands: ask-only-pay-mcp (the MCP
server), ask-only-pay-approver and ask-only-pay-certs.
mkdir ask-only-pay && cd ask-only-pay
npx -y -p ask-only-pay-mcp ask-only-pay-certs certs # two separate CAs and two certificates, in ./certs1. Start the approver in a terminal of its own, in the same folder:
ASK_ONLY_PAY_APPROVER_CERT=certs/approver.pem \
ASK_ONLY_PAY_APPROVER_KEY=certs/approver.key \
ASK_ONLY_PAY_APPROVER_CA=certs/client-ca.pem \
npx -y -p ask-only-pay-mcp ask-only-pay-approver2. Add the MCP server to Claude Code (from the same folder):
claude mcp add --transport stdio ask-only-pay \
-e ASK_ONLY_PAY_URL=https://localhost:8443 \
-e ASK_ONLY_PAY_CLIENT_CERT="$PWD/certs/client.pem" \
-e ASK_ONLY_PAY_CLIENT_KEY="$PWD/certs/client.key" \
-e ASK_ONLY_PAY_CA="$PWD/certs/approver-ca.pem" \
-- npx -y ask-only-pay-mcp3. Ask Claude to buy something. The approver's terminal shows:
[ask K7Q2M4XZ3A] PAY 19.00 EUR
to: Example Shop
card: card-2
site: shop.example
checkout: https://shop.example/checkout/123
reason: (from the agent, unchecked) renew the domain
expires: in 10 min
approving: PAY 19.00 EUR at shop.example
approve K7Q2M4XZ3A or deny K7Q2M4XZ3AType approve K7Q2M4XZ3A or deny K7Q2M4XZ3A. The approver answers with what you decided:
K7Q2M4XZ3A: approved: PAY 19.00 EUR at shop.example
demo-3e40a688: no money moved (reference approver)list shows what is pending. Claude reads the decision with the status verb.
The tool
One tool, request, with three verbs:
verb | the agent gives | it gets back |
|
|
|
|
| the same |
|
|
|
The tool description tells the agent that "pending" and "denied" are normal answers, not obstacles to work around. Every field rule, error code and limit is in SPEC.md.
What the reference approver is, and is not
The approver here is a reference. On approval it records a reference starting demo- and moves no
money. A real deployment keeps the same three endpoints and puts a real payment or signup step behind
the approval.
Limits worth knowing:
Where the approver runs matters. Its console is the approval channel. Run it where the agent cannot type: another user account, another machine, or at least a terminal the agent has no access to. If the agent has a shell as the same user on the same machine, it can reach anything that user can, including holding the approver's connection places so asks fail (the safe failure).
Check the
siteandapprovinglines. The merchant name and the reason are the agent's words. The site and the closingapproving:line are the approver's own, from the stored URL.A recap needs a terminal at least 76 columns wide. On a narrower one the approver shows only the ids of new asks and asks you to widen it, since wrapped lines could let agent text start a row.
The client key only lets you ask. An agent that reads
client.keycan make more asks, which the person sees and denies. It cannot approve one. It can, though, fill the 50 pending places with junk and block real asks until they expire (10 minutes). Keep the key readable only by the MCP server's user.The card check is a net, not a wall. It catches a card number pasted by mistake. An agent set on leaking one could spell the digits out. The real defence is that the agent never sees a card.
Memory only. The approver keeps asks in memory. A restart forgets them, which denies nothing that was not yet approved.
Development
npm ci
npm run typecheck
npm run lint
npm test # unit, real mTLS, and end to end with the built programsTo run the quick start from a clone instead, use npm run certs -- certs, node dist/approver/main.js and
node "$PWD/dist/index.js" in place of the three npx commands.
The end-to-end tests start the built approver and the built MCP server as real processes, connect an MCP
client, and type approve and deny on the approver's console, as a person would. The mTLS tests use
fresh certificates from scripts/certs.mjs and check that the approver refuses a client with no
certificate, one from another CA, and its own certificate used as a client.
Related
money-guard-mcp: an MCP server that checks how a project handles money (float columns, unbalanced ledgers, tampered audit logs). This one gates the money an agent wants to spend.
agent-shell-gate: a permission gate for an agent's shell commands.
Licence
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Give any AI agent a way to ask a person — for approval, a decision, an answer or a review.
Set up human approval for your AI agents' tool calls.
Human-in-the-loop API for AI agents. CAPTCHA, OTP, KYC, and approvals by real humans.
Human-in-the-loop approval for agent actions, with verifiable action-bound receipts.
Related MCP Servers
- AlicenseAqualityDmaintenanceHuman-in-the-loop approval gate for AI agents. Your agent calls submit_approval before any irreversible action; a human reviews on a branded page; a signed webhook fires back with the decision.11MIT
- AlicenseNot gradedqualityCmaintenancePauses AI agent execution and routes approval requests to humans via Slack or email, with cryptographically signed proof of the human's decision.23 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to request human approvals with customizable forms, webhooks, and team features.25 npmMIT

Allowance MCPofficial
FlicenseNot gradedqualityDmaintenanceEnables AI agents to request purchase approval from humans, receive scoped virtual cards, complete checkout, and report receipts for audit.-