Skip to content

feat(mcp): cumulative spend cap and durable payment audit ledger (closes #405, closes #406) - #447

Open
sparkysolutions10-pixel wants to merge 1 commit into
Divinity-Labs:mainfrom
sparkysolutions10-pixel:feat/mcp-spend-cap-and-ledger-405-406
Open

sparkysolutions10-pixel wants to merge 1 commit into
Divinity-Labs:mainfrom
sparkysolutions10-pixel:feat/mcp-spend-cap-and-ledger-405-406

Conversation

@sparkysolutions10-pixel

@sparkysolutions10-pixel sparkysolutions10-pixel commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Addresses and resolves issues #405 and #406 by introducing a cumulative spend ceiling and a durable payment audit ledger for the Bazaar MCP server.

Key Changes

  1. Cumulative Spend Ceiling (The spend cap is per call, so it is not a cap #405):

    • Configurable cumulative budget ceiling (maxCumulativeSpend, environment variable MCP_MAX_CUMULATIVE_SPEND or MCP_MAX_SESSION_SPEND, defaulting to $10.00).
    • Added distinct error code ERR_SPEND_LIMIT_EXCEEDED to MCP_ERROR_CODES in src/mcp/codes.ts. When the cumulative budget ceiling is reached, subsequent payment requests are refused with ERR_SPEND_LIMIT_EXCEEDED and a descriptive message detailing the exhausted budget.
    • Proves in tests that N calls under the per-call limit are refused once their sum exceeds the cumulative ceiling.
  2. Budget Discoverability (The spend cap is per call, so it is not a cap #405):

    • Dynamic paid_call tool description updated on ListToolsRequestSchema to disclose the per-call cap, cumulative cap, current spent total, and remaining budget to the agent before calling.
    • Added new �azaar_spend_budget MCP query tool allowing agents to inspect spending breakdown, limits, and recent audit records.
  3. Restart Behavior (The spend cap is per call, so it is not a cap #405):

    • Deliberate and documented restart handling:
      • When spendLedgerPath (MCP_SPEND_LEDGER_PATH) is configured, previous payment records and cumulative spend totals are restored from disk on startup, preventing agents or operators from bypassing the spend cap via process restarts.
      • When spendLedgerPath is omitted (default), spending is tracked in-memory for the duration of the MCP server session, suitable for stateless or serverless environments.
  4. Durable Payment Audit Ledger (Nothing records what the agent spent #406):

    • Implemented SpendLedger in src/mcp/ledger.ts.
    • Records every payment attempt (timestamp, URL, host, method, amount, network, transaction hash, outcome, and reason), whether successful or failed.
    • Extracts transaction hash from payment-response / x-payment-response headers or x-transaction-hash where present.
    • Zero secret material: Strictly never records secret keys, seeds, signatures, or raw transaction envelopes.
  5. Prometheus Metrics with Bounded Labels (Nothing records what the agent spent #406):

    • Implemented McpMetrics in src/mcp/metrics.ts.
    • mcp_payment_attempts_total: Counter tracking payment attempts labelled by bounded host,
      etwork, and outcome.
    • mcp_spend_total: Counter tracking total amount spent in USD labelled by bounded host and
      etwork.
    • host label is bounded against an allowlisted host set (�llowedHosts); any unlisted target host is mapped to 'other' to prevent Prometheus time series cardinality explosion.
  6. Changeset & Tests:

    • Added .changeset/mcp-spend-cap-and-ledger.md.
    • Expanded Vitest test suite in ests/mcp.test.ts to 10 comprehensive tests.

Closes #405
Closes #406

@Miracle656 Miracle656 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes requested: one issue per PR, and only issues assigned to you

This is a process requirement, applied to all 23 of your open PRs in this repo. It is not a judgement about the code, which I have not been able to review — and that is the first half of the problem.

The bundling

Across your open PRs, 150 distinct issues are claimed. This one claims several. #483 claims 22, #481 claims 20, #477 claims 20, #474 claims 20.

A PR that closes twenty issues cannot be reviewed. Each of those issues has its own acceptance criteria — typically five — so twenty issues is a hundred separate things to verify in one diff, and if any one of them is wrong the whole PR is blocked while it is fixed. Every batch I published says the issues are deliberately independent so they can be worked in parallel, by different people, without colliding. Bundling them removes exactly that property.

The assignments

135 of the 150 issues claimed are assigned to other contributors — 67 different people.

This PR is an example: it names issues currently assigned to other contributors who are working on them now. Several have open PRs of their own. If this merged as it stands, those people would have done the work and received nothing for it, and I would have no way to tell the two efforts apart.

I am not assuming anything about why. Assignments change, Drips and GitHub can disagree, and a wide-ranging branch picks up issue numbers easily. But the effect on the people holding those assignments is the same regardless of intent, which is why I have to act on it.

What I need

  • One issue per PR. The issue number in the title, its acceptance criteria met, and nothing else in the diff.
  • Only issues assigned to you, or unassigned ones you have claimed through Drips. If an issue is assigned to someone else, it is theirs.
  • Re-open the work that meets both conditions as individual PRs. I will review them in the order they arrive and at the same pace as everyone else's.

Nothing is being closed. These stay open and are yours to re-cut, withdraw or split as you choose.

Two things worth knowing before you re-cut

Some of this has already landed. #488 (SSRF guard for bazaar_search) and #487 (the paid_call host allow-list) cover the same ground as your #449; #486 covers the MCP README. Check current main before rebuilding something that is already there.

main has moved a long way today — #306, #309, #252, #256, #355, #381, #390, #402, #476, #488 and more. Cut from current main, not from where these branches started.

If you believe an issue named here is genuinely yours, say which and I will check the assignment myself — I would rather be corrected than have someone lose work.

@sparkysolutions10-pixel
sparkysolutions10-pixel force-pushed the feat/mcp-spend-cap-and-ledger-405-406 branch from 3a6af99 to 93924aa Compare October 19, 2026 20:34
@Miracle656

Copy link
Copy Markdown
Collaborator

Holding this behind the assignee's PRs, same as the earlier set.

This resolves #405 and #406, and both are assigned to @AGWAM001, who has a PR open for each:

Issue Assigned Their PR
#405 — the spend cap is per call, so it is not a cap AGWAM001 #492
#406 — nothing records what the agent spent AGWAM001 #523

So I will review #492 and #523 first. Not because yours is worse — I have not read either in depth yet — but because they hold the assignments, and reviewing in any other order decides it by who got there first, which is not how the assignments are meant to work.

If either lands, this closes as superseded. If one needs changes and goes quiet, the issue frees up and yours is the obvious thing to look at — tell me and I will pick it up.

One thing worth flagging: #406 was closed by mistake this morning and I have reopened it. A merge commit of mine carried the wrong issue number. So if you saw it closed and assumed the work was done, that was my error, not a signal about this PR.

Separately, on the Lens Wave budget: it is spent for this round (24,950 of 25,000), so nothing new here can be funded until it resets. Worth knowing before you put more time in.

@Miracle656

Copy link
Copy Markdown
Collaborator

Re-reviewed after your push. Same situation as #442, and I am afraid this one has less left in it.

So the spend-ceiling half duplicates something already shipped, and the ledger half belongs to someone who holds the assignment. The branch also conflicts now.

The ledger design in here was good — I said so at the time and I still think it. But I cannot merge it over an open assignment, and I would not want to: @AGWAM001 has had #406 since before this PR existed.

Please close this one. If you want to keep working in the MCP area, #442 has a genuine gap left in it that nobody else is on — the merged error classifier does no HTTP status mapping at all (grep -cE "402|403|502|503|504" src/mcp/codes.ts returns 0), and I have suggested there that you take exactly that as a small follow-up.

Not closing it myself; that is yours.

One process note, said once and not repeated: before starting, check whether the issue has an assignee. An assigned issue is spoken for. You are putting real effort into work that keeps landing on top of someone else's claim, and I would much rather that effort went somewhere it can merge.

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.

Nothing records what the agent spent The spend cap is per call, so it is not a cap

2 participants