<?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: whiteknightonhorse</title>
    <description>The latest articles on DEV Community by whiteknightonhorse (@whiteknightonhorse).</description>
    <link>https://dev.to/whiteknightonhorse</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3833834%2Fdffc57b7-7dd6-4e34-9cc7-7b628ffec695.png</url>
      <title>DEV Community: whiteknightonhorse</title>
      <link>https://dev.to/whiteknightonhorse</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whiteknightonhorse"/>
    <language>en</language>
    <item>
      <title>What Happens to the $0.001 When an AI Agent Pays for an API Call</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Tue, 19 May 2026 04:56:58 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/what-happens-to-the-0001-when-an-ai-agent-pays-for-an-api-call-389a</link>
      <guid>https://dev.to/whiteknightonhorse/what-happens-to-the-0001-when-an-ai-agent-pays-for-an-api-call-389a</guid>
      <description>&lt;p&gt;An AI agent pays $0.001 in USDC for one API call. What actually happens to that money? The honest answer involves gas fees, upstream provider charges, a database write, and the smallest margin you've ever seen.&lt;/p&gt;

&lt;p&gt;I run a pay-per-call API gateway with 618 tools across 191 providers. Every paid call settles on Base mainnet via x402. Here is the actual journey of one penny — broken down with numbers from production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters in 2026
&lt;/h2&gt;

&lt;p&gt;The "pay per call" business model for AI agent tools is finally real. Two things made it possible: the &lt;a href="https://github.com/coinbase/x402" rel="noopener noreferrer"&gt;x402 protocol&lt;/a&gt; gave agents a standard way to send payments inside an HTTP 402 response, and stablecoin settlement on Base mainnet made the gas cost low enough that a $0.001 call is not absurd.&lt;/p&gt;

&lt;p&gt;But the math is tighter than you'd think. Anyone who tells you "just charge $0.001 per call and you'll be rich" has not actually looked at where the money goes. Let me walk you through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four buckets of $0.001
&lt;/h2&gt;

