Skip to content

feat(mcp): the paid-depth seam and its structured refusal - #11219

Merged
JSONbored merged 1 commit into
mainfrom
feat/paid-tier-seam
Aug 14, 2026
Merged

feat(mcp): the paid-depth seam and its structured refusal#11219
JSONbored merged 1 commit into
mainfrom
feat/paid-tier-seam

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #11179.

Tier gates depth, never visibility. Every tool stays listed and callable at every tier; what a key buys is how far back a call may read. A paid tool hidden from free callers is a tool nobody discovers or upgrades for — the same absence-reads-as-nonexistence failure this repo measured twice already (unregistered mutations in #11146, empty captured schemas in #11148).

What shipped

Phase 1 was already in place and is verified, not rebuilt: applyTieredRateLimit resolves the tier at the MCP dispatch seam, and authTier has ridden every $mcp_tool_call since #8967 — which is exactly why phase 3 could be decided from data instead of taste.

Phase 2 — the structured refusal. payment_required rides the existing tool-error path with a payment block: tier, required_tier, boundary, limit, requested, upgrade_url. The message carries the upgrade URL too, so a client that renders only prose still shows its human something actionable. The block is shaped so an x402 challenge later joins it rather than introducing a second error vocabulary. Published where agents actually read: the tool description and public/skills/bittensor/SKILL.md.

Phase 3 — the first boundary, chosen from usage. Over the 30 days to 2026-08-14 the economics family carried the most distinct callers of any tool (get_subnet_economics: 52 callers, above get_subnet_health's 47 on a third the volume) — economic history is the demand centre the issue predicted. Effectively all measured traffic is anonymous, so the free depth stays a real product rather than a teaser: 7d/30d/90d open to everyone, and only 1y and all — the two whole-rollup scans — need a paid key.

Phase 4 (x402) is the evaluate-after step in the issue; the seam it needed now exists and the refusal shape is where a challenge will live.

Two traps closed by tests

  • An unrecognised tier clears nothing. "enterprise", "__proto__", "" all rank below free — otherwise a typo in an account record becomes free access to every paid depth.
  • An unbounded window crosses every finite ceiling. all parses to days: null; treating null as "no request" would have made the deepest read the one thing that passed free.

Validation

  • typecheck, lint, format:check, validate:mcp (240 tools), validate:unreferenced-exports (731 — at the ceiling, not raised), validate:module-state-resets
  • Full suite: 918 files / 20,932 tests passed
  • Diff-intersection coverage: 0 uncovered lines and 0 partial branch arms across src/mcp-tier-gate.ts (100%) and every changed src/mcp-server.ts line. The one partial branch an earlier revision had — a ?? "anonymous" fallback — was removed rather than ignored: applyTieredRateLimit always sets a tier, so the arm was unreachable by construction.
  • The boundary is proven end-to-end through a real tools/call: anonymous 1ypayment_required with the block; the same anonymous caller at 30d → never gated; the gated tool still appears in tools/list

Tier gates DEPTH, never visibility. Every tool stays listed and callable at
every tier; a call past a paid boundary answers a structured
`payment_required` naming the boundary, the tier that clears it, and where to
get one -- so an agent relays an actionable upgrade path instead of reporting
a dead end. A paid tool hidden from free callers is a tool nobody discovers
or upgrades for, which is the same absence-reads-as-nonexistence failure this
repo measured twice in #11146 and #11148.

The tier resolver already existed at the MCP dispatch seam (authTier has
ridden every $mcp_tool_call since #8967), so the seam is the refusal plus the
first boundary: history windows on get_economics_trends. That surface was
CHOSEN FROM USAGE -- over the 30 days to 2026-08-14 the economics family
carried the most distinct callers of any tool (get_subnet_economics: 52,
above get_subnet_health's 47 on a third the volume). Effectively all traffic
is anonymous, so the free depth stays a real product: 7d/30d/90d are open to
everyone and only `1y` and `all` -- the two whole-rollup scans -- need a key.

An unrecognised tier clears nothing, and an unbounded window crosses every
finite ceiling. The `payment` block is shaped so an x402 challenge later
joins it rather than introducing a second error vocabulary.

Closes #11179
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
metagraphed-registry-sync-api af49a1d Aug 14 2026, 01:17 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
metagraphed-wss-lb af49a1d Aug 14 2026, 01:17 PM

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
metagraphed-data-api af49a1d Aug 14 2026, 01:17 PM

@superagent-security

Copy link
Copy Markdown

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.51%. Comparing base (20e8af1) to head (af49a1d).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #11219   +/-   ##
=======================================
  Coverage   95.51%   95.51%           
=======================================
  Files         742      743    +1     
  Lines       45308    45329   +21     
  Branches    16648    16658   +10     
=======================================
+ Hits        43277    43298   +21     
  Misses        526      526           
  Partials     1505     1505           
Files with missing lines Coverage Δ
src/mcp-server.ts 94.02% <100.00%> (+<0.01%) ⬆️
src/mcp-tier-gate.ts 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JSONbored JSONbored self-assigned this Aug 14, 2026
@JSONbored
JSONbored merged commit 3183103 into main Aug 14, 2026
17 checks passed
@JSONbored
JSONbored deleted the feat/paid-tier-seam branch August 14, 2026 20:04
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.

design(monetization): paid MCP access — one server, tiered depth, and where x402 fits

1 participant