Repository navigation
Conversation
|
@AGWAM001 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
paid_call signs with a real mainnet key, and maxPrice only bounds one mistake — a caller in a retry loop could spend without limit. Add a cumulative USD ceiling that reserves each call's maximum before the payment runs and settles it after, record every attempt in an audit ledger, and refuse to spend at all when a durable ledger was asked for and cannot be written. The same tools are also served over Streamable HTTP, which refuses to start without a bearer token since it exposes paid_call to the network. Cover Divinity-Labs#421: bazaar_search, ListTools and the unknown-tool path had no tests, and the simulated upstream errors were plain strings that hid how handlePaidCallError classifies on lowercased message substrings. Fixtures now use the shapes that @x402/fetch, @x402/core and @x402/stellar really throw, including one Horizon error whose op_no_trust signal is invisible to that matcher.
|
Needs a rebase — #488 (the SSRF guard for Two things worth knowing before you rebase, because three PRs are converging on the same file:
Push the rebase and I will review properly. The spend ceiling is the half of #404 that actually bounds the loss — an allow-list stops the money going somewhere strange, a ceiling stops it going somewhere allowed ten thousand times. |
Coordination note — ten PRs are editing one 179-line fileIf your MCP PR has just gone red with a conflict, this is why, and it is my fault rather than yours. I published 22 MCP issues (#404–#425) as if they were independent. They are not: almost all of them land in Already merged:
Order I intend to take the rest in, so you can rebase once rather than repeatedly:
Please do not all rebase at once. If you are below the one currently in flight, wait until the one above you lands — otherwise you rebase, I merge someone else, and you rebase again. I will comment on your PR when it is your turn. One thing to settle between you: Nothing here reflects on the quality of the work. Several of these are among the best PRs this repo has had. |
|
#487 has landed — the I resolved #487's conflicts myself because nine PRs were stuck behind it. Three things on 1. Two refusal codes, deliberately separate. ERR_URL_BLOCKED // the target resolves somewhere we will never fetch (#488)
ERR_HOST_NOT_ALLOWED // reachable, but not on the paid_call allow-list (#487)If your PR adds a refusal, extend this vocabulary rather than starting a third. "I cannot reach there" and "I will not pay there" are different answers; whatever you add should be a third distinct answer, not a synonym for one of these. 2. The constructor takes 3. Push the rebase and I will review it. If it conflicts in a way that is not obvious, say so and I will resolve it rather than leave you stuck. |
Summary
Closes #406, #419 and #421. Adds cumulative spend controls, a payment audit trail and an HTTP transport to the MCP server.
bazaar_search(with and without a query, empty results in both shapes, non-2xx, malformed body, transport failure),ListTools(advertised names, result parsed with the SDK's ownListToolsResultSchema, every tool validated withToolSchema,inputSchema.type === "object", eachrequiredentry declared inproperties) and the unknown-tool path. The four pre-existing tests are untouched and still pass.maxPricebounds one mistake, not a day of retries, andpaid_callsigns with a real mainnet key. A cumulative USD ceiling now reserves each call's maximum before the payment runs and settles it afterwards.paid_callto the network.Related issue
Closes #406 — the payment audit ledger (nothing records what the agent spent).
Closes #419 — the HTTP transport.
Closes #421 — the tool test coverage.
Type of change
Checklist
npx tsc --noEmitpassesnpm run buildpasses — not verified here, so left untickedREADME.md,.env.example, three changesets)Test evidence
npx vitest run tests/mcp.test.ts— 40 passednpx vitest run tests/mcp-http.test.ts— 22 passednpx tsc --noEmit— cleantests/aggregator.property.test.tsfails on this machine with "Failed to resolve entry for package fast-check", a devDependency resolution problem in this install. That file imports onlysrc/aggregator/bestRouteandsrc/db, so this diff cannot account for it.Notes for reviewers
Three new tests deliberately characterize
handlePaidCallError's lowercased-substring matching rather than endorse it:No client registered for scheme: exact and network: stellar:pubnet— local x402 misconfiguration, yet reported asERR_SERVICE_UNREACHABLEbecause the message contains "network".extras.result_codes.operations: ["op_no_trust"]— reported asERR_INTERNAL_FAILUREbecause onlye.messageis read.ERR_SERVICE_UNREACHABLE, conflating a transport failure with a bad payload.Making the matcher read structured fields would fail those tests on purpose; that is what #421 means by plain strings hiding the fragility.
Upstream error fixtures reuse messages the published packages really throw (
Failed to create payment payload: ...,Invalid Stellar asset address: ..., undici'sTypeError: fetch failedwith anECONNREFUSEDcause) instead of invented text. No key material appears anywhere; hosts arebazaar.exampleand the TEST-NET address203.0.113.10.The #421 tests and the spend-control feature are in one commit because
tests/mcp.test.tsnow importssrc/mcp/budget.tsandsrc/mcp/ledger.ts. Say so if you would rather they land separately.