&lt;p&gt;When an agent sends a $0.001 (1000 microUSDC) payment for a standard read-tier tool, the money lands in roughly four places:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bucket&lt;/th&gt;
&lt;th&gt;Typical share&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Base mainnet gas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.0003–$0.0008&lt;/td&gt;
&lt;td&gt;Submitting &lt;code&gt;transferWithAuthorization&lt;/code&gt; on-chain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Upstream API cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.0000–$0.0005&lt;/td&gt;
&lt;td&gt;What the underlying provider charges (often $0 for free-tier APIs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gateway compute&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~$0.00005&lt;/td&gt;
&lt;td&gt;Postgres + Redis + viem + Pino logs for one request&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Margin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;the rest&lt;/td&gt;
&lt;td&gt;Whatever survives the above&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Base mainnet finality is fast (~1–3 seconds) and gas is cheap, but it is &lt;strong&gt;not zero&lt;/strong&gt;. Submitting a single &lt;code&gt;transferWithAuthorization&lt;/code&gt; call against the USDC contract on Base costs roughly 50,000 gas units. At a typical Base gas price of 0.01 gwei and ETH at $3,000, that is &lt;code&gt;50000 × 0.01 × 10^-9 × 3000 ≈ $0.0015&lt;/code&gt;. Sometimes more, sometimes less.&lt;/p&gt;

&lt;p&gt;If gas spikes during a Base congestion event, a single settle can cost $0.005. At that moment, your "comfortable" $0.001 price tier is operating at a loss until gas calms down. This is why margin discipline matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five pricing tiers (with real tools)
&lt;/h2&gt;

&lt;p&gt;We don't use a flat $0.001 across all tools. Different upstream costs and different data volumes demand tiered pricing. Here is the actual distribution across our 618 tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Price range&lt;/th&gt;
&lt;th&gt;Tool count&lt;/th&gt;
&lt;th&gt;Example tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0.000&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Some platform metadata endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;$0.0005–$0.0011&lt;/td&gt;
&lt;td&gt;346&lt;/td&gt;
&lt;td&gt;Most reads — crypto, weather, jobs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mid&lt;/td&gt;
&lt;td&gt;$0.002–$0.005&lt;/td&gt;
&lt;td&gt;119&lt;/td&gt;
&lt;td&gt;Heavier reads, AI inference&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;$0.005–$0.10&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;OCR, image gen, paid upstreams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premium&lt;/td&gt;
&lt;td&gt;$0.10+&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;SMS sends, domain registrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The min price we charge is &lt;strong&gt;$0.0005&lt;/strong&gt; (Polymarket read endpoints — high volume, low upstream cost, low gas overhead per settle when batched). The max is &lt;strong&gt;$29.99&lt;/strong&gt; for an AIPush market report (heavy LLM work upstream, multi-hour generation) or &lt;strong&gt;$21.00&lt;/strong&gt; for a domain registration through NameSilo (passes the actual domain price through with thin margin).&lt;/p&gt;

&lt;p&gt;That's a 60,000× range from cheapest to most expensive. The same payment rail handles all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cache-hit shortcut
&lt;/h2&gt;

&lt;p&gt;Roughly 25–40% of incoming requests in our pipeline are cache hits. We don't call the upstream for those — Redis already has the answer.&lt;/p&gt;

&lt;p&gt;The business question: should a cache-hit cost the same as a fresh call?&lt;/p&gt;

&lt;p&gt;We charge &lt;strong&gt;10% of the full price&lt;/strong&gt; for a cache hit. Here's why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/pipeline/stages/ledger-write.stage.ts&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CACHE_HIT_COST_MULTIPLIER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&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;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cacheHit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chargeAmount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toolPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;CACHE_HIT_COST_MULTIPLIER&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;writeDirectCharge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chargeAmount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a $0.001 tool, cache-hit billing is $0.0001. That sounds tiny, but the math is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We skip ESCROW (no $0.0005 gas for full settle — cache hits go through balance debit, not on-chain settle)&lt;/li&gt;
&lt;li&gt;We skip the upstream provider call (no cost at all)&lt;/li&gt;
&lt;li&gt;We do one Redis read + one Postgres write&lt;/li&gt;
&lt;li&gt;Net cost to us: roughly $0.00001&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the agent saves 90%, we still net ~$0.00009 margin per cache hit. Volume is the multiplier — at 25K cache hits per day, that's $2.25/day from cache hits alone. Not a fortune, but it pays for the Redis container.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the call fails
&lt;/h2&gt;

&lt;p&gt;Refund math is where most pay-per-call systems break. The naive design — "take the money first, fail later, manually refund" — gets you a class-action lawsuit.&lt;/p&gt;

&lt;p&gt;Our model: every paid request &lt;strong&gt;reserves&lt;/strong&gt; USDC at ESCROW stage, before the provider call. Then:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;What happens to the reserved USDC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Provider returns 200&lt;/td&gt;
&lt;td&gt;Finalize escrow → mark PAID in ledger → 1 PG transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provider returns 5xx&lt;/td&gt;
&lt;td&gt;Refund escrow → mark REFUNDED → 1 PG transaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provider times out (10s)&lt;/td&gt;
&lt;td&gt;Refund (same path)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline crashes mid-call&lt;/td&gt;
&lt;td&gt;Reconciliation job sweeps within 60-120s → refund&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent retries with same Idempotency-Key&lt;/td&gt;
&lt;td&gt;We don't charge twice — idempotent at PG level&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The escrow + finalize is &lt;strong&gt;one atomic PG transaction&lt;/strong&gt; — either both succeed or both roll back. No partial state, no orphaned escrows. The reconciliation job is a fail-safe for the unhappy path where the API process crashes between reserve and finalize.&lt;/p&gt;

&lt;p&gt;For the agent this means: &lt;strong&gt;you only pay for what worked&lt;/strong&gt;. A 5xx from the upstream doesn't cost you anything. This is the single biggest reason agents trust pay-per-call gateways — the alternative ("we charged your card, sorry the API is down") is the SaaS pricing model that AI agent developers are actively trying to escape.&lt;/p&gt;

&lt;h2&gt;
  
  
  A worked example: agent calls finnhub.quote for AAPL
&lt;/h2&gt;

&lt;p&gt;Let's trace one real request end-to-end. Tool: &lt;code&gt;finnhub.quote&lt;/code&gt;, price: $0.001, cache miss (first call this minute).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/finnhub.quote/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Payment: eyJ4NDAyVmVyc2lvbiI..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"symbol": "AAPL"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 13-stage pipeline runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AUTH          (Redis lookup, ~1ms)
IDEMPOTENCY   (Redis check + set, ~1ms)
CONTENT_NEG   (header parse, &amp;lt;0.1ms)
SCHEMA_VALID  (Zod parse, &amp;lt;1ms)
TOOL_STATUS   (in-memory cache hit, &amp;lt;0.1ms)
CACHE_CHECK   (Redis lookup, ~1ms)  ← miss, continue
RATE_LIMIT    (Redis dual-bucket, ~1ms)
ESCROW        (PG reserve 1000 microUSDC, ~3ms)
PROVIDER_CALL (Finnhub API, ~200ms)  ← real cost
ESCROW_FINAL  (PG finalize, ~3ms)
LEDGER_WRITE  (PG insert, ~2ms)  ← x402 settle queued
CACHE_SET     (Redis write, ~1ms)
RESPONSE      (JSON serialize, &amp;lt;1ms)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total: ~213ms for the agent. After the response is sent, our facilitator submits the on-chain settle (~1-3 seconds, async — doesn't block the agent).&lt;/p&gt;

&lt;p&gt;The income/expense for this one call:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Revenue:&lt;/strong&gt; $0.001 USDC from agent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Upstream cost:&lt;/strong&gt; $0 (Finnhub free tier covers our volume)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-chain gas:&lt;/strong&gt; $0.00045 (50K gas × 0.01 gwei × $3000/ETH)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compute:&lt;/strong&gt; ~$0.00005 (CPU + Redis + PG amortized)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Net margin:&lt;/strong&gt; $0.0005 per call&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Half a cent. The whole business has to scale on that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the math actually works at scale
&lt;/h2&gt;

&lt;p&gt;At our current volume of ~26K x402 settles per month, the gross margin per settle is roughly $0.0005. That's $13/month in gross margin just from x402-paid calls. Not a lot.&lt;/p&gt;

&lt;p&gt;The trick is volume × tier mix. The 119 mid-tier tools ($0.002–$0.005 price) and the 35 high-tier tools ($0.005+) have proportionally higher margins. A $0.005 OCR call has $0.004 of margin after upstream + gas. One of those covers the gas for ten $0.001 reads.&lt;/p&gt;

&lt;p&gt;The economics flip from "barely profitable" to "comfortable" once you hit ~50K settles/month, because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fixed gas cost per settle stays constant (it's an externality, not our cost basis)&lt;/li&gt;
&lt;li&gt;Per-request compute amortizes across a bigger denominator&lt;/li&gt;
&lt;li&gt;Cache hit ratio improves with traffic (more requests → better cache locality)&lt;/li&gt;
&lt;li&gt;Tier mix stabilizes (early users skew toward "I want to try it" cheap tools; later users skew toward production workloads on expensive tools)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why pay-per-call pricing models tend to look unprofitable at the start and then suddenly work once volume crosses a threshold. The thresholds for our gateway, today, look like:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Monthly settles&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt; 5K&lt;/td&gt;
&lt;td&gt;Operating at a loss after operator wallet top-up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5K–25K&lt;/td&gt;
&lt;td&gt;Breakeven, no growth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25K–100K&lt;/td&gt;
&lt;td&gt;Modest profit, infrastructure paid for&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100K+&lt;/td&gt;
&lt;td&gt;Real margin, can fund new provider integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;Three things, in order of how much they surprised me:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gas is the dominant cost line for cheap tools.&lt;/strong&gt; I assumed compute would be the biggest cost; it's actually the on-chain settlement. This means optimizing the database is less impactful than optimizing the settle path. We've since moved to self-hosted facilitator (cuts out third-party SaaS fees on top of gas) and we batch where the protocol allows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache hits subsidize the cheap tiers.&lt;/strong&gt; The 10% cache-hit billing is what makes the $0.0005 tier viable. Without it, polymarket read tools would lose money per call. With it, they net $0.00009 per cache hit and break even on cache misses — and 25-40% of requests are cache hits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Refund math is a feature, not a cost center.&lt;/strong&gt; Every refund we issue (5xx, timeout, agent cancellation) costs us the gas we already burned on the failed settle attempt. But the agent's confidence in the system — "I only pay for what worked" — is what makes them set up automated workflows that drive volume. The refund overhead is a fixed cost of doing pay-per-call business, and it's worth it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;If you want to see this in action without writing any code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Get an API key (auto-registration, no signup)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/agents/register &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"agent_name": "experiment", "agent_version": "1.0.0"}'&lt;/span&gt;

&lt;span class="c"&gt;# 2. Try a free-tier call (no payment needed for free tools)&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/iss.position/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{}'&lt;/span&gt;

&lt;span class="c"&gt;# 3. Try a paid tool — you'll get a 402 with the exact payment details&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/finnhub.quote/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"symbol": "AAPL"}'&lt;/span&gt;
&lt;span class="c"&gt;# → HTTP 402 with x402 challenge: pay $0.001 USDC on Base to &amp;lt;address&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 402 response includes everything an x402-compatible agent needs to sign and submit the payment. Real agents do this automatically. You can also call it from any MCP-compatible client at &lt;code&gt;https://apibase.pro/mcp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The full open-source implementation is at &lt;a href="https://github.com/whiteknightonhorse/APIbase" rel="noopener noreferrer"&gt;github.com/whiteknightonhorse/APIbase&lt;/a&gt;. The pricing logic lives in &lt;code&gt;config/tool_provider_config.yaml&lt;/code&gt;, the cache-hit math is in &lt;code&gt;src/pipeline/stages/ledger-write.stage.ts&lt;/code&gt;, and the escrow + refund cycle is in &lt;code&gt;src/services/escrow.service.ts&lt;/code&gt;. Fork it. Steal the ideas. Just don't forget the gas math.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;APIbase is a unified MCP gateway with 618 tools across 191 providers, paid per call via x402 USDC on Base or MPP USDC on Tempo. The economics in this article are real production numbers.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How We Replaced Our x402 Payment Facilitator in a Single Afternoon</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Fri, 01 May 2026 07:32:28 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/how-we-replaced-our-x402-payment-facilitator-in-a-single-afternoon-f84</link>
      <guid>https://dev.to/whiteknightonhorse/how-we-replaced-our-x402-payment-facilitator-in-a-single-afternoon-f84</guid>
      <description>&lt;p&gt;This morning I got an email from Coinbase Developer Platform (CDP):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Your organization has reached the monthly free tier limit for settled x402 payments using the CDP Facilitator. Additional settled payments will require a payment method on file.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fine. I tried to add a payment method. CDP rejected my KYC documents three times. There is no support channel for KYC issues — just "try again later".&lt;/p&gt;

&lt;p&gt;By that point we were already settling roughly &lt;strong&gt;869 x402 payments per day&lt;/strong&gt; through CDP for our MCP gateway (576 tools, 177 providers, public API at &lt;code&gt;apibase.pro&lt;/code&gt;). When the free tier flipped, every paid call would start failing on &lt;code&gt;/settle&lt;/code&gt;. Agents would get 5xx, escrow would leak, customer USDC would orphan.&lt;/p&gt;

&lt;p&gt;I had two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Wait for KYC, lose revenue, hope it resolves.&lt;/li&gt;
&lt;li&gt;Replace CDP. Build our own facilitator. Today.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I picked option 2. Here is how it went.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an x402 facilitator actually does
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/coinbase/x402" rel="noopener noreferrer"&gt;x402 protocol&lt;/a&gt; standardizes pay-per-call HTTP. The agent (payer) signs an &lt;a href="https://eips.ethereum.org/EIPS/eip-3009" rel="noopener noreferrer"&gt;EIP-3009&lt;/a&gt; &lt;code&gt;transferWithAuthorization&lt;/code&gt; permit. The merchant verifies the signature and submits the permit on-chain to actually move USDC.&lt;/p&gt;

&lt;p&gt;That last part — submitting on-chain — is the &lt;strong&gt;facilitator's&lt;/strong&gt; job. Most x402 services delegate it to a SaaS provider:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Facilitator&lt;/th&gt;
&lt;th&gt;Auth&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;KYC&lt;/th&gt;
&lt;th&gt;Bazaar discovery&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDP (Coinbase)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ed25519 JWT&lt;/td&gt;
&lt;td&gt;Free tier, then unbounded&lt;/td&gt;
&lt;td&gt;Required for billing&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PayAI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;x402.org&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Free, testnet-leaning&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-hosted&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;n/a — your own wallet&lt;/td&gt;
&lt;td&gt;Base gas (~$0.0005/settle)&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The facilitator role is genuinely simple: hold an EOA with ETH for gas, submit USDC &lt;code&gt;transferWithAuthorization&lt;/code&gt; calls. The whole thing is public on-chain. There is no proprietary algorithm. CDP just runs a wallet and an HTTP API around &lt;code&gt;viem&lt;/code&gt; (or some equivalent).&lt;/p&gt;

&lt;p&gt;So why does anyone pay for a facilitator? Because operating a hot wallet 24/7 with proper monitoring and key handling is annoying and most teams would rather expense it.&lt;/p&gt;

&lt;p&gt;That logic flips the moment the SaaS itself becomes the failure mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  The build: 350 lines of glue
&lt;/h2&gt;

&lt;p&gt;The good news: the &lt;code&gt;@x402/core&lt;/code&gt; and &lt;code&gt;@x402/evm&lt;/code&gt; SDKs already include a complete in-process facilitator implementation. It just normally lives behind an HTTP layer in CDP/PayAI's infrastructure. Nothing prevents us from running it ourselves.&lt;/p&gt;

&lt;p&gt;The whole architecture, top to bottom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 x402ResourceServer (SDK, untouched)
                            |
                            v
                 LocalFacilitatorClient (new, ~120 lines)
                  - Redis SETNX lock per operator address
                  - Prometheus metrics
                  - PayAI HTTP fallback on throw
                            |
                            v
                 x402Facilitator (SDK, in-process)
                 + registerExactEvmScheme(signer)
                            |
                            v
                 viem WalletClient + publicActions
                  - operator privkey from .env
                  - Base mainnet, fixed RPC
                  - holds ETH only, never USDC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The viem signer is six lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createWalletClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publicActions&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;privateKeyToAccount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem/accounts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viem/chains&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;privateKeyToAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;X402_OPERATOR_PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createWalletClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;account&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;http&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rpcUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;retryCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;retryDelay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publicActions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The facilitator wiring is four:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;x402Facilitator&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@x402/core/facilitator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;registerExactEvmScheme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@x402/evm/exact/facilitator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;facilitator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;x402Facilitator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nf"&gt;registerExactEvmScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;facilitator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;signer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eip155:8453&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is genuinely the entire payment-settlement layer. The SDK does the EIP-3009 signature verification, builds the calldata, submits via the signer, waits for the receipt. We add three things on top:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Redis SETNX lock&lt;/strong&gt; keyed by operator address (TTL 60s). With multiple containers (api + worker) running on the same operator wallet, two concurrent &lt;code&gt;eth_getTransactionCount&lt;/code&gt; calls would return the same nonce and the second tx would fail "nonce too low". The lock serializes settle calls cross-container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus metrics&lt;/strong&gt;: &lt;code&gt;x402_local_settle_total{result}&lt;/code&gt; counter, &lt;code&gt;x402_local_settle_duration_seconds&lt;/code&gt; histogram with &lt;code&gt;result&lt;/code&gt; label, &lt;code&gt;x402_operator_eth_balance&lt;/code&gt; gauge. Plus alerts at &amp;lt;0.005 ETH balance and &amp;gt;5% error rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PayAI HTTP fallback&lt;/strong&gt; wired transparently inside &lt;code&gt;LocalFacilitatorClient&lt;/code&gt;. If our local settle throws (RPC outage, signer drift, anything), the same call automatically retries against PayAI's free public facilitator. Single-RPC blips do not drop revenue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two architectural decisions worth explaining:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operator wallet ≠ receiver wallet.&lt;/strong&gt; Our receiver address (the one that accumulates USDC revenue) has no private key in the runtime environment. The operator address is a fresh hot wallet that holds only ETH for gas. If the operator key is compromised, the attacker steals unspent gas (~$10), not customer USDC. Compromise of the receiver requires compromising whatever cold custody we use for that address. Keep them separate. Always.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The SDK does not iterate fallback clients automatically.&lt;/strong&gt; I assumed it did — the existing code I inherited had a comment claiming "if first client throws, tries next." Reading the actual &lt;code&gt;@x402/core/server&lt;/code&gt; source disproved this. &lt;code&gt;x402ResourceServer.initialize()&lt;/code&gt; populates a &lt;code&gt;(version, network, scheme) → client&lt;/code&gt; lookup map, and the FIRST registered client wins. So the fallback semantics had to live inside our &lt;code&gt;LocalFacilitatorClient&lt;/code&gt; itself: try local, catch, delegate to a PayAI HTTP client.&lt;/p&gt;

&lt;p&gt;Full code in &lt;a href="https://github.com/whiteknightonhorse/APIbase/blob/main/src/payments/local-facilitator.ts" rel="noopener noreferrer"&gt;&lt;code&gt;src/payments/local-facilitator.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three gotchas that cost us seven minutes of 502s
&lt;/h2&gt;

&lt;p&gt;The implementation worked on first try. The deployment is what bit me. Three docker-compose footguns, in order:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;docker compose restart&lt;/code&gt; does not re-read &lt;code&gt;env_file&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I edited &lt;code&gt;.env&lt;/code&gt; to set &lt;code&gt;X402_FACILITATOR_MODE=local&lt;/code&gt;, then ran &lt;code&gt;docker compose restart api worker&lt;/code&gt;. The container came up healthy. Logs showed &lt;code&gt;mode: "remote"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I assumed the env file load was broken. I read it three times. It was correct. Then I ran &lt;code&gt;docker exec apibase-api-1 env | grep X402_FACILITATOR_MODE&lt;/code&gt; — empty.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;restart&lt;/code&gt; does not reload &lt;code&gt;env_file&lt;/code&gt;. It just SIGHUPs the existing container, keeping the env vars from the original &lt;code&gt;up&lt;/code&gt;. To pick up new values you need &lt;code&gt;docker compose up -d --force-recreate --no-deps api worker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Documented nowhere prominent. Cost me ~3 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;code&gt;--force-recreate&lt;/code&gt; does not pull new images
&lt;/h3&gt;

&lt;p&gt;The push to &lt;code&gt;main&lt;/code&gt; had triggered a CI build that published a new image to &lt;code&gt;ghcr.io&lt;/code&gt;. The image included our new &lt;code&gt;LocalFacilitatorClient&lt;/code&gt; code. I assumed &lt;code&gt;--force-recreate&lt;/code&gt; would pull it.&lt;/p&gt;

&lt;p&gt;It did not. It happily reused the locally cached pre-push image. The container started with &lt;code&gt;mode=local&lt;/code&gt; (from the new env), but the actual code was old (no &lt;code&gt;LocalFacilitatorClient&lt;/code&gt;). Logs showed CDP being registered as primary.&lt;/p&gt;

&lt;p&gt;Fix: &lt;code&gt;docker compose pull api worker&lt;/code&gt; before recreate. Or &lt;code&gt;--pull always&lt;/code&gt;. Cost: another ~2 minutes of confusion.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. After &lt;code&gt;--force-recreate&lt;/code&gt;, the inner nginx caches the old IP
&lt;/h3&gt;

&lt;p&gt;This one was the worst. After recreating api, the new container got a new IP on the internal Docker network. Our edge nginx (&lt;code&gt;apibase-nginx-1&lt;/code&gt;) had the old IP cached from its config-load time. Every request to &lt;code&gt;apibase.pro/api/v1/tools&lt;/code&gt; returned 502 because nginx kept connecting to a dead IP.&lt;/p&gt;

&lt;p&gt;Symptoms: outer health checks pass (200 from static pages), API endpoints all 502, container looks healthy from &lt;code&gt;docker ps&lt;/code&gt;, &lt;code&gt;docker exec apibase-nginx-1 wget http://api:3000/health/ready&lt;/code&gt; works. Took me a moment to realize nginx was holding &lt;code&gt;172.18.0.5&lt;/code&gt; from the previous container while the new one was at &lt;code&gt;172.18.0.7&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Fix: &lt;code&gt;docker exec apibase-nginx-1 nginx -s reload&lt;/code&gt; after every recreate. Cost: ~2 minutes of users seeing 502s before I diagnosed it.&lt;/p&gt;

&lt;p&gt;I documented all three in our runbook so the next person (or my future self) does not repeat them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Council Review and auto-fix
&lt;/h2&gt;

&lt;p&gt;Before pushing, I ran our internal &lt;code&gt;/councilreview&lt;/code&gt; skill — eight specialized reviewers (Security, Performance, Reliability, API Designer, Domain Expert, Crypto Specialist, DevOps, Observability) each look at the diff independently. They surfaced five MEDIUM findings I had not thought of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crypto Specialist&lt;/strong&gt;: viem &lt;code&gt;http()&lt;/code&gt; transport had no retry config. Added &lt;code&gt;{ retryCount: 2, retryDelay: 200 }&lt;/code&gt; so transient public-RPC blips are absorbed before triggering PayAI fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability Engineer&lt;/strong&gt;: my Redis lock had a final &lt;code&gt;redis.get(key) !== token&lt;/code&gt; check after the SETNX retry loop, which has a tiny race window where the SET succeeds and the TTL expires before the GET. Replaced with a simple in-loop boolean.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Engineer&lt;/strong&gt;: histogram buckets started at 500ms, masking sub-second optimization wins. Tightened to &lt;code&gt;[0.1, 0.25, 0.5, 1, 2, 5, 10, 30]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability Engineer (×2)&lt;/strong&gt;: settle duration histogram had no &lt;code&gt;result&lt;/code&gt; label, so I could not distinguish success-latency from fallback-latency. Also added a brand-new &lt;code&gt;x402_operator_lock_wait_seconds&lt;/code&gt; histogram so I would see lock contention rising before requests started timing out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The skill auto-applied all five fixes (with a TS+ESLint+Jest validation gate that would revert everything if any of the three regressed). Took 90 seconds. Six new useful changes, zero work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Day-0 numbers (with honest framing)
&lt;/h2&gt;

&lt;p&gt;I am writing this an hour after &lt;code&gt;mode=local&lt;/code&gt; went live. I genuinely do not know how it will perform under a peak hour, an RPC outage, or a Base fee-market spike yet. What I do know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~15 settles&lt;/strong&gt; processed through &lt;code&gt;LocalFacilitatorClient&lt;/code&gt; so far&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0 errors&lt;/strong&gt;, 0 fallbacks (Day-0 cherry — does not generalize)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~0.001 ETH&lt;/strong&gt; spent on gas (~$3)&lt;/li&gt;
&lt;li&gt;Operator wallet balance hit the dashboard, low-balance alert wired and tested&lt;/li&gt;
&lt;li&gt;Production &lt;code&gt;/health/ready&lt;/code&gt; returned 200 throughout (after the nginx reload fix)&lt;/li&gt;
&lt;li&gt;Base finality on every settle, all transactions visible on basescan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will follow up in two weeks with a real soak report: 7-day error rate, fallback rate, p99 lock-wait latency, total ETH spent, total USDC settled. The numbers I quote there will be production-true, not hopeful.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;Three things, ordered from operational to philosophical:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read the SDK source, do not trust the inline docstrings.&lt;/strong&gt; The "iterates fallback clients" comment was in our code, not in the SDK. The actual SDK behavior is single-client-wins. If I had not read &lt;code&gt;@x402/core/server/index.js&lt;/code&gt; directly, our PayAI fallback would have been dead code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hot wallet operations are simpler than they sound.&lt;/strong&gt; Generate a key, fund with ETH, hold it in &lt;code&gt;.env&lt;/code&gt; (&lt;code&gt;chmod 600&lt;/code&gt;, gitignored), monitor balance via Prometheus alert. The operational complexity of running our own facilitator is genuinely lower than the operational complexity of dealing with KYC, billing dashboards, and SaaS quota limits. We are saving roughly &lt;strong&gt;$50/month&lt;/strong&gt; at our current volume — not a lot, but the dependency removal is the actual prize.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vendor dependencies on critical revenue paths are technical debt.&lt;/strong&gt; A free tier with a paid escalator is a free tier until the day it isn't. CDP did not do anything wrong here — they sent a clear notification, gave a clear path forward, and have legitimate KYC requirements. But "depend on a vendor for the part of our system that converts agent calls to revenue" was a fragile choice we had not noticed making. Self-hosting is one less hop, one less account to manage, one less single point of failure.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;If you run an x402-priced API and want to drop your facilitator dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate an operator wallet&lt;/span&gt;
npx tsx &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"
const { generatePrivateKey, privateKeyToAccount } = require('viem/accounts');
const pk = generatePrivateKey();
console.log('address:', privateKeyToAccount(pk).address);
console.log('privkey:', pk);
"&lt;/span&gt;

&lt;span class="c"&gt;# Fund the address with ~$10 of ETH on Base via any exchange withdrawal&lt;/span&gt;

&lt;span class="c"&gt;# Add to .env (chmod 600, gitignored, never log)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"X402_OPERATOR_PRIVATE_KEY=&amp;lt;the privkey&amp;gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .env

&lt;span class="c"&gt;# Replace your HTTP facilitator with the in-process one&lt;/span&gt;
&lt;span class="c"&gt;# (full reference impl: github.com/whiteknightonhorse/APIbase/blob/main/src/payments/local-facilitator.ts)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole pattern. The full architecture write-up — operational design, two-wallet model, observability stack, key rotation procedure — lives in &lt;a href="https://github.com/whiteknightonhorse/APIbase/blob/main/docs/x402-facilitator.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/x402-facilitator.md&lt;/code&gt;&lt;/a&gt;. MIT-licensed, fork freely.&lt;/p&gt;

&lt;p&gt;If you ship something on this pattern, open an issue on the repo. I would like to know it works for someone other than us.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;APIbase is a unified MCP gateway with 576 tools and 177 providers, paid via x402 USDC on Base or MPP USDC on Tempo. Production endpoint: &lt;code&gt;https://apibase.pro/mcp&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>web3</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Flight-Search MCP App in 10 Minutes with Sunpeak + APIbase</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Fri, 10 Apr 2026 07:41:17 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/build-a-flight-search-mcp-app-in-10-minutes-with-sunpeak-apibase-ml5</link>
      <guid>https://dev.to/whiteknightonhorse/build-a-flight-search-mcp-app-in-10-minutes-with-sunpeak-apibase-ml5</guid>
      <description>&lt;h2&gt;
  
  
  What if your ChatGPT plugin could search real flight prices?
&lt;/h2&gt;

&lt;p&gt;Not a mock. Not a demo. Actual Amadeus GDS data — airlines, prices, stops, departure times — inside an interactive app running in ChatGPT or Claude.&lt;/p&gt;

&lt;p&gt;That's what we're building in this tutorial. The stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://sunpeak.ai" rel="noopener noreferrer"&gt;Sunpeak&lt;/a&gt;&lt;/strong&gt; — open-source framework for building MCP Apps inside ChatGPT and Claude&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://apibase.pro" rel="noopener noreferrer"&gt;APIbase&lt;/a&gt;&lt;/strong&gt; — unified MCP gateway with 500 real-world API tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ten minutes. Working app. Let's go.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Sunpeak?
&lt;/h2&gt;

&lt;p&gt;Sunpeak is an npm framework that lets you build interactive applications — with forms, buttons, charts, and data displays — that run &lt;em&gt;inside&lt;/em&gt; AI assistants. Think of it as React for ChatGPT.&lt;/p&gt;

&lt;p&gt;The apps are built on MCP (Model Context Protocol), so they work in both ChatGPT and Claude without separate codebases. You develop locally with a hot-reloading inspector, then deploy once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-g&lt;/span&gt; sunpeak
sunpeak create my-flight-app
&lt;span class="nb"&gt;cd &lt;/span&gt;my-flight-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What is APIbase?
&lt;/h2&gt;

&lt;p&gt;APIbase is a single MCP endpoint that gives your app access to 500 API tools — flights (Amadeus), weather (NOAA), stock quotes (Finnhub), government data (Census, CDC, Congress), museums (Met, Rijksmuseum), and 150+ more providers.&lt;/p&gt;

&lt;p&gt;One connection. No individual API keys to manage. Pay per call with x402 USDC micropayments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MCP endpoint: https://apibase.pro/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Wire APIbase into your Sunpeak app
&lt;/h2&gt;

&lt;p&gt;In your Sunpeak app config, add APIbase as an MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sunpeak&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;mcpServers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apibase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://apibase.pro/mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;streamable-http&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Your app now has access to all 500 tools. No API key needed for initial connection — auto-registration handles it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Discover available tools
&lt;/h2&gt;

&lt;p&gt;Before you hardcode tool names, use the &lt;code&gt;discover_tools&lt;/code&gt; prompt to find what's available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "jsonrpc": "2.0",
    "method": "prompts/get",
    "params": {
      "name": "discover_tools",
      "arguments": {"category": "travel"}
    },
    "id": 1
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns only the travel-related tools instead of dumping all 500 into context. You'll see tools like:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amadeus.flights.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Search flights by origin/destination/date&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amadeus.flights.price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirm pricing for a specific flight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amadeus.airports.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find airports by keyword&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;weatherapi.forecast&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Weather forecast for any city&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;finance.exchange.ecb_rates&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Currency exchange rates (ECB)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Build the flight search component
&lt;/h2&gt;

&lt;p&gt;Here's a Sunpeak component that searches flights and displays results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useToolCall&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sunpeak/hooks&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;FlightSearch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchFlights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useToolCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amadeus.flights.search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;searchFlights&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// "JFK"&lt;/span&gt;
      &lt;span class="nx"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// "LHR"&lt;/span&gt;
      &lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// "2026-05-15"&lt;/span&gt;
      &lt;span class="na"&gt;adults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// result.flights contains real Amadeus GDS data:&lt;/span&gt;
    &lt;span class="c1"&gt;// airline, price, currency, departure, arrival, stops&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Sunpeak renders this as an interactive form inside ChatGPT/Claude&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SearchForm&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSearch&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;origin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;From (e.g. JFK)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Input&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;destination&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;To (e.g. LHR)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DatePicker&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;date&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SubmitButton&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Search&lt;/span&gt; &lt;span class="nx"&gt;Flights&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SubmitButton&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SearchForm&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user interacts with your app in ChatGPT, they see a form. They fill in JFK → LHR → May 15. Your app calls &lt;code&gt;amadeus.flights.search&lt;/code&gt; through the APIbase MCP endpoint. Real flight data comes back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Add weather and currency conversion
&lt;/h2&gt;

&lt;p&gt;One endpoint, multiple tools. Let's add weather for the destination and currency conversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;enrichFlightResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Flight&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rates&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;weatherapi.forecast&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destination_city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;days&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;}),&lt;/span&gt;
    &lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;finance.exchange.ecb_rates&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD,EUR,GBP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;destination_weather&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;weather&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forecast&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;price_in_usd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;price_in_eur&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three API calls. Three different providers (Amadeus, WeatherAPI, ECB). One MCP connection. Total cost: ~$0.04.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Test locally
&lt;/h2&gt;

&lt;p&gt;Sunpeak's inspector lets you test your app in a simulated ChatGPT/Claude environment without needing a paid account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sunpeak dev
&lt;span class="c"&gt;# Opens inspector at http://localhost:3000&lt;/span&gt;
&lt;span class="c"&gt;# Simulates ChatGPT and Claude runtimes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The inspector renders your forms, handles tool calls, and shows you exactly what the user would see. Hot module reloading means changes appear instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Deploy
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sunpeak build
sunpeak deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app is now installable in ChatGPT and Claude. Users can search real flight prices, see destination weather, and compare prices in multiple currencies — all inside their AI assistant.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you just built
&lt;/h2&gt;

&lt;p&gt;An interactive MCP App that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Searches real flight prices&lt;/strong&gt; via Amadeus GDS (not scraped, not cached — live airline data)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checks destination weather&lt;/strong&gt; via WeatherAPI (3-day forecast)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Converts currencies&lt;/strong&gt; via ECB exchange rates (160+ currencies)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runs inside ChatGPT and Claude&lt;/strong&gt; via Sunpeak MCP framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pays per call&lt;/strong&gt; via x402 USDC micropayments ($0.04 total for all three queries)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No API keys to manage. No separate provider accounts. No subscription fees.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bigger picture
&lt;/h2&gt;

&lt;p&gt;MCP Apps are a new category. They're not chatbots (no free-form text generation). They're not plugins (no OAuth dance). They're interactive applications that happen to live inside AI assistants.&lt;/p&gt;

&lt;p&gt;The missing piece has always been data. Sunpeak gives you the UI framework. APIbase gives you 500 real-world data sources through one connection. Together, they let you build apps that would have taken weeks of API integration in days.&lt;/p&gt;

&lt;p&gt;Some ideas for what to build next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real estate explorer&lt;/strong&gt; — search properties (US Real Estate API), check walkability (Walk Score), get neighborhood demographics (Census)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Research assistant&lt;/strong&gt; — search papers (DBLP, arXiv, OpenAlex), find authors, check citations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Travel planner&lt;/strong&gt; — flights + hotels + weather + currency + local events (Ticketmaster) + restaurant reservations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio tracker&lt;/strong&gt; — stock quotes (Finnhub), crypto prices (CoinGecko), exchange rates, company news&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these are 3-5 tool calls through one MCP endpoint.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;1. Install Sunpeak:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-g&lt;/span&gt; sunpeak
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Browse APIbase tools:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://apibase.pro/api/v1/tools | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Full framework integration guide:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://apibase.pro/frameworks#sunpeak" rel="noopener noreferrer"&gt;apibase.pro/frameworks#sunpeak&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. APIbase MCP endpoint:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://apibase.pro/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;&lt;a href="https://apibase.pro" rel="noopener noreferrer"&gt;APIbase&lt;/a&gt; is open source — &lt;a href="https://github.com/whiteknightonhorse/APIbase" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. &lt;a href="https://sunpeak.ai" rel="noopener noreferrer"&gt;Sunpeak&lt;/a&gt; is open source — MIT license.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The 3 MCP Servers Every AI Agent Needs in Production</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Wed, 08 Apr 2026 12:19:29 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/the-3-mcp-servers-every-ai-agent-needs-in-production-1107</link>
      <guid>https://dev.to/whiteknightonhorse/the-3-mcp-servers-every-ai-agent-needs-in-production-1107</guid>
      <description>&lt;h2&gt;
  
  
  Your AI agent is probably missing two-thirds of what it needs
&lt;/h2&gt;

&lt;p&gt;Most agents ship with one capability: text generation. Some get tool access — usually a single API or a browser. But in production, agents need three fundamentally different types of tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Documentation context&lt;/strong&gt; — reading library docs, API references, changelogs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser interaction&lt;/strong&gt; — navigating pages, filling forms, taking screenshots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-world data&lt;/strong&gt; — flights, weather, stock prices, government records, package metadata&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No single MCP server covers all three. But three servers together do. Here's how I wire Context7, Playwright, and APIbase into one agent — and why the combination matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why three servers, not one?
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol lets an agent connect to multiple tool servers simultaneously. Each server exposes its tools through the same protocol, so the agent sees one flat catalog regardless of how many servers are behind it.&lt;/p&gt;

&lt;p&gt;But MCP servers specialize. A documentation server optimizes for RAG over markdown. A browser server manages headless Chrome sessions. An API gateway handles auth, caching, rate limits, and payment for upstream providers.&lt;/p&gt;

&lt;p&gt;Trying to do all three in one server means doing all three badly. The separation is intentional.&lt;/p&gt;

&lt;p&gt;Here's the architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐
│   AI Agent   │
│  (your code) │
└──────┬───────┘
       │ MCP (Streamable HTTP)
       ├──────────────────────────────────┐
       │                                  │
┌──────▼───────┐  ┌──────────────┐  ┌─────▼──────────┐
│  Context7    │  │  Playwright  │  │  APIbase       │
│  (docs/code) │  │  (browser)   │  │  (487 APIs)    │
└──────────────┘  └──────────────┘  └────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me walk through each one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server 1: Context7 — Up-to-date documentation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Fetches live documentation for libraries and frameworks. Instead of relying on the LLM's training data (which is always months behind), Context7 pulls the current docs at query time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why agents need it:&lt;/strong&gt; LLMs hallucinate API signatures. A lot. If your agent is generating code that calls &lt;code&gt;pandas.DataFrame.to_parquet()&lt;/code&gt;, it needs the &lt;em&gt;current&lt;/em&gt; parameter list — not what GPT memorized from 2024 docs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;resolve&lt;/code&gt; — finds the right library by name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get-library-docs&lt;/code&gt; — retrieves documentation for a specific topic
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example: Get current Next.js App Router docs
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resolve&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;libraryName&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;next.js&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;# Returns: library_id = "/vercel/next.js"
&lt;/span&gt;
&lt;span class="n"&gt;docs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;get-library-docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;libraryId&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/vercel/next.js&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;topic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app router middleware&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;# Returns: current markdown docs, not stale training data
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Free, open source, no API key needed.&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;"context7"&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;"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.context7.com/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;&lt;strong&gt;Limitation:&lt;/strong&gt; Only covers libraries indexed in their registry. If you're using a niche library, you'll get nothing. But for popular frameworks (React, Next.js, FastAPI, LangChain), it's solid.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server 2: Playwright MCP — Browser automation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Gives the agent a headless browser. Navigate pages, click buttons, fill forms, take screenshots, extract content from rendered JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why agents need it:&lt;/strong&gt; Not everything has an API. Job application forms, internal dashboards, CMS interfaces, legacy web apps — your agent needs a browser for these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key tools:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;browser_navigate&lt;/code&gt; — go to a URL&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_click&lt;/code&gt; — click an element&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_type&lt;/code&gt; — fill input fields&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_screenshot&lt;/code&gt; — capture the current page&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;browser_snapshot&lt;/code&gt; — get accessibility tree (structured page content)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example: Check a competitor's pricing page
&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;playwright&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;browser_navigate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://competitor.com/pricing&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;playwright&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;browser_snapshot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="c1"&gt;# Returns: structured accessibility tree of the pricing page
# Agent can now parse tiers, prices, feature lists
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Setup:&lt;/strong&gt; Runs locally via npx (no remote server needed for dev):&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;"playwright"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&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="s2"&gt;"@anthropic-ai/mcp-server-playwright"&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;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;&lt;strong&gt;Limitation:&lt;/strong&gt; Headless browser is slow (2-5 seconds per action). Rate-limited by nature. Not suitable for bulk data retrieval — that's what APIs are for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Server 3: APIbase — 487 real-world APIs through one endpoint
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Unified MCP gateway to 487 tools from 150 upstream providers. Travel, finance, weather, government data, science, e-commerce, jobs, entertainment, dev tools — all through one connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why agents need it:&lt;/strong&gt; An agent that can only browse the web and read docs is still missing structured data. It can't check flight prices, look up stock quotes, query US Census data, or search npm packages without an API. And wiring 150 separate APIs means managing 150 auth flows, rate limits, and response formats.&lt;/p&gt;

&lt;p&gt;APIbase handles that. One MCP endpoint, one auth token (or no token — auto-registration), pay-per-call pricing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key tools (487 total, here are 10 across categories):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it returns&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amadeus.flights.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Real-time flight prices, routes, airlines&lt;/td&gt;
&lt;td&gt;$0.035&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;coingecko.crypto.price&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Live crypto prices for any token&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;serper.search.web&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Google search results as JSON&lt;/td&gt;
&lt;td&gt;$0.002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;census.gov.population&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;US Census population data by state/county&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm.registry.package_info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;npm package metadata, versions, downloads&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hf.hub.models&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HuggingFace model search (1M+ models)&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;noaa.weather.forecast&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;US weather forecasts by coordinates&lt;/td&gt;
&lt;td&gt;$0.002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;congress.gov.bills&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;US Congressional bills and legislation&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;gbif.species.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Global biodiversity occurrence data&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;osv.security.query&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vulnerability database (npm, PyPI, Go, etc.)&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example: Search for flights from NYC to London&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "amadeus.flights.search",
      "arguments": {
        "origin": "JFK",
        "destination": "LHR",
        "date": "2026-05-15",
        "adults": 1
      }
    },
    "id": 1
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response (trimmed):&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;"result"&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;"content"&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;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;flights&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:[{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;airline&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;BA&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;price&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;412.00&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;currency&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;USD&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;departure&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;2026-05-15T19:00:00&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;arrival&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;2026-05-16T07:15:00&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;stops&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:0}]}"&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;&lt;strong&gt;Setup:&lt;/strong&gt;&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;"apibase"&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;"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://apibase.pro/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;No API key required for initial connection — auto-registration gives you credentials on first request. Payment is x402 USDC micropayments (from $0.001 to $1.00 per call depending on the tool).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitation:&lt;/strong&gt; Paid per call. Not suitable for bulk scraping or high-frequency polling. Use the browser server for web scraping, APIbase for structured data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wiring all three together
&lt;/h2&gt;

&lt;p&gt;Here's a complete Python example using the OpenAI Agents SDK with all three servers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPServerStreamableHTTP&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Connect to all 3 MCP servers
&lt;/span&gt;    &lt;span class="n"&gt;context7&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPServerStreamableHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context7&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://mcp.context7.com/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;playwright&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPServerStreamableHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;playwright&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3001/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# local Playwright server
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;apibase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPServerStreamableHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apibase&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://apibase.pro/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;context7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;apibase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Gather tools from all servers
&lt;/span&gt;        &lt;span class="n"&gt;all_tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;playwright&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;apibase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research-agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are a research agent with 3 capabilities:
            1. Context7: look up current library documentation
            2. Playwright: browse websites and interact with pages
            3. APIbase: query 487 real-world APIs (flights, finance,
               weather, government data, science, jobs, etc.)

            Use the right tool for each task. Prefer APIs over
            browser automation when structured data is available.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;all_tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find the cheapest JFK→LHR flight for May 15, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;then check the current GBP/USD exchange rate, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;and look up London weather for that date.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;final_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent sees one combined tool catalog. It picks &lt;code&gt;amadeus.flights.search&lt;/code&gt; for flights, &lt;code&gt;finance.exchange.ecb_rates&lt;/code&gt; for the exchange rate, and &lt;code&gt;weatherapi.forecast&lt;/code&gt; for London weather — all from APIbase. If it needed to check a website that doesn't have an API, it'd use Playwright. If it needed current docs for a library it's using, it'd call Context7.&lt;/p&gt;

&lt;p&gt;Three servers. One agent. Full coverage.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to use which server
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Best Server&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Get current React docs&lt;/td&gt;
&lt;td&gt;Context7&lt;/td&gt;
&lt;td&gt;Up-to-date library docs, not stale training data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fill out a web form&lt;/td&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;Needs browser interaction, no API available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search flight prices&lt;/td&gt;
&lt;td&gt;APIbase&lt;/td&gt;
&lt;td&gt;Structured API data, faster and cheaper than scraping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read a blog post&lt;/td&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;Rendered HTML, may need JavaScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query US Census data&lt;/td&gt;
&lt;td&gt;APIbase&lt;/td&gt;
&lt;td&gt;Government API, returns structured JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check npm package versions&lt;/td&gt;
&lt;td&gt;APIbase&lt;/td&gt;
&lt;td&gt;Registry API, no browser needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Navigate a dashboard&lt;/td&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;Interactive UI, login required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Get stock quotes&lt;/td&gt;
&lt;td&gt;APIbase&lt;/td&gt;
&lt;td&gt;Real-time financial data via API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Look up LangChain docs&lt;/td&gt;
&lt;td&gt;Context7&lt;/td&gt;
&lt;td&gt;Framework docs that change frequently&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Take a webpage screenshot&lt;/td&gt;
&lt;td&gt;Playwright&lt;/td&gt;
&lt;td&gt;Visual capture, needs rendering engine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule of thumb: &lt;strong&gt;if structured data exists via an API, use APIbase. If you need a browser, use Playwright. If you need current docs, use Context7.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned running all three in production
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Token efficiency matters.&lt;/strong&gt; APIbase exposes 487 tools. Loading all of them into context is wasteful. Instead, I use the &lt;code&gt;discover_tools&lt;/code&gt; prompt with a category filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "jsonrpc": "2.0",
    "method": "prompts/get",
    "params": {
      "name": "discover_tools",
      "arguments": {"category": "finance"}
    },
    "id": 1
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns only the ~40 finance tools instead of all 487. The agent gets what it needs without burning 10K tokens on tool definitions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser is the fallback, not the default.&lt;/strong&gt; Agents instinctively reach for the browser because it's the most general tool. But browser actions are 10-50x slower than API calls and cost more in tokens (accessibility trees are verbose). Train your agent to check APIbase first, browser second.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache TTLs vary wildly.&lt;/strong&gt; Crypto prices cache for 5 seconds. Walk Score data caches for 7 days. Census data caches for 24 hours. This is handled per-tool on the server side — your agent doesn't need to think about it. But it matters for cost: repeated calls to cached endpoints are cheaper.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;1. Connect to all three in Claude Desktop:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;~/.config/claude/claude_desktop_config.json&lt;/code&gt;:&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;"context7"&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;"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.context7.com/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="nl"&gt;"apibase"&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;"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://apibase.pro/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;(Playwright requires a local process — see the &lt;a href="https://github.com/anthropics/mcp-server-playwright" rel="noopener noreferrer"&gt;Playwright MCP docs&lt;/a&gt; for setup.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Ask your agent:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Search for direct flights from SFO to Tokyo for next month, check the current JPY exchange rate, and find the weather forecast for Tokyo on the arrival date."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent will use &lt;code&gt;amadeus.flights.search&lt;/code&gt;, &lt;code&gt;finance.exchange.ecb_rates&lt;/code&gt;, and &lt;code&gt;weatherapi.forecast&lt;/code&gt; — three API calls, one agent, real data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Browse the full tool catalog:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://apibase.pro/api/v1/tools | python3 &lt;span class="nt"&gt;-m&lt;/span&gt; json.tool | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;487 tools across 22 categories. Travel, finance, weather, science, government, jobs, entertainment, dev tools, and more.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;APIbase is open source — &lt;a href="https://github.com/whiteknightonhorse/APIbase" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Integration guides for OpenAI SDK, LangChain, Google ADK, and more at &lt;a href="https://apibase.pro/frameworks" rel="noopener noreferrer"&gt;apibase.pro/frameworks&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How I Gave an AI Agent Access to 20 Job APIs Through One Endpoint</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Tue, 31 Mar 2026 14:27:40 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/how-i-gave-an-ai-agent-access-to-20-job-apis-through-one-endpoint-20kf</link>
      <guid>https://dev.to/whiteknightonhorse/how-i-gave-an-ai-agent-access-to-20-job-apis-through-one-endpoint-20kf</guid>
      <description>&lt;h2&gt;
  
  
  The Problem: Job Data is Scattered Everywhere
