apps/agent is the agent-facing half of STELLARSIGHT: an MCP server that drops the Stellar
Bazaar directly into an AI agent’s runtime. The agent searches the bazaar in natural
language, reads a resource’s exact call contract, and then actually pays for it — the full
discover → 402 → sign → retry → settle x402 loop happens inside a single tool call.
No API key. No vendor account. No human in the loop. Just a wallet.
This is RFP requirement 3.3.
Testnet only. No relayer, no third-party channel service — the payment is signed locally with
@x402/stellar and settled by the STELLARSIGHT facilitator on stellar:testnet.
Quick start
Wiring it into Claude
Claude Desktop — claude_desktop_config.json
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
Claude Code
.mcp.json at the project root:
PAYER_SECRET and friends are read from the repo-root /.env when they are not in env, so
the plain form above works once scripts/setup-testnet.mjs has run. Diagnostics go to
stderr only — stdout is the JSON-RPC transport.
Tools
All four tools return both a JSON text block (for the model) andstructuredContent (for
the host). Every result is { ok: true, ... } or { ok: false, code, reason }. reason is
never null on a rejection.
stellarsight_search
Ranked natural-language search over the bazaar. Each candidate carries the index’s _explain
breakdown, so the ranking is auditable rather than a black box.
stellarsight_browse
Unranked catalogue listing. Use it to see what exists, or to enumerate one seller’s endpoints.
stellarsight_describe
Full discovery metadata for one resource, flattened into a call-construction brief: every
parameter with its type, whether it is required, and its description — so the agent can build a
valid call with no external documentation.
stellarsight_pay
The whole x402 loop in one call: request → 402 challenge → sign the Soroban auth entry with the
operator’s PAYER_SECRET → retry with the payment header → return the unlocked body plus the
settled transaction hash and its explorer link.
Spends real testnet funds. Set maxPrice to cap it.
{ ok: true, paid: false, body }.
timings is always present, including on rejections — the UI reads it.
Error codes
Every rejection is{ ok: false, code, reason } with a non-null, human-readable reason.
Nothing throws out of a tool handler.
The enum is exported as
ERROR_CODES from src/pay.mjs, and facilitator failure strings are
mapped onto it deterministically by classifySettleFailure().
The terminal demo
Using the payment client directly
payAndFetch never throws for a protocol or network failure — it resolves to a coded result.
Tests
PAYMENT-SIGNATURE header and an expired authorization entry are both
refused, each with a non-null reason and the right code, and that no rejection path in the
client can produce a null reason. The first three tests are hermetic (local stub seller,
throwaway keypair, no network). The fourth exercises the live facilitator and skips cleanly
when it is not running.
Environment
Read from the repo-root/.env, overridable by process.env or the MCP env block.
Protocol notes
Verified against the installed@x402/core@2.21 build, not assumed:
- 402 challenge arrives in the
PAYMENT-REQUIREDresponse header (base64 JSON). STELLARSIGHT also accepts the same object in the JSON body, which is what several v2 servers emit. - The signed payload goes out as
PAYMENT-SIGNATURE(x402 v2); STELLARSIGHT mirrors it ontoX-PAYMENTso v1-shaped sellers work unchanged. - Settlement comes back in
PAYMENT-RESPONSE/X-PAYMENT-RESPONSEas{ success, errorReason, transaction, network, payer }. - Bazaar extension status rides on
EXTENSION-RESPONSES(base64 JSON) and is surfaced asextensions.bazaaron the result.