MCP Billing Spec v1
Version: 1.0.0-draft Machine-readable core profile: 0.1.0 Date: 2026-10-06 Authors: TombStone Dash LLC License: MIT for this specification only Reference Code / Candidate Implementation: noui.bot (Agent Bazaar)Abstract
This specification defines a standard schema for billing, metering, receipts, verification, and dispute resolution in MCP (Model Context Protocol) tool ecosystems. It is designed to be implementable by any billing provider, marketplace, or MCP server operator. The spec is bigger than any single implementation.
Status
Draft. Feedback welcome at GitHub Issues or agents@noui.bot.
The NB-01 machine-readable core profile covers only the billing response envelope, meter-event request, and public receipt shapes already present in the candidate source code. It does not certify a deployment or change billing behavior. It does not prove every metered call receives a receipt or claim conformance for the pricing, verification, dispute, trust-score, or discovery sections below.
Machine-readable core artifacts
and fictional fixture and fictional fixture and fictional fixtureFixtures contain fictional identifiers and sanitized payloads only. The receipt
fixture is signed with the public test-only key
noui-spec-fixture-secret-v1; that key is intentionally non-secret and MUST
NOT be used outside deterministic conformance tests.
The implemented subset is documented in SPEC.md. This revision carries forward draft #1 as documentation and fixtures on main after #14; it adds no runtime validation, dependencies, migrations, or billing behavior.
Known source-alignment deltas
NB-01 records these current-code mismatches instead of silently redefining or repairing runtime behavior:
| Surface | Current source truth | NB-01 handling |
|---|
| Cost units | Meter, pricing, stats, and balance use cents × 10,000 after #14. | Receipt fixture uses 1 cent → 10,000 microcents → $0.01. Existing stored receipts are not rescaled or re-signed. |
|---|---|---|
| Proxy tool metadata | The successful proxy route emits meta.tool; the SDK ProxyResult type names that field meta.tool_name. | Billing-envelope schema follows the route. |
| Proxy display cost | The successful proxy route returns a formatted meta.cost string; the SDK ProxyResult.meta omits meta.cost. | Billing-envelope schema follows the route and requires meta.cost; this does not imply SDK compatibility. |
| Proxy invocation identifier | The SDK declares an SDK-only optional meta.invocation_id; the successful proxy route does not return it. | Billing-envelope schema follows the route and omits meta.invocation_id. |
| Request validation | Main uses truthiness defaults and TypeScript casts, not runtime schema validation; unknown request fields are ignored. | The closed meter schema describes the intended client profile, not every payload accepted by the route. No runtime enforcement is introduced. |
| Meter request | The route accepts tool_id/tool_name, agent_id, status, duration_ms, input_tokens, output_tokens, and metadata; the SDK MeterPayload instead exposes tokens_used, success, and consumer_id. | Meter-event schema follows the route. |
| Meter response | MeterAPI.record() declares { recorded, invocation_id }; the meter route returns { metered, tool_id, agent_id, cost_microcents, cost_cents, status, timestamp, receipt }. | NB-01 records the mismatch; its meter-event schema covers the request only and makes no response-compatibility claim. |
| Receipt content fields | The meter route stores token-count strings in internal nullable columns named input_hash and output_hash; the public receipt verifier returns neither field. | Public-receipt schema follows the verifier response and makes no content-hash claim. |
| Receipt lifecycle | The meter route signs receipts, but logs and continues when receipt persistence fails. The proxy route records usage without generating a signed receipt. | Schemas define shapes only; NB-01 does not certify persistence or claim every proxy call has a receipt. |
0. Billing Response Envelope
The billing proxy currently returns a JSON envelope containing the tool result and billing metadata. The machine-readable schema follows the route's current field names and changes neither the route nor SDK.
{
"result": {
"content": [
{
"type": "text",
"text": "fictional fixture response"
}
]
},
"meta": {
"tool": "fixture.echo",
"provider": "Fixture Provider",
"cost_cents": 1,
"cost": "$0.0100",
"latency_ms": 12,
"remaining_balance_cents": 499
}
}
Required fields are result and meta. The current meta object contains
tool, provider, cost_cents, cost, latency_ms, and
remaining_balance_cents.
Machine-readable source:
billing-envelope.schema.json.
1. Meter Event Request Schema
A meter-event request records a single tool invocation through billing-aware middleware. The provider, price, receipt identifier, and server timestamp are resolved or generated by the meter route; clients do not supply them in this request shape.
{
"tool_name": "fixture.echo",
"agent_id": "agent_fixture_001",
"status": "success",
"duration_ms": 12,
"input_tokens": 3,
"output_tokens": 5,
"metadata": {
"fixture": "fictional-sanitized",
"source": "nb-01"
}
}
Required Fields
tool_idortool_name— at least one must be present
Optional Fields
agent_id— defaults to the authenticated key ownerstatus— one ofsuccess,error,timeout, orrate_limited; defaults tosuccessduration_ms— wall-clock execution timeinput_tokens,output_tokens— token counts for LLM-backed toolsmetadata— arbitrary key-value pairs
meter-event.schema.json.
Cost Precision
Fields ending in_microcents use integer microcents; fields ending in _cents
retain cents. 1 cent = 10,000 microcents. Conversion is
cost_microcents = cost_cents * 10_000; display USD as
dollars = cost_microcents / 1_000_000. Display strings are not signed amounts.
The proxy displays zero as Free and nonzero cents as
"$" + (cost_cents / 100).toFixed(4). The envelope fixture therefore displays
1 cent as $0.0100, and its corresponding receipt signs 10,000 microcents.
$0.05 per call = 50,000 microcents
$0.005 per call = 5,000 microcents
$0.0001 per call = 100 microcents
Failed meter calls record zero microcents. The current meter response still
returns the listed price in cost_cents on failure; do not use that field as
the charged amount. Historical signed receipts retain their original amounts.
2. Receipt Schema
Every metered invocation SHOULD generate a signed receipt. Receipts provide tamper-evident signed billing fields for auditing and dispute resolution; a valid signature does not prove tool execution or settlement.
{
"receipt_id": "rcpt_0123456789abcdef",
"tool_id": "tool_fixture_echo",
"tool_name": "fixture.echo",
"agent_id": "agent_fixture_001",
"provider_id": "provider_fixture_001",
"timestamp": "2026-02-27T12:00:00.000Z",
"duration_ms": 12,
"cost_microcents": 10000,
"status": "success",
"signature": "8019e19b0807a357f6fbafc6d4c1f7b5bc7c94c52c71e71bf00d1a2dc71e4f31",
"created_at": "2026-02-27T12:00:00.000Z"
}
This is the receipt object returned by the legacy stored-receipt endpoint
GET /api/v1/bazaar/receipts/{receipt_id}. Its amount is $0.01. The meter endpoint's creation response also returns a verify_url;
that URL is an envelope field, not part of the public receipt object.
Machine-readable source:
receipt.schema.json.
Receipt ID Format
Receipt IDs MUST use the prefixrcpt_ followed by 16+ hex characters.
Signature
The signature MUST be computed as HMAC-SHA256 over a canonical string:canonical = receipt_id | tool_id | agent_id | provider_id | timestamp | cost_microcents | status
Fields are joined with the pipe character (|), without spaces. The amount
uses its integer decimal representation. Sign the UTF-8 string with HMAC-SHA256
and encode the digest as 64 lowercase hex characters. Do not normalize signed
values. Signed strings must not contain |. Only these seven fields are signed:
tool_name, duration_ms, created_at, hashes, and verify_url are not
authenticated by this signature. The production HMAC key is a server-side
secret that MUST NOT be exposed to clients. HMAC requires the shared secret;
it is not public-key verification.
Verification
Use POST /api/v1/verify with the complete signed receipt, either bare or
wrapped as { "receipt": { ... } }. It needs no API key, performs no database
lookup, and returns only caller-supplied receipt data and a verification outcome:
{receipt, verification:{valid, reason, checked:{canonical, algorithm}, verified_at}}.
The algorithm is HMAC-SHA256; comparison is timing-safe. Invalid envelopes
return HTTP 200 with valid:false; invalid JSON returns HTTP 400. Reasons are
ok, missing_fields, bad_receipt_id, bad_signature_format,
signature_mismatch, and ambiguous_fields. The public verifier requires the
seven signed fields plus signature; it does not require the legacy endpoint's
additional fields in the receipt schema.
The verification page accepts receipt JSON. It does not look up
billing data by receipt ID. GET /api/v1/verify?receipt_id=... returns HTTP 405.
The legacy stored-receipt URL remains a separate endpoint; the meter response
contains only a receipt ID, signature, and legacy URL, not a full signed
envelope (it omits the provider ID needed for independent submission).
The fixture key above is test-only. Its signature is not expected to verify against a deployment with a different signing secret.
Privacy
The profile fixtures contain no raw input or output. The legacy endpoint omits
internal input_hash and output_hash columns, which currently store token-count
strings rather than SHA-256 content digests. Public POST verification echoes
submitted data, so callers should submit only receipt metadata.
3. Pricing Declaration Schema
Providers declare pricing per tool. This enables agents to make cost-aware decisions before invocation.
{
"tool_id": "string",
"tool_name": "string",
"provider_id": "string",
"pricing_model": "per_call | per_token | free",
"price_per_call_microcents": 50000,
"price_per_input_token_microcents": 10,
"price_per_output_token_microcents": 30,
"free_tier": {
"calls_per_month": 100,
"tokens_per_month": 10000
},
"currency": "USD"
}
Pricing Models
- per_call — flat rate per invocation
- per_token — rate per input/output token
- free — no charge (community/open-source tools)
Free Tiers
Providers MAY declare free tiers. Billing systems MUST track free-tier usage per agent per calendar month.4. Verification Levels
Provider verification establishes trust in tool listings. Four levels, from no verification to full code ownership proof:
| Level | Requirements | Badge |
|---|
unverified | Default. Anyone can list. | None |
|---|---|---|
email | Provider confirmed email ownership | ✉️ |
domain | DNS TXT record proves domain control | 🌐 |
code | GitHub/GitLab repo references the listing | 💻 |
Email Verification
Provider has a valid email on record. Auto-verifiable.Domain Verification
Provider adds a DNS TXT record:_mcp-billing-verify.example.com TXT "mcp-billing-verify={provider_id_prefix}-{challenge_token}"
Code Verification
Provider's public repository contains a reference to their billing listing (e.g., in README, package.json, or a.mcp-billing.json file).
5. Dispute Schema
Disputes allow agents or providers to contest charges associated with a receipt.
{
"dispute_id": "disp_a1b2c3d4e5f67890",
"receipt_id": "rcpt_...",
"filed_by": "string (agent_id or provider_id)",
"filed_by_type": "agent | provider",
"reason": "tool_error | overcharge | timeout | quality | other",
"description": "Human-readable description",
"evidence": {},
"status": "filed",
"created_at": "ISO 8601 datetime"
}
Dispute ID Format
Dispute IDs MUST use the prefixdisp_ followed by 16+ hex characters.
Reasons
- tool_error — Tool returned an error but agent was charged
- overcharge — Charge exceeds declared pricing
- timeout — Tool timed out but agent was charged
- quality — Output quality does not match tool description
- other — Catch-all with required description
Status Flow
filed → under_review → resolved_refund | resolved_denied | resolved_credit
- filed — Dispute created
- under_review — Platform is investigating
- resolved_refund — Full refund issued to agent
- resolved_denied — Dispute rejected, charge stands
- resolved_credit — Partial credit or alternative resolution
6. Trust Score Schema
A composite score combining verification, reliability, and dispute history. Enables agents to make trust-aware tool selection.
{
"provider_id": "string",
"trust_score": 87,
"badge": "verified",
"components": {
"verification": 25,
"uptime": 24,
"latency": 20,
"disputes": 18
}
}
Component Weights (100 points total)
| Component | Max | Scoring |
|---|
| Verification | 25 | unverified=0, email=10, domain=20, code=25 |
|---|---|---|
| Uptime | 25 | Based on success rate over 30 days |
| Latency | 25 | Based on p95 latency vs category average |
| Disputes | 25 | Based on dispute rate and resolution history |
Badges
| Badge | Score Range |
|---|
unrated | 0-24 |
|---|---|
basic | 25-49 |
trusted | 50-74 |
verified | 75-100 |
7. Discovery
Billing-capable MCP servers SHOULD advertise their capabilities in /.well-known/agents.json:
{
"billing": {
"type": "mcp-billing-v1",
"spec": "https://noui.bot/specs/mcp-billing-v1",
"pricing_endpoint": "/api/pricing",
"metering_endpoint": "/api/meter",
"receipts_endpoint": "/api/receipts"
},
"trust": {
"verification_endpoint": "/api/providers/verify",
"trust_endpoint": "/api/providers/{id}/trust",
"sla_endpoint": "/api/providers/{id}/sla",
"disputes_endpoint": "/api/disputes"
}
}
8. Conformance
An implementation is MCP Billing v1 conformant if it:
Partial conformance is acceptable. Implementations SHOULD document which sections they support.
NB-01 core-profile conformance
Run npm test from the repository root. The documentation tests check fixture
shapes and lossless JSON round trips, documented dollar conversions, the real
receipt signer with the public test key, and tampering of each signed field.
Existing repository tests cover route conversions and public envelope verification.
These are targeted contract checks, not a general JSON Schema validator or live
conformance certification. The schemas describe a stricter client profile than
current runtime validation. Passing tests does not prove deployment, atomic
receipt persistence, SDK compatibility, or broader six-part conformance.
Appendix A: Why an Open Spec?
The MCP ecosystem needs billing. Multiple providers are building it independently with incompatible schemas. This fragmentation hurts everyone:
- Agents must learn different billing APIs per provider
- Providers can't switch billing platforms without rewriting integrations
- Platforms compete on implementation details instead of value
Appendix B: Candidate Implementation
The Agent Bazaar source at noui.bot is candidate implementation code used to align the NB-01 artifacts. It is not established as a fully conformant live reference implementation: the current proxy path does not generate signed receipts, and the meter path can report success after receipt persistence fails.
- API:
https://noui.bot/api/v1 - SDK:
npm install @forthebots/bazaar-sdk - OpenAPI:
https://noui.bot/api/openapi.json - GitHub:
https://github.com/TombStoneDash/noui-bot
*The specification files are licensed under their adjacent MIT License. That grant does not claim to license the rest of this repository.*