&lt;/h2&gt;

&lt;p&gt;If you've ever tried to build anything that touches job market data, you know the pain. Every job board has its own API, its own auth, its own rate limits, its own response format.&lt;/p&gt;

&lt;p&gt;Want global coverage? You need Adzuna for 16 countries, Reed for UK, Arbeitnow for EU, Remotive for remote roles, TheirStack for tech stack analysis, Jooble for aggregated results, and probably five more I'm forgetting.&lt;/p&gt;

&lt;p&gt;That's 7 API keys, 7 auth schemes (Basic Auth, Bearer tokens, keys-in-URL-path, no auth at all), 7 different response formats, and 7 sets of rate limit rules. For a single query like "find me Python developer jobs in Europe, preferably remote."&lt;/p&gt;

&lt;p&gt;I spent the last week wiring all of these into a single MCP endpoint. Here's exactly how it works and how you can use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What MCP Changes About Multi-API Orchestration
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol (MCP) is the standard that lets AI agents discover and call tools dynamically. Instead of hardcoding API calls, your agent connects to an MCP server and gets a catalog of available tools — with typed schemas, descriptions, and pricing.&lt;/p&gt;

&lt;p&gt;The key insight: &lt;strong&gt;the agent decides which tools to call based on the user's question.&lt;/strong&gt; You don't write if/else logic for "if the user asks about UK jobs, call Reed; if they ask about remote, call Remotive." The LLM reads the tool descriptions and routes naturally.&lt;/p&gt;

