Skip to content

feat(#4557): wire X402PaymentGate into the serve surfaces#228

Merged
Skobeltsyn merged 1 commit into
mainfrom
feat/x402-serve-wiring
Jun 16, 2026
Merged

feat(#4557): wire X402PaymentGate into the serve surfaces#228
Skobeltsyn merged 1 commit into
mainfrom
feat/x402-serve-wiring

Conversation

@Skobeltsyn

Copy link
Copy Markdown
Contributor

Summary

Follow-on to #4527 (#4557): wire X402PaymentGate into the serve surfaces so an agent can monetize its served endpoint directly. X402PaymentGate wraps a JDK HttpHandler, but the serve surfaces build their HttpServer internally with no injection point — so x402 couldn't actually front them until now.

NlWebServer.from(agent, payment = X402PaymentGate(requirements, facilitator)).start()
// also AgUiServer.from / A2AServer.from

Change

  • Optional payment: X402PaymentGate? = null on NlWebServer.from / AgUiServer.from / A2AServer.from; each wraps its invocation handler (payment?.gate(h) ?: h).
  • A2A: only the RPC path is gated — the /.well-known/agent-card.json discovery endpoint stays free (you must be able to read the terms before paying).
  • McpServer intentionally not gated here — it wants a granular paidTool() (per-tool pricing) per PRD §12.8, a separate follow-up, not a blanket endpoint gate.

Gates

2 hermetic integration tests (NLWeb + AG-UI gated by a fake facilitator: 402 without X-PAYMENT, served with it). Full ./gradlew build green. README + CHANGELOG + internals adjunct updated. Closes #4557.

CodeQL java-kotlin expected-red on Kotlin 2.4 (codeql#21938); build is the gate.

🤖 Generated with Claude Code

Follow-on to #4527. X402PaymentGate wraps a JDK HttpHandler, but the serve surfaces
created their HttpServer internally with no injection point — so you couldn't put x402
in front of them. Now `NlWebServer.from`, `AgUiServer.from`, and `A2AServer.from` take
an optional `payment: X402PaymentGate? = null` and wrap their invocation handler
(payment?.gate(h) ?: h). An agent can now monetize its served endpoint directly:
`NlWebServer.from(agent, payment = gate).start()`.

- A2A: only the RPC path is gated; the /.well-known agent-card discovery stays FREE.
- McpServer intentionally NOT gated here — it wants a granular paidTool() (per-tool
  pricing) per PRD §12.8, a separate follow-up, not a blanket endpoint gate.
- 2 hermetic integration tests (NlWeb + AG-UI gated by a fake facilitator). README +
  CHANGELOG + internals adjunct updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Skobeltsyn Skobeltsyn merged commit 0e604af into main Jun 16, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant