MCP server explained: what changes when a tool costs money
An MCP server is simple to explain and harder to build once a tool has to be paid for. Four curl calls against a live merchant server, the header that hides your tools, and what x402 adds.
By XAgent Team · 2026-08-23
An MCP server is a small HTTP service that tells a model what it can do, in a format the model can read without being told. Most explanations stop there, which is enough to build one that returns the weather and not enough to build one that takes money. This is an MCP server explained from the wire — every request below was run against a live production server, and you can run them yourself.
The server is XAgent's own eSIM merchant. It sells travel data plans to AI agents and settles on-chain, so it has to do the part the tutorials skip: refuse a call until it has been paid.
MCP server explained: the four calls that matter
The protocol is JSON-RPC over HTTP. A client opens with initialize, and the
server answers with what it supports:
curl -s -X POST https://xagentgo.com/api/esim/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"probe","version":"1.0"}}}'
{"result":{"protocolVersion":"2025-06-18",
"capabilities":{"tools":{"listChanged":true}},
"serverInfo":{"name":"xagent-esim","version":"1.0.0"}}}
Two things are already settled by that response. The server speaks the 2025-06-18 revision of the spec, and it offers exactly one capability: tools. No prompts, no resources, no sampling. A merchant server does not need them.
tools/list then returns the menu. Ours has three entries: search_esim,
buy_esim, get_esim_status. Each carries a JSON Schema for its arguments,
which is the whole point of the protocol — the model does not need a prose
integration guide, it reads the schema.
tools/call runs one. search_esim is free and answers immediately:
XAgent 自营旅行 eSIM — 11 国 / 44 档:
Japan (JP):
• [1 GB 7 days] — 3.5 USDG
• [3 GB 15 days] — 7.5 USDG
• [10 GB 30 days] — 21.5 USDG
• [20 GB 30 days] — 40.5 USDG
Four calls, and an agent that had never heard of us can price a Japanese eSIM. That is the part MCP genuinely solves.
The header that returns an empty tool list
The first time we probed this endpoint from outside, tools/list came back with
zero tools. The server was healthy and the tools were there.
The request was missing half an Accept header. This server streams over
Server-Sent Events, so a client that asks only for application/json gets
nothing useful back. The working header is both:
Accept: application/json, text/event-stream
It is in the specification, and it is in almost no tutorial. If your client sees an empty tool list against a server you know has tools, check this before you check anything else.
Notice also what the response did not contain: an Mcp-Session-Id. This server
is stateless — every call stands alone, and there is no server-side cart to
resume. That is a deliberate design decision with real consequences for
checkout, which we worked through separately in
the stateless cart problem.
What changes when the tool costs money
search_esim returns data. buy_esim moves value, and the difference is not a
matter of degree.
A paid tool cannot simply execute when called. It has to answer the first call
with the terms — how much, in what currency, on what chain, to which address —
and then wait. In our server the first buy_esim call returns x402 payment
requirements rather than an eSIM. The agent signs an
EIP-3009
transferWithAuthorization for that exact amount, calls again with the signed
payment in _meta["x402/payment"], and only then does the tool do its work. The
rail is XLayer, chain 196, in USDG or USDT.
Three things follow from that, and they are what a merchant MCP server is actually made of:
- The quote must be binding. The agent signs against a number you gave it. If that number can drift between the two calls, the signature is worthless and the purchase fails at settlement.
- Every declared currency must be the same currency. We found our own
search_esimprinting prices in USDC whilebuy_esimdemanded USDG, because a field namedretailUsdcoutlived the rail it was named after. A human skims past that. A machine signs it. - Free and paid tools belong on the same server.
search_esimcosts nothing deliberately: an agent that has to pay to see a price will go somewhere else. Discovery is free, execution is paid.
What MCP does not give you
MCP standardises the request. It says nothing about who is allowed to spend, how a refund works, whether the merchant honours the quote, or what proof the buyer holds afterwards. Those are not protocol problems and no revision of the spec will solve them — they are operations, and they are the same operations whether the agent arrives speaking MCP, A2A, UCP or AP2.
That gap is the reason XAgent exists, and the longer argument for it is in what agentic commerce actually requires.
What's next
The eSIM server above is live. Point an MCP client at
https://xagentgo.com/api/esim/mcp, list the tools, and call search_esim — it
is free, and it is the shortest path to seeing what an agent sees. If you run a
store and want it to answer the same way, that is what
listing on XAgent does.
Read the MCP specification for the parts we skipped. Then decide which of your tools cost money, because that is the decision the protocol does not make for you.