<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: junter1989k-ai</title>
    <description>The latest articles on DEV Community by junter1989k-ai (@junter1989kai).</description>
    <link>https://dev.to/junter1989kai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4021404%2F4c486840-e372-44b1-a646-8f548fea4e96.png</url>
      <title>DEV Community: junter1989k-ai</title>
      <link>https://dev.to/junter1989kai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/junter1989kai"/>
    <language>en</language>
    <item>
      <title>A stranger on Reddit suggested a guardrail for my payment MCP servers. It shipped to 30 countries in one day.</title>
      <dc:creator>junter1989k-ai</dc:creator>
      <pubDate>Wed, 08 Jul 2026 22:04:56 +0000</pubDate>
      <link>https://dev.to/junter1989kai/a-stranger-on-reddit-suggested-a-guardrail-for-my-payment-mcp-servers-it-shipped-to-30-countries-26en</link>
      <guid>https://dev.to/junter1989kai/a-stranger-on-reddit-suggested-a-guardrail-for-my-payment-mcp-servers-it-shipped-to-30-countries-26en</guid>
      <description>&lt;p&gt;Last week I posted about a family of MCP servers that let AI agents accept payments — Pix in Brazil, UPI in India, GCash in the Philippines, PromptPay in Thailand, one stateless server per country.&lt;/p&gt;

&lt;p&gt;The first substantive reply came from someone who works on agent guardrails. Their point, paraphrased:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Trust boundaries around &lt;em&gt;money custody&lt;/em&gt; are solved by your design (the server never holds funds). But there's a second boundary you haven't addressed: &lt;strong&gt;a well-formed request can still be a request the agent should never have made.&lt;/strong&gt; Amount limits, allow-lists, human-approval thresholds — checked deterministically &lt;em&gt;before&lt;/em&gt; anything is signed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They were right, and the interesting part was figuring out how to do this &lt;strong&gt;statelessly&lt;/strong&gt; — these servers have no database, no accounts, no config storage. Credentials ride on HTTP headers per request. Where does policy live?&lt;/p&gt;

&lt;h2&gt;
  
  
  The answer: policy rides the same channel as credentials
&lt;/h2&gt;

&lt;p&gt;The MCP client config (where a human pastes API keys) is something the &lt;strong&gt;agent cannot touch&lt;/strong&gt;. Model output never edits &lt;code&gt;claude_desktop_config.json&lt;/code&gt; or a &lt;code&gt;.mcp.json&lt;/code&gt;. So policy set there has a property no in-band instruction has: &lt;strong&gt;the model cannot relax its own limits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two headers, checked before any signature is computed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;x-agentpay-max-amount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
&lt;span class="na"&gt;x-agentpay-approval-above&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;x-agentpay-max-amount&lt;/code&gt;&lt;/strong&gt; — hard cap in the local currency's major unit. Anything above is refused with a readable &lt;code&gt;POLICY_BLOCKED&lt;/code&gt; error that tells the agent to ask the human, not to retry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;x-agentpay-approval-above&lt;/code&gt;&lt;/strong&gt; — softer: amounts above return an &lt;strong&gt;unsigned draft&lt;/strong&gt; (all payment parameters, &lt;code&gt;payment_url: null&lt;/code&gt;, &lt;code&gt;approval_required: true&lt;/code&gt;) for the human to review. There is deliberately &lt;strong&gt;no bypass parameter&lt;/strong&gt; — the only way to proceed is for the owner to change the header in their client config.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A weak local model can't be prompt-injected past this, because the check isn't in the prompt. It's a deterministic &lt;code&gt;if&lt;/code&gt; before the crypto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before any PSP call or signature:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enforce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amountMajor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;needsApproval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;policy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draftResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amountMajor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  From suggestion to 30 countries
&lt;/h2&gt;