&lt;p&gt;Here's what 20 job-related tools look like through one MCP connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Connect and discover job tools&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "prompts/get",
    "params": {
      "name": "discover_tools",
      "arguments": { "category": "jobs" }
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response lists every job tool with its parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;th&gt;Coverage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adzuna.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Job search with salary data&lt;/td&gt;
&lt;td&gt;16 countries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adzuna.salary&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Salary histograms by role&lt;/td&gt;
&lt;td&gt;16 countries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adzuna.categories&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Job category taxonomy&lt;/td&gt;
&lt;td&gt;Per-country&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;theirstack.jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tech stack-filtered job search&lt;/td&gt;
&lt;td&gt;Global, 181M+ postings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;theirstack.companies&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find companies by technology&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jooble.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Aggregated search, 70+ countries&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reed.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UK jobs with salary (GBP)&lt;/td&gt;
&lt;td&gt;UK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reed.details&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full job details by ID&lt;/td&gt;
&lt;td&gt;UK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;arbeitnow.jobs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EU job listings&lt;/td&gt;
&lt;td&gt;DE, AT, CH, NL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;remotive.search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Remote-only curated listings&lt;/td&gt;
&lt;td&gt;Global remote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jobs.salary_data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;BLS salary statistics&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jobs.occupation_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;O*NET occupation database&lt;/td&gt;
&lt;td&gt;US&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jobs.esco_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;EU skills/occupation taxonomy&lt;/td&gt;
&lt;td&gt;EU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;jobs.job_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CareerJet search&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That's one connection, one auth token, one response format. The agent picks which tool fits the question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Agent: From Question to Multi-Source Results
&lt;/h2&gt;

&lt;p&gt;Let me walk through what happens when a user asks: &lt;em&gt;"Find me senior Python developer jobs in Berlin, preferably remote, and compare salaries with London."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A well-prompted agent would break this into 3-4 tool calls:&lt;/p&gt;

&lt;h3&gt;
  
  
  Call 1: TheirStack for tech-stack-specific results
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/theirstack.jobs/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-PAYMENT: ..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "keywords": "senior python developer",
    "country": "DE",
    "remote": true,
    "technologies": "python, django, fastapi",
    "limit": 10
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Response:&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;"jobs"&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;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Senior Python Developer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Delivery Hero"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Berlin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"country"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"remote"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"salary_min_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"salary_max_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;95000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"posted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-28"&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://..."&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="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&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;h3&gt;
  
  
  Call 2: Reed for UK salary comparison
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/reed.search/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-PAYMENT: ..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "keywords": "senior python developer",
    "location": "London",
    "salary_min": 60000,
    "permanent": true,
    "limit": 10
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;"jobs"&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;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;56671234&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Senior Python Developer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Revolut"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"London"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"salary_min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"salary_max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;110000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GBP"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"applications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;47&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://www.reed.co.uk/jobs/..."&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="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&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;h3&gt;
  
  
  Call 3: Remotive for remote-only options
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/remotive.search/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-PAYMENT: ..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "search": "python senior",
    "category": "software-dev",
    "limit": 10
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;"jobs"&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;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;982341&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Senior Python Backend Engineer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"company"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GitLab"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Software Development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"salary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$130,000 - $170,000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"location_requirement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Americas, EMEA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tags"&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="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"django"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgresql"&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://remotive.com/remote-jobs/..."&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="nl"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2847&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;h3&gt;
  
  
  Call 4: Adzuna salary histogram
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/tools/adzuna.salary/call &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer ak_live_..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-PAYMENT: ..."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "what": "python developer",
    "where": "london",
    "country": "gb"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent now has: Berlin jobs with tech stack filters, London jobs with GBP salaries, global remote positions with USD salary ranges, and a salary distribution histogram. Total cost: 4 API calls × $0.001-0.002 each = &lt;strong&gt;less than $0.01&lt;/strong&gt; for a comprehensive multi-market job analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Part Nobody Talks About: Why 7 Providers, Not 1
&lt;/h2&gt;

&lt;p&gt;Here's what I learned integrating all these job APIs in one day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No single provider covers everything:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Need&lt;/th&gt;
&lt;th&gt;Best Provider&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Show me Python jobs"&lt;/td&gt;
&lt;td&gt;TheirStack&lt;/td&gt;
&lt;td&gt;Only one with tech stack filter (&lt;code&gt;technologies_or&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"UK jobs with salary"&lt;/td&gt;
&lt;td&gt;Reed&lt;/td&gt;
&lt;td&gt;Structured min/max GBP salary, not free text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Remote jobs only"&lt;/td&gt;
&lt;td&gt;Remotive&lt;/td&gt;
&lt;td&gt;Curated remote-only board, salary strings included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Jobs in Germany"&lt;/td&gt;
&lt;td&gt;Arbeitnow&lt;/td&gt;
&lt;td&gt;EU-native, German market coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Salary comparison"&lt;/td&gt;
&lt;td&gt;Adzuna&lt;/td&gt;
&lt;td&gt;Statistical salary histograms, not just listings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Global search"&lt;/td&gt;
&lt;td&gt;Jooble&lt;/td&gt;
&lt;td&gt;70+ countries, widest aggregation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"How competitive is this role?"&lt;/td&gt;
&lt;td&gt;Reed&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;applications&lt;/code&gt; count per listing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The auth diversity is wild.&lt;/strong&gt; In one afternoon I dealt with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bearer JWT tokens (TheirStack)&lt;/li&gt;
&lt;li&gt;API key in URL path — literally &lt;code&gt;/api/{key}&lt;/code&gt; (Jooble)&lt;/li&gt;
&lt;li&gt;HTTP Basic Auth with key as username, empty password (Reed)&lt;/li&gt;
&lt;li&gt;No auth at all (Arbeitnow, Remotive)&lt;/li&gt;
&lt;li&gt;App ID + App Key as query params (Adzuna)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's 5 different auth schemes for one category. An MCP gateway normalizes this — your agent sends one &lt;code&gt;Authorization: Bearer&lt;/code&gt; header and the gateway handles the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Response Format Normalization
&lt;/h2&gt;

&lt;p&gt;This is the unsexy-but-critical part. Each API returns salary differently:&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="err"&gt;TheirStack:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"salary_min_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;75000&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"salary_max_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;95000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Reed:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nl"&gt;"minimumSalary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;80000.0&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maximumSalary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;110000.0&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GBP"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Remotive:&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nl"&gt;"salary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$130,000 - $170,000"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Adzuna:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"salary_min"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45000&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"salary_max"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;65000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;field,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;inferred&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;country)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Arbeitnow:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;no&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;salary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;all&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Jooble:&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nl"&gt;"salary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(often&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;empty)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The adapter layer normalizes each response into a consistent shape. Reed's &lt;code&gt;minimumSalary&lt;/code&gt; becomes &lt;code&gt;salary_min&lt;/code&gt;. Remotive's free-text salary string gets passed through as-is (parsing "$130,000 - $170,000" into min/max is the agent's job — the API shouldn't guess).&lt;/p&gt;

&lt;p&gt;Every adapter also strips HTML from descriptions (job boards love injecting &lt;code&gt;&amp;amp;nbsp;&lt;/code&gt; and &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; tags into plain text fields) using a shared &lt;code&gt;stripHtml()&lt;/code&gt; utility. This sounds trivial until you're debugging why an agent is hallucinating HTML entities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Payment: Per-Call, Not Per-Month
&lt;/h2&gt;

&lt;p&gt;Each job search costs $0.001 to $0.002 per call. The payment happens via x402 — the HTTP standard where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Agent calls a tool → gets &lt;code&gt;402 Payment Required&lt;/code&gt; with price&lt;/li&gt;
&lt;li&gt;Agent signs a USDC micropayment on Base&lt;/li&gt;
&lt;li&gt;Agent retries with payment proof in &lt;code&gt;X-PAYMENT&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;Server verifies, escrows funds, calls the upstream API, returns data&lt;/li&gt;
&lt;li&gt;Escrow settles to the platform wallet&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a recruiting agent that runs 100 job searches per day across 7 providers, that's roughly &lt;strong&gt;$0.15/day&lt;/strong&gt;. Compare that to subscribing to 7 different job APIs at $30-100/month each.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Traditional: 7 APIs × ~$50/month = $350/month
Per-call:    100 calls/day × $0.002 × 30 days = $6/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is why per-call pricing matters for agents. Most agents are bursty — they run a batch of searches, synthesize results, then go idle. Paying subscriptions for idle capacity is exactly the wrong model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The entire jobs toolkit is live right now. Connect any MCP client:&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;"apibase"&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;"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://apibase.pro/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"transport"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"streamable-http"&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;Or use REST directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get all available job tools&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://apibase.pro/api/v1/tools | &lt;span class="se"&gt;\&lt;/span&gt;
  python3 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"
import sys,json
tools = json.load(sys.stdin)['data']
jobs = [t for t in tools if t['category'] == 'jobs' or 'job' in t['name'].lower()]
for t in jobs:
    print(f&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;{t['id']:30s} &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;{t['pricing']['price_usd']}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;)
"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP endpoint is at &lt;code&gt;https://apibase.pro/mcp&lt;/code&gt;. The full tool catalog (409 tools across 30+ categories — not just jobs) is at &lt;code&gt;https://apibase.pro/api/v1/tools&lt;/code&gt;. Source code is on &lt;a href="https://github.com/whiteknightonhorse/APIbase" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The jobs category alone now has 20 tools across 7 specialized providers. Each one was chosen for a specific coverage gap — there's no overlap where one provider does everything another does. That's the point of a gateway: you pick the best tool for each question, not the best "one API to rule them all."&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with &lt;a href="https://apibase.pro" rel="noopener noreferrer"&gt;APIbase.pro&lt;/a&gt; — 409 tools, 121 providers, one MCP endpoint.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>6 Things No Other MCP Server Lets Your AI Agent Do</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Tue, 24 Mar 2026 12:47:28 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/6-things-no-other-mcp-server-lets-your-ai-agent-do-53ei</link>
      <guid>https://dev.to/whiteknightonhorse/6-things-no-other-mcp-server-lets-your-ai-agent-do-53ei</guid>
      <description>&lt;h2&gt;
  
  
  Your AI agent can chat. But can it buy a domain?
&lt;/h2&gt;

&lt;p&gt;Most MCP servers give agents access to search, weather, maybe a database. Useful, but not differentiated. Every MCP directory has a dozen weather tools and five search wrappers.&lt;/p&gt;

&lt;p&gt;I spent the last week asking a different question: what can an AI agent do through MCP that it literally cannot do anywhere else?&lt;/p&gt;

&lt;p&gt;The answer turned into six exclusive integrations that I haven't seen on any other MCP server. Here's what they are, why they matter, and how agents actually use them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "exclusive" matters for MCP
&lt;/h2&gt;

&lt;p&gt;MCP servers are multiplying fast. Smithery lists hundreds. Most wrap the same APIs — OpenWeatherMap, Google Search, maybe a stock price feed.&lt;/p&gt;

&lt;p&gt;The problem: if every MCP server offers the same tools, agents have no reason to prefer one over another. The value isn't in wrapping APIs. It's in &lt;strong&gt;which&lt;/strong&gt; APIs you wrap and &lt;strong&gt;what workflows&lt;/strong&gt; they unlock when combined.&lt;/p&gt;

&lt;p&gt;That's what pushed me to look beyond data-retrieval tools toward tools that let agents &lt;strong&gt;take action&lt;/strong&gt; in the real world.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Register a domain name
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check if a domain is available&lt;/span&gt;
POST /tools/namesilo.domain_check
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"domains"&lt;/span&gt;: &lt;span class="s2"&gt;"mycoolstartup.com,awesomeapp.io,buildfast.dev"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;"available"&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;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mycoolstartup.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;17.29&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="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"buildfast.dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price_usd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;14.99&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="nl"&gt;"unavailable"&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="s2"&gt;"awesomeapp.io"&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;The agent checks availability, sees the price, and can call &lt;code&gt;namesilo.domain_register&lt;/code&gt; to actually purchase it. The domain cost gets charged through x402 USDC — the agent pays, the domain is registered, WHOIS privacy included.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; An agent building a website for a client can now handle the entire domain lifecycle — check, buy, configure — without a human opening GoDaddy.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Manage Cloudflare DNS
&lt;/h2&gt;

&lt;p&gt;Once the agent owns a domain, it needs to point it somewhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST /tools/cloudflare.dns_create
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"zone_id"&lt;/span&gt;: &lt;span class="s2"&gt;"abc123..."&lt;/span&gt;,
  &lt;span class="s2"&gt;"type"&lt;/span&gt;: &lt;span class="s2"&gt;"A"&lt;/span&gt;,
  &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"api"&lt;/span&gt;,
  &lt;span class="s2"&gt;"content"&lt;/span&gt;: &lt;span class="s2"&gt;"5.78.135.159"&lt;/span&gt;,
  &lt;span class="s2"&gt;"proxied"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six DNS tools: list zones, list records, create records, delete records, view traffic analytics, and purge CDN cache.&lt;/p&gt;

&lt;p&gt;The real power is the &lt;strong&gt;combination&lt;/strong&gt;. Domain purchase (NameSilo) + DNS configuration (Cloudflare) = an agent that can deploy a complete web presence from scratch. No dashboards, no clicking through UIs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent workflow:
1. namesilo.domain_check → "buildfast.dev available"
2. namesilo.domain_register → domain purchased
3. cloudflare.dns_create → A record → server IP
4. cloudflare.purge_cache → CDN active
Total: 4 API calls. Zero human interaction.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Search 577,000 clinical trials
&lt;/h2&gt;

&lt;p&gt;This one surprised me. ClinicalTrials.gov has a public API with every clinical study registered in the US — drug trials, device trials, behavioral studies — from 220+ countries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST /tools/clinical.search
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"condition"&lt;/span&gt;: &lt;span class="s2"&gt;"Breast Cancer"&lt;/span&gt;,
  &lt;span class="s2"&gt;"intervention"&lt;/span&gt;: &lt;span class="s2"&gt;"pembrolizumab"&lt;/span&gt;,
  &lt;span class="s2"&gt;"status"&lt;/span&gt;: &lt;span class="s2"&gt;"RECRUITING"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns: NCT ID, title, sponsor, enrollment count, phase, interventions, dates. The detail endpoint (&lt;code&gt;clinical.study&lt;/code&gt;) gives you the full protocol — eligibility criteria, primary outcomes, dosing schedules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Healthcare AI agents are one of the fastest-growing segments. A research agent can now search for "all Phase 3 trials for lung cancer recruiting in 2026" and get structured, machine-readable results. No scraping, no parsing PDFs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who uses this:&lt;/strong&gt; Pharma competitive intelligence agents, clinical research assistants, patient-matching systems, academic research bots.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Send Telegram messages
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST /tools/telegram.send_message
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"chat_id"&lt;/span&gt;: &lt;span class="s2"&gt;"123456789"&lt;/span&gt;,
  &lt;span class="s2"&gt;"text"&lt;/span&gt;: &lt;span class="s2"&gt;"Portfolio alert: AAPL dropped 5% to &lt;/span&gt;&lt;span class="nv"&gt;$237&lt;/span&gt;&lt;span class="s2"&gt;.50"&lt;/span&gt;,
  &lt;span class="s2"&gt;"parse_mode"&lt;/span&gt;: &lt;span class="s2"&gt;"Markdown"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five tools: send text messages (with Markdown/HTML), send photos, send documents (PDFs, CSVs), check for incoming messages, and get chat info.&lt;/p&gt;

&lt;p&gt;The game-changer is combining this with monitoring tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent workflow:
1. finnhub.quote → check stock price
2. Price dropped 5%? →
3. telegram.send_message → alert the user
4. edgar.company_facts → pull latest SEC filing
5. telegram.send_document → send financial summary as PDF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every monitoring agent needs a notification channel. Telegram is free, has 900M users, and the bot API has no meaningful rate limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content moderation built in:&lt;/strong&gt; Every outbound message passes through a content filter that blocks prohibited content (drugs, weapons, CSAM, terrorism) &lt;em&gt;before&lt;/em&gt; it reaches the Telegram API. The blocklist covers exact phrases, regex patterns, and URL validation. If the filter catches something, the message is never sent.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Spin up managed browser sessions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST /tools/browser.create_session
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"region"&lt;/span&gt;: &lt;span class="s2"&gt;"us-west-2"&lt;/span&gt;,
  &lt;span class="s2"&gt;"proxy"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;"session_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0f5e888e-8109-4395-a62a-95f07943160e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RUNNING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connect_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;"wss://connect.browserbase.com?apiKey=...&amp;amp;sessionId=..."&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;This creates a real Chromium browser session in the cloud. The agent gets a WebSocket URL it can connect to with Puppeteer or Playwright. Navigate pages, fill forms, click buttons, take screenshots — on infrastructure that handles anti-bot detection and residential proxies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Computer-use agents (Claude Computer Use, GPT-4o browsing) need browser infrastructure they can't self-provision. Per-session pricing ($0.01-0.05) makes it economically viable for agents to browse the web on-demand.&lt;/p&gt;

&lt;p&gt;Powered by Browserbase — one of the earliest adopters of x402 agent payments.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Search free stock photos and videos
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST /tools/pexels.search_photos
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"query"&lt;/span&gt;: &lt;span class="s2"&gt;"modern office workspace"&lt;/span&gt;,
  &lt;span class="s2"&gt;"orientation"&lt;/span&gt;: &lt;span class="s2"&gt;"landscape"&lt;/span&gt;,
  &lt;span class="s2"&gt;"size"&lt;/span&gt;: &lt;span class="s2"&gt;"large"&lt;/span&gt;,
  &lt;span class="s2"&gt;"limit"&lt;/span&gt;: 5
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns high-quality photos with download URLs in multiple sizes (original, large, medium, small, portrait, landscape). All photos are free for commercial use under the Pexels license — no attribution required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; Content-generation agents building websites, reports, or marketing materials need licensed media. Instead of a human browsing stock photo sites, the agent searches, selects, and downloads — all programmatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: action, not just data
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Traditional MCP&lt;/th&gt;
&lt;th&gt;These tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Domain&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Check + buy + manage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Create, delete, analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clinical data&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;577K trials searchable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Messaging&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Telegram with content filter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Managed sessions with proxy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stock media&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Free commercial-use photos&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The common thread: these tools let agents &lt;strong&gt;do things&lt;/strong&gt;, not just &lt;strong&gt;look things up&lt;/strong&gt;. Register a domain. Configure infrastructure. Send a notification. Spin up a browser. Get licensed media.&lt;/p&gt;

&lt;p&gt;That's the direction agentic commerce is heading. McKinsey projects $3-5 trillion in agentic commerce by 2030. The agents that win won't be the ones with the best chat — they'll be the ones that can take action in the real world.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;After this week's sprint:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;300 tools&lt;/strong&gt; across &lt;strong&gt;84 providers&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 exclusive capabilities&lt;/strong&gt; no other MCP server offers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30+ categories&lt;/strong&gt;: travel, finance, health, legal, entertainment, infrastructure, messaging, media&lt;/li&gt;
&lt;li&gt;All paid per-call via x402 USDC on Base&lt;/li&gt;
&lt;li&gt;Open source: &lt;a href="https://github.com/whiteknightonhorse/APIbase" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Connect any MCP-compatible client:&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;"apibase"&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;"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://apibase.pro/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;Or browse the full tool catalog: &lt;code&gt;https://apibase.pro/api/v1/tools&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The clinical trials search, stock photos, and domain availability check all work on the free tier. Send a Telegram message to see the content filter in action.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with &lt;a href="https://apibase.pro" rel="noopener noreferrer"&gt;APIbase&lt;/a&gt; — 300 tools, 84 providers, one MCP endpoint.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>showdev</category>
    </item>
    <item>
      <title>What Happens When an AI Agent Pays for Its Own API Calls</title>
      <dc:creator>whiteknightonhorse</dc:creator>
      <pubDate>Thu, 19 Mar 2026 14:53:30 +0000</pubDate>
      <link>https://dev.to/whiteknightonhorse/what-happens-when-an-ai-agent-pays-for-its-own-api-calls-4lbk</link>
      <guid>https://dev.to/whiteknightonhorse/what-happens-when-an-ai-agent-pays-for-its-own-api-calls-4lbk</guid>
      <description>&lt;p&gt;Your AI agent needs to search flights. It needs real-time stock prices. It needs to OCR a receipt image. Each of these requires a different API, a different auth flow, a different billing account.&lt;/p&gt;

&lt;p&gt;What if the agent just... paid for each call itself? No subscriptions. No API key management. No human in the loop.&lt;/p&gt;

&lt;p&gt;That's what I built. Here's how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: API Integration Is a Tax on Every Agent Builder
&lt;/h2&gt;

&lt;p&gt;If you're building an AI agent that interacts with the real world, you already know the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amadeus needs OAuth2 with double-base64 encoding&lt;/li&gt;
&lt;li&gt;Finnhub uses a query param token&lt;/li&gt;
&lt;li&gt;Serper wants an &lt;code&gt;X-API-KEY&lt;/code&gt; header&lt;/li&gt;
&lt;li&gt;NASA uses &lt;code&gt;?api_key=&lt;/code&gt; in the URL&lt;/li&gt;
&lt;li&gt;Some APIs charge per call, others per month, others per character&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each provider, you're writing auth code, error handling, retry logic, rate limiting, and billing integration. Multiply that by 10 providers and you've spent more time on plumbing than on your actual agent logic.&lt;/p&gt;

&lt;p&gt;I wanted one endpoint where my agent sends a tool call, pays in USDC, and gets data back. No signup forms. No dashboards. No invoices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: MCP + x402 in One Pipeline
&lt;/h2&gt;

&lt;p&gt;I built an MCP server that wraps 46 upstream API providers behind a single endpoint. The agent connects to &lt;code&gt;https://apibase.pro/mcp&lt;/code&gt;, discovers 203 available tools, and calls any of them. Payment happens automatically via the x402 protocol — HTTP 402 with USDC on Base.&lt;/p&gt;

&lt;p&gt;Here's what a single tool call looks like from the agent's perspective:&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;"jsonrpc"&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.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tools/call"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stocks.market.quote"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&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;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AAPL"&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;The response comes back with the stock price. Behind the scenes, $0.001 in USDC was escrowed, the Finnhub API was called, and the payment was settled — all in under 400ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 13-Stage Pipeline
&lt;/h2&gt;

&lt;p&gt;Every tool call passes through 13 stages in strict order. No stage can be skipped or reordered:&lt;/p&gt;

&lt;p&gt;AUTH → IDEMPOTENCY → CONTENT_NEG → SCHEMA_VALIDATION → TOOL_STATUS → CACHE_OR_SINGLE_FLIGHT → RATE_LIMIT → ESCROW → PROVIDER_CALL → ESCROW_FINALIZE → LEDGER_WRITE → CACHE_SET → RESPONSE&lt;/p&gt;

&lt;p&gt;Let me walk through the stages that matter most.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 1: AUTH
&lt;/h3&gt;

&lt;p&gt;The agent authenticates with a Bearer token. On first request, the system auto-registers the agent and returns an API key — no human signup required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/api/v1/agents/register &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"agent_name": "my-agent", "agent_version": "1.0.0"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returns &lt;code&gt;api_key: ak_live_...&lt;/code&gt; — stored as SHA-256 hash in PostgreSQL, never in plaintext.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 4: SCHEMA_VALIDATION
&lt;/h3&gt;

&lt;p&gt;Every tool has a Zod schema with &lt;code&gt;.describe()&lt;/code&gt; on every field. The agent can't send garbage — invalid params are rejected at this stage with a clear error message, before any money moves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search query&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;gl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Country code (e.g. "us")&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;num&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Results count&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stage 8: ESCROW
&lt;/h3&gt;

&lt;p&gt;This is where it gets interesting. Before calling the upstream provider, we lock the tool's price in USDC:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;finnhub.quote&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.001&lt;/td&gt;
&lt;td&gt;Escrow $0.001 USDC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;serper.web_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.002&lt;/td&gt;
&lt;td&gt;Escrow $0.002 USDC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;amadeus.flight_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.035&lt;/td&gt;
&lt;td&gt;Escrow $0.035 USDC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stability.generate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.070&lt;/td&gt;
&lt;td&gt;Escrow $0.070 USDC&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The USDC is reserved from the agent's balance in a PostgreSQL transaction. If the provider call fails, Stage 10 automatically refunds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 9: PROVIDER_CALL
&lt;/h3&gt;

&lt;p&gt;Now we actually call the upstream API. Each provider has a dedicated adapter that handles auth, request building, and response normalization.&lt;/p&gt;

&lt;p&gt;What the agent sends:&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="nl"&gt;"symbol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AAPL"&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;What our adapter sends to Finnhub:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET https://finnhub.io/api/v1/quote?symbol=AAPL&amp;amp;token=xxxxx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;What comes back to the agent (normalized):&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;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"change"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-4.06&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"change_percent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-1.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"high"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;254.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"low"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;249.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"open"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;253.78&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"previous_close"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;254.00&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;The agent never sees the upstream API format, auth headers, or error codes. Every tool returns the same normalized structure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stage 10: ESCROW_FINALIZE + LEDGER_WRITE
&lt;/h3&gt;

&lt;p&gt;If the provider call succeeded: settle the escrow, write to the append-only ledger. If it failed: refund the USDC, write a REFUNDED ledger entry. This happens in a single PostgreSQL transaction — no partial state possible.&lt;/p&gt;

&lt;p&gt;The ledger is append-only. We never UPDATE or DELETE rows. This gives us a complete audit trail of every payment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 46 Providers Look Like Through One Pipe
&lt;/h2&gt;

&lt;p&gt;Here's a sample of what agents can do through this single MCP endpoint:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Tools&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flights&lt;/td&gt;
&lt;td&gt;amadeus.flight_search&lt;/td&gt;
&lt;td&gt;Search JFK to LHR, real prices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stocks&lt;/td&gt;
&lt;td&gt;finnhub.quote, finnhub.candles&lt;/td&gt;
&lt;td&gt;AAPL $249.94, OHLCV charts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Search&lt;/td&gt;
&lt;td&gt;serper.web_search&lt;/td&gt;
&lt;td&gt;Google results as JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Search&lt;/td&gt;
&lt;td&gt;tavily.search&lt;/td&gt;
&lt;td&gt;AI-synthesized answers + sources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;News&lt;/td&gt;
&lt;td&gt;news.latest, news.crypto&lt;/td&gt;
&lt;td&gt;180K+ sources, 200+ countries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legal&lt;/td&gt;
&lt;td&gt;courtlistener.search&lt;/td&gt;
&lt;td&gt;US court opinions since 1995&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real Estate&lt;/td&gt;
&lt;td&gt;walkscore.score&lt;/td&gt;
&lt;td&gt;Walk/Transit/Bike scores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image Gen&lt;/td&gt;
&lt;td&gt;stability.generate&lt;/td&gt;
&lt;td&gt;Stable Diffusion from text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;resend.send_email&lt;/td&gt;
&lt;td&gt;Transactional email delivery&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCR&lt;/td&gt;
&lt;td&gt;ocr.extract_text&lt;/td&gt;
&lt;td&gt;Text from image/PDF URL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each tool costs between $0.001 and $0.070 per call. The agent decides what to call based on the task. No subscriptions, no minimums.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cache Layer: Why Most Calls Are Nearly Free
&lt;/h2&gt;

&lt;p&gt;Stage 6 checks Redis before hitting the upstream provider. Each tool has a configured TTL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;finnhub.quote&lt;/strong&gt; — 5 seconds (stock prices change fast)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;walkscore.score&lt;/strong&gt; — 7 days (walkability scores rarely change)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;news.latest&lt;/strong&gt; — 1 minute (news updates frequently)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;courtlistener.search&lt;/strong&gt; — 1 hour (court opinions are historical)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If 100 agents request AAPL's stock price in the same 5-second window, only one upstream call happens. The other 99 get the cached result instantly — still billed, but at a lower cache-hit price, and the upstream provider sees only one request.&lt;/p&gt;

&lt;p&gt;Single-flight deduplication prevents thundering herd: concurrent identical requests wait for the first one to complete rather than all hitting the provider simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned Building This
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Escrow-first is non-negotiable.&lt;/strong&gt; Early versions charged after the provider call. But if the agent disconnected mid-response, we'd already incurred upstream cost with no payment. Escrow-before-call eliminates this entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Idempotency prevents double charges.&lt;/strong&gt; Agents retry on timeout. Without idempotency keys, a single flight search could charge the agent twice. Stage 2 catches duplicates before any work happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Fail-closed beats fail-open.&lt;/strong&gt; When Redis goes down, we reject all requests rather than disabling rate limits and caching. This sounds aggressive, but it prevents a single Redis restart from causing a cascade of unthrottled upstream calls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. 13 stages sounds like overhead, but each one prevents a real production bug.&lt;/strong&gt; We removed a stage once (content negotiation) and immediately got agents sending XML to JSON-only providers. Every stage exists because we hit the bug it prevents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Connect any MCP client to the endpoint and discover the tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://apibase.pro/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or add it to Claude Desktop / Cursor:&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;"apibase"&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;"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://apibase.pro/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;203 tools. One endpoint. The agent pays for what it uses.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built with &lt;a href="https://apibase.pro" rel="noopener noreferrer"&gt;APIbase&lt;/a&gt; — open source on &lt;a href="https://github.com/whiteknightonhorse/APIbase" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>agents</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