&lt;p&gt;The same ~40-line &lt;code&gt;policy.js&lt;/code&gt; dropped into every server, because they all share one shape: validate → policy gate → sign/call → return hosted checkout URL. The rollout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Day 0&lt;/strong&gt;: shipped to the 20 live countries (Asia + Latin America + US/UK/NL/SG/NG), behavior tests + full e2e regression.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day 1&lt;/strong&gt;: baked into the country &lt;em&gt;generator&lt;/em&gt;, so the next wave was born with it — Turkey (iyzico), Saudi Arabia &amp;amp; UAE (Tap / mada), Kenya (Flutterwave / M-Pesa), Ghana &amp;amp; South Africa (Paystack), Poland (Stripe / BLIK), Germany &amp;amp; Belgium (Mollie / Klarna / Bancontact), France. That's 30 countries, every one policy-gated from its first request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each server's e2e suite now asserts both branches with a fake key against the real gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PASS policy cap -&amp;gt; POLICY_BLOCKED
PASS policy approval -&amp;gt; unsigned draft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the daily fingerprint canary (a watchdog that hits every gateway with fake keys and asserts the error fingerprint hasn't changed) grew to 30 endpoints / 36 canaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Policy for AI agents belongs outside the model.&lt;/strong&gt; Headers set by a human in client config are a surprisingly good policy channel: zero storage, per-merchant, and structurally out of the agent's reach.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draft mode beats refusal for the human-in-the-loop case.&lt;/strong&gt; Returning the parameters (but no live link) gives the human something to approve instead of a dead end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community feedback compounds when your architecture is uniform.&lt;/strong&gt; One suggestion became a family-wide feature in a day because all 30 servers share one skeleton.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The family hub with all 30 endpoints: &lt;a href="https://mcp.wishpool.app/" rel="noopener noreferrer"&gt;mcp.wishpool.app&lt;/a&gt; — each country page's &lt;code&gt;llms.txt&lt;/code&gt; documents the two policy headers. All open source (MIT), all on the official MCP Registry under &lt;code&gt;app.wishpool/*&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you're building agent guardrails and see a boundary I've missed — that's exactly the kind of comment that turned into this feature. 🙏&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>payments</category>
      <category>showdev</category>
    </item>
    <item>
      <title>AI agents can now accept payments in 10 countries — Pix, UPI, GCash, PromptPay, konbini, KakaoPay (one MCP server each)</title>
      <dc:creator>junter1989k-ai</dc:creator>
      <pubDate>Wed, 08 Jul 2026 17:32:28 +0000</pubDate>
      <link>https://dev.to/junter1989kai/ai-agents-can-now-accept-payments-in-10-countries-pix-upi-gcash-promptpay-konbini-kakaopay-5g5a</link>
      <guid>https://dev.to/junter1989kai/ai-agents-can-now-accept-payments-in-10-countries-pix-upi-gcash-promptpay-konbini-kakaopay-5g5a</guid>
      <description>&lt;p&gt;Last week I built an MCP server so AI agents could accept payments in Taiwan. This week the same pattern grew into &lt;strong&gt;ten countries&lt;/strong&gt; — one MCP server per country, each wrapping the payment rails that country actually uses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Country&lt;/th&gt;
&lt;th&gt;MCP endpoint&lt;/th&gt;
&lt;th&gt;Local rails&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🇹🇼 Taiwan&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ECPay + NewebPay, convenience stores, &lt;strong&gt;government e-invoices&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇯🇵 Japan&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-jp.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;konbini&lt;/strong&gt; コンビニ, PayPay (KOMOJU)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇰🇷 Korea&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-kr.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;cards, &lt;strong&gt;KakaoPay / NaverPay&lt;/strong&gt; (Toss Payments)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇮🇩 Indonesia&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-id.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;GoPay, QRIS&lt;/strong&gt;, Alfamart cash (Midtrans)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇮🇳 India&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-in.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;UPI&lt;/strong&gt; — Google Pay / PhonePe / Paytm (Razorpay)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇧🇷 Brazil&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-br.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Pix&lt;/strong&gt;, boleto (Mercado Pago)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇵🇭 Philippines&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-ph.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;GCash&lt;/strong&gt;, Maya (PayMongo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇹🇭 Thailand&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-th.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;PromptPay QR&lt;/strong&gt;, TrueMoney (Opn/Omise)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇲🇾 Malaysia&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-my.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;FPX&lt;/strong&gt; online banking, DuitNow QR (Billplz)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🇻🇳 Vietnam&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://mcp-vn.wishpool.app/mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;MoMo&lt;/strong&gt; wallet QR — zero-setup sandbox demo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All ten are on the &lt;a href="https://registry.modelcontextprotocol.io/v0/servers?search=wishpool" rel="noopener noreferrer"&gt;official MCP Registry&lt;/a&gt; under &lt;code&gt;app.wishpool/*&lt;/code&gt;, MIT-licensed, zero runtime dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why per-country servers?
&lt;/h2&gt;

&lt;p&gt;Global processors skip the rails locals actually pay with. A Japanese buyer wants to pay at 7-Eleven. An Indian buyer scans UPI. A Brazilian uses Pix. A Filipino uses GCash. Those rails were built for humans clicking through checkout pages — there is no agent-ready API for "let my customer pay the way they normally pay."&lt;/p&gt;

&lt;p&gt;Each server is a &lt;strong&gt;stateless translation layer&lt;/strong&gt; (~500 lines of Node, no database): it turns one country's hosted-checkout API into two or three MCP tools. Same shape everywhere:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;create_payment_link&lt;/code&gt; → returns a hosted checkout URL for the buyer&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;query_payment_status&lt;/code&gt; → pull-based polling, no webhooks needed&lt;/li&gt;
&lt;li&gt;(Korea only) &lt;code&gt;confirm_payment&lt;/code&gt; — Toss requires a server-side approval within 10 minutes of buyer authentication, so the flow is exposed honestly as a third tool&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Bring-your-own credentials&lt;/strong&gt;: the merchant's API keys ride along as HTTP headers on every request and are used in memory only. Funds always flow buyer → gateway → merchant. The servers never touch money — which also keeps them clean legally in every jurisdiction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing for weak models
&lt;/h2&gt;

&lt;p&gt;Most MCP clients aren't frontier models — plenty are small local models that skim tool descriptions. So the guidance lives &lt;strong&gt;in the tool results, at the right moment&lt;/strong&gt;, not in documentation nobody reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payment_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"next_steps"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"1. Give payment_url to the buyer and ask them to open it and pay."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"2. Call query_payment_status with order_id=KR2607091542XYZ every ~15 seconds."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"3. When status becomes IN_PROGRESS, immediately call confirm_payment (you have only 10 minutes)."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every &lt;code&gt;query_payment_status&lt;/code&gt; state carries a one-line &lt;code&gt;next&lt;/code&gt; hint: &lt;em&gt;"Buyer authenticated — NOW call confirm_payment"&lt;/em&gt;, &lt;em&gt;"Link expired — create a new one"&lt;/em&gt;. A 7B model can follow that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verification without opening ten merchant accounts
&lt;/h2&gt;

&lt;p&gt;I didn't register merchant accounts in ten countries (each KYC would take weeks). Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spec verification&lt;/strong&gt;: every request format checked against official docs, and for signature-based gateways, byte-compared against production SDKs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fake-key live probes&lt;/strong&gt;: every e2e suite fires a fake key at the real production API and asserts the gateway's own auth error comes back (&lt;code&gt;UNAUTHORIZED_KEY&lt;/code&gt; in Korean from Toss, &lt;code&gt;Authentication failed&lt;/code&gt; from Razorpay…). That proves the wire path is real.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-setup demos where possible&lt;/strong&gt;: Taiwan (ECPay's public sandbox) and Vietnam (MoMo's documented public sandbox credentials) do &lt;strong&gt;real&lt;/strong&gt; sandbox transactions end-to-end — try them with no credentials at all.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A daily canary&lt;/strong&gt; replays those probes against every gateway and emails me if any fingerprint changes — so if a PSP moves an endpoint, I know before the first user does. This already paid off during the build: PayMongo's legacy Links API turned out to be dead (404 behind the gateway), which the probe caught, and I shipped Checkout Sessions instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the verification is the BYO architecture itself: the first merchant who brings a real key &lt;strong&gt;is&lt;/strong&gt; the live test, failures are loud and readable, and a beacon mails me the moment a real-key call fails for any non-auth reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Point any remote-MCP client (Claude Desktop / Claude Code / Cursor) at the Vietnam or Taiwan endpoint — both work instantly with no credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vietnam-payments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp-vn.wishpool.app/mcp"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask your agent to "create a 50,000 VND payment link" and watch it come back with a real MoMo sandbox checkout URL.&lt;/p&gt;

&lt;p&gt;All repos: &lt;a href="https://github.com/junter1989k-ai?tab=repositories&amp;amp;q=payments-mcp" rel="noopener noreferrer"&gt;github.com/junter1989k-ai&lt;/a&gt; — feedback and country requests welcome.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>payments</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built an MCP server so AI agents can accept payments in Taiwan</title>
      <dc:creator>junter1989k-ai</dc:creator>
      <pubDate>Wed, 08 Jul 2026 13:03:53 +0000</pubDate>
      <link>https://dev.to/junter1989kai/i-built-an-mcp-server-so-ai-agents-can-accept-payments-in-taiwan-2cc0</link>
      <guid>https://dev.to/junter1989kai/i-built-an-mcp-server-so-ai-agents-can-accept-payments-in-taiwan-2cc0</guid>
      <description>&lt;p&gt;I run a small education business in Taiwan. When I started letting AI agents handle operations, they kept hitting the same wall: Taiwan's payment gateways and the government e-invoice system are built for humans clicking through web pages. No agent-usable API anywhere.&lt;/p&gt;

&lt;p&gt;So I wrapped that layer into a remote MCP server: &lt;strong&gt;&lt;a href="https://mcp.wishpool.app/mcp" rel="noopener noreferrer"&gt;https://mcp.wishpool.app/mcp&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;create_payment_link&lt;/strong&gt; — TWD payment link (credit card / ATM / convenience store / mobile). Aggregates two local gateways, ECPay 綠界 and NewebPay 藍新, behind one tool — the agent picks with a &lt;code&gt;provider&lt;/code&gt; field, or it auto-selects from which credential headers you send.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;query_payment_status&lt;/strong&gt; — pull-based payment check, no webhook needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;issue_einvoice / invalid_einvoice&lt;/strong&gt; — Taiwan legally requires a government e-invoice (電子發票) for every sale; agents can now issue and void them, including company invoices with a tax ID (統一編號).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Three design constraints that shaped everything
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Never touch funds
&lt;/h3&gt;

&lt;p&gt;Taiwan's Electronic Payment Act makes holding other people's money without a license a criminal offense (3–10 years). So this is a stateless translation layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You bring your own merchant credentials as HTTP headers on each request&lt;/li&gt;
&lt;li&gt;Money flows buyer → gateway → merchant directly&lt;/li&gt;
&lt;li&gt;The server stores &lt;strong&gt;nothing&lt;/strong&gt; — no database at all. A payment link is literally the signed checkout form encoded into the URL itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Zero-setup demo
&lt;/h3&gt;

&lt;p&gt;ECPay publishes public sandbox credentials, so with no headers every tool runs against the official test environment. Add the server URL to Claude, Cursor, or any remote-MCP client and you can create a (fake) payment link in about a minute.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Zero dependencies
&lt;/h3&gt;

&lt;p&gt;Hand-written JSON-RPC over streamable HTTP. The whole thing is a few small files of plain Node — no framework, no SDK. When you sign payment requests for a living, you want to read every line that touches the crypto.&lt;/p&gt;

&lt;h2&gt;
  
  
  The crypto part (the scary part)
&lt;/h2&gt;

&lt;p&gt;Payment gateways here use bespoke signing schemes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ECPay: SHA-256 over a sorted query string with .NET-style URL encoding&lt;/li&gt;
&lt;li&gt;NewebPay: AES-256-CBC encrypted trade payloads + SHA-256 &lt;code&gt;TradeSha&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For NewebPay (which has no public sandbox), I cross-checked my implementation against two independent production SDKs and verified the AES output is byte-identical to OpenSSL before shipping. Merchants bring their own credentials, so their first sandbox call is the final integration test — and error messages pass through readable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why aggregate gateways?
&lt;/h2&gt;

&lt;p&gt;A single-gateway wrapper dies the day that gateway ships its own official MCP. An aggregation layer is a different product: one tool surface across many local gateways, in a market where every gateway has its own bespoke API. That's also the world-scaling plan — the big providers build the global highways; this covers the local roads they don't bother with (Taiwan e-invoices today; the same pattern fits Japan's konbini payments or Korea's local PSPs later).&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint: &lt;code&gt;https://mcp.wishpool.app/mcp&lt;/code&gt; (streamable HTTP)&lt;/li&gt;
&lt;li&gt;Source (MIT): &lt;a href="https://github.com/junter1989k-ai/taiwan-payments-mcp" rel="noopener noreferrer"&gt;https://github.com/junter1989k-ai/taiwan-payments-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Official MCP Registry: &lt;code&gt;app.wishpool/taiwan-payments-mcp&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Honest caveats: the NewebPay path is verified against reference implementations and OpenSSL but not yet with a live merchant account, and the demo sandbox never moves real money. If you're building agents that need to do real-world commerce in markets the big providers skip — I'd love to compare notes.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>payments</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
