Botsupply
You can create tamper-evident purchase receipts, manage prepaid credit wallets and catalog purchases, and run credit escrow jobs between agents.
Record a human purchase approval on any payment rail and get a public receipt URL plus a one-time edit token.
Attach delivery proof to a receipt, optionally marking it delivered or disputed and flagging over-cap amounts.
Read public receipts and verify their SHA-256 hash chain and HMAC signature.
List catalog SKUs, open a wallet, check balance, buy SKUs with prepaid credits, and start Stripe Checkout top-ups.
Create escrow jobs that hold credits for another agent, then inspect, release, or refund them.
Enables paid wallet credit top-ups through Stripe Checkout, with Stripe webhook integration to apply credits after successful checkout sessions.
BotSupply
Free, rail-agnostic purchase receipts for AI agents. Live at https://botsupply.onrender.com.
record_approval logs what a person approved — merchant, scope, price cap, and rail — as a public tamper-evident receipt link. The record is a SHA-256 hash chain. The latest hash is signed with HMAC-SHA256 (RECEIPT_SIGNING_KEY). GET /v1/receipts/:id/verify recomputes that chain. Verified means the record has not changed since it was created. It does not confirm who approved.
An email contact gets a one-time Confirm link. The public line is Approver confirmed after the person who opens that link clicks Confirm. BotSupply does not send the email. The caller delivers confirm_url. There is no identity check.
pay_allowed is true only after Confirm, or when no approver contact was given and the price cap is strictly under RECEIPT_CONFIRM_THRESHOLD (default 100, in the price cap's currency). record_payment then flags Paid before confirmation and Over approved cap instead of rejecting those payments. attach_proof adds delivery proof. Emails and phones are masked on public pages. A redacted public view can hide more. See below.
BotSupply never holds or moves the purchase money. No wallet is required for a receipt.
Also included: prepaid credit wallets with live Stripe Checkout top-ups, and escrow jobs between agents.
Agent skill: npx skills add iambrettforbes/Botsupply- (see skills/botsupply-receipts/SKILL.md).
10-minute quickstart
MCP endpoint:
https://botsupply.onrender.com/mcpnpx add-mcp 'https://botsupply.onrender.com/mcp'
# or
claude mcp add --transport http botsupply 'https://botsupply.onrender.com/mcp'Install notes: MCP_INSTALL.md. REST: AGENT_INSTALL.md. Demo: DEMO.md.
Record an approval. Keep edit_token. If you passed an email, deliver confirm_url to that person yourself.
curl -s -X POST https://botsupply.onrender.com/v1/receipts \
-H 'content-type: application/json' \
-d '{"approver":"Ada","approver_contact":"ada@example.com","merchant_name":"North Market","scope":"Two bags of coffee","price_cap_amount":"25.00","price_cap_currency":"USD","payment_rail":"stripe_link"}'Poll until pay_allowed is true, then pay on your own rail.
curl -s "https://botsupply.onrender.com/v1/receipts/$RECEIPT_ID"Record what you paid, attach proof, and check the signature.
curl -s -X POST "https://botsupply.onrender.com/v1/receipts/$RECEIPT_ID/payment" \
-H 'content-type: application/json' \
-d '{"edit_token":"…","external_payment_ref":"pi_123","amount":"25.00"}'
curl -s -X POST "https://botsupply.onrender.com/v1/receipts/$RECEIPT_ID/proof" \
-H 'content-type: application/json' \
-d '{"edit_token":"…","type":"order_confirmation","value":"ord_123"}'
curl -s "https://botsupply.onrender.com/v1/receipts/$RECEIPT_ID/verify"The public page is https://botsupply.onrender.com/r/$RECEIPT_ID.
Related MCP server: Netlify MCP Server
MCP tools (15)
Purchase receipts (no wallet, free)
Tool | What it does |
| Write what was reported as approved. The approver name is supplied by the agent. An email contact gets a one-time confirm link returned as |
| Attach delivery proof with the |
| Record a payment the agent already made ( |
| Change |
| Public receipt JSON, including |
| Recompute the hash chain and HMAC. |
Public HTML page: GET /r/:id (Verified or Tampered badge, and a separate Approver unconfirmed / Approver confirmed ✓ / Approver declined line).
Wallets and catalog
Tool | What it does |
| List live SKUs and credit prices. |
| Create a wallet. API key returned once. |
| Prepaid credit balance. |
| Buy one catalog SKU with credits. |
| Live Stripe Checkout top-up (500 to 100000 credits, $5 to $1,000). |
Escrow (prepaid credits)
Tool | What it does |
| Hold credits for another agent. |
| Read a job. |
| Pay the payee. |
| Return the hold to the payer. |
Purchase receipts
An agent records what was reported as approved on any payment rail (stripe_link, card, x402, botsupply_wallet, or another label) and later attaches proof. The approver name is text the agent typed. BotSupply stores that record and a public URL. It does not hold or move the money. No wallet and no API key are required.
The response includes receipt_id (rcpt_ + 24 hex), receipt_url, and edit_token (returned once). When approver_contact is an email, the response also includes confirm_url (returned once) while no email provider is configured. The address itself is not returned.
Approver confirmation
Passing an email as approver_contact (a string, or { "channel": "email", "address": "ada@example.com" }) issues one confirm link, /c/:token. The token is unguessable, stored only as a SHA-256 hash, expires (default 24 hours, RECEIPT_CONFIRM_TTL_SECONDS), and works once. sms is reserved and rejected until a sender exists. A non-email string is stored only as a hash and does not issue a link.
The approver opens the link and sees the scope, price cap, merchant, and requesting agent, with Confirm and Decline buttons. That page shows the stored text, including when the public receipt is redacted, so the person can see what they are confirming. Opening the link does not decide anything. The buttons POST. Confirm and decline are hash-chain events. The public state is then:
Approver unconfirmed — default, including receipts created before this step
Approver confirmed ✓ — the person with access to that contact clicked Confirm, with time and channel
Approver declined — that person clicked Decline
Confirmed does not mean BotSupply checked a legal identity, and it does not mean the agent-reported name was proven. The Verified badge still only means the hash chain and HMAC match.
Confirm before pay
pay_allowed is the contract the paying agent follows. It is true only when approver_confirmation.status is confirmed, or when no approver_contact was given and the price cap is strictly under RECEIPT_CONFIRM_THRESHOLD (default 100). At or above that threshold, record_approval without an email contact still succeeds, the receipt shows "No approver contact; confirmation required above threshold", and pay_allowed stays false.
Poll get_receipt and pay only when pay_allowed is true. POST /v1/receipts/:id/payment (record_payment) records what was paid. It requires edit_token, external_payment_ref, and amount. paid_at is optional and defaults to now. The call appends a signed payment_recorded event. It sets paid_before_confirmation when the payment time is before the confirm event, or when a contact was set and the receipt was never confirmed. It sets over_cap when amount exceeds the price cap. Those payments are stored and flagged. They are not rejected.
On a later read, external_payment_ref is the latest recorded payment's ref, taken from receipt_payments at read time. The stored receipt column is not rewritten, so existing hashes still verify. When no payment has been recorded, the approval-time ref is shown (or none). Top-level paid_before_confirmation and over_cap are true when any recorded payment has that flag, and false otherwise. They are also derived at read time. The response from attaching a proof still reports that proof's own over_cap at the top level. The next get_receipt uses the payment-derived flags. Each proof keeps its own over_cap.
The public page lists Approved by agent report, Approver confirmed, and Paid, with times, then a green "Confirmed before payment" line or a red "Paid before confirmation" / "Over approved cap" line. The Price cap section shows the same latest payment ref.
In the default full view, email addresses and phone numbers in the approver name, scope, merchant name, or proof value are masked (for example i***@gmail.com). Stored rows and hash-chain payloads are unchanged.
Redacted public view
public_view is full (default) or redacted. It is stored on the receipt outside the hash snapshot. Changing it does not change the content hash, the signature, or updated_at. Pass it on record_approval, or later:
curl -s -X POST "https://botsupply.onrender.com/v1/receipts/$RECEIPT_ID/visibility" \
-H 'content-type: application/json' \
-d '{"edit_token":"…","public_view":"redacted","public_scope":"Two bags of coffee"}'MCP: set_receipt_visibility. Omit public_scope to leave the stored public scope unchanged.
While redacted, the public JSON and /r/:id show:
Approver as initials only (
Jane DoebecomesJ.D.)Agent name as
Agent(the agent id is omitted)No email or phone, not even masked
Payment refs and proof values as
on fileplus the last 4 characters that remain after card phrases such asending 1234are removedMerchant name and URL kept (emails and phones stripped from the name)
Scope kept, with those same contact and card phrases removed, unless
public_scopeis set, which replaces the public scopeAmounts, price cap, timeline, statuses, the confirmed and paid lines, and verify results stay visible
The receipt page adds a quiet note: "Some details hidden by the purchaser."
verify still checks the full stored row. valid does not depend on the display setting.
Optional confirmation_webhook_url (public https only) receives { "receipt_id", "approver_confirmation" } after the click. Delivery is best-effort. Poll get_receipt if it does not arrive.
Email sending is behind ApprovalNotifier. No email provider is included. Leave RECEIPT_EMAIL_PROVIDER unset (or none). The confirm link is returned as confirm_url with confirm_delivery: "caller". A future provider would read RECEIPT_EMAIL_FROM and RECEIPT_EMAIL_API_KEY. Those are unused today.
Confirm attempts are rate-limited (30/min/IP), separate from the approval limit (30/min/IP). The contact address is stored only as a SHA-256 hash. A masked form appears on a full receipt only after Confirm or Decline. Each hash-chain change is SHA-256. The latest hash is HMAC-SHA256. Set RECEIPT_SIGNING_KEY to a long random secret. If it is unset, an ephemeral key is generated and signatures will not verify after a restart.
Startup adds nullable confirmation columns and receipt_payments. It also adds public_view (default full) and public_scope. Older rows keep their signatures. The confirmation object is omitted from the hash snapshot until a decision exists, payments is omitted until a payment is recorded, and public_view is never in the snapshot.
Wallets and credits
1 credit = $0.01 USD. Agents open a wallet, top up with live Stripe Checkout, and buy JSON products from the catalog.
POST /v1/wallets/:id/topup is a free development top-up only when STRIPE_SECRET_KEY is unset. When STRIPE_SECRET_KEY is set, that route returns 403 and agents pay with Checkout. Paid top-ups are 500 to 100000 credits ($5 to $1,000).
Catalog
SKU | Kind | Credits | Intended retail |
| pack | 50 | $0.50 |
| pack | 20 | $0.20 |
| recipe | 100 | $1.00 |
pack.competitor-snapshot is a Cobble Hill casual-dining competitive set. pack.venue-hours is weekly hours and reservation policy for those venues. recipe.book-table is an executable booking recipe the agent runs itself (buying it does not place a reservation). Payloads are delivered on purchase.
Escrow jobs
One agent can hold credits for another. POST /v1/jobs debits the payer and marks the job held. Release pays the payee. Refund returns the hold. Writes run in one database transaction. ESCROW_FEE_BPS defaults to 0.
curl -s -X POST https://botsupply.onrender.com/v1/jobs \
-H "authorization: Bearer $PAYER_API_KEY" \
-H 'content-type: application/json' \
-d '{"payee_wallet_id":"wal_…","amount_credits":100,"description":"Deliver the brief","idempotency_key":"job-1"}'Run locally
Requires Node.js 22+.
npm install
npm test
npm run build
npm startThe process binds 0.0.0.0 and listens on PORT, default 4317.
curl -s http://127.0.0.1:4317/healthOpen http://127.0.0.1:4317 for the price sheet and curl examples. npm run dev reloads with tsx.
Data
When DATABASE_URL is set, wallets, purchases, checkout sessions, credited Checkout sessions, escrow jobs, and receipts are stored in Postgres. Each row is tagged dev, test, or live from the Stripe secret key prefix (sk_test_ / rk_test_ → test, sk_live_ / rk_live_ → live, unset → dev). Lookups include that tag, so each mode reads only its own rows.
When DATABASE_URL is unset, the same records stay in a SQLite file (SQLITE_PATH, or /data/botsupply.sqlite if writable, else ./data/botsupply.sqlite).
The hosted service uses Postgres. With a live Stripe key, /health reports "storage":"postgres","mode":"live".
API (summary)
Method | Path | Notes |
|
| Record what was reported as approved (no auth). Email contact also issues a confirm link. Optional |
|
| Attach proof ( |
|
| Record a payment the agent already made ( |
|
| Set |
|
| Public JSON, including |
|
| Integrity check and confirmation state |
|
| Public HTML receipt |
|
| Confirm page. Does not decide. Shows the stored text. |
|
| One-time confirm |
|
| One-time decline |
|
| Open wallet |
|
| Stripe top-up (auth) |
|
| List SKUs |
|
| Balance (auth) |
|
| Buy SKU (auth) |
|
| Create escrow hold (auth) |
|
| Get job (auth) |
|
| Release (auth) |
|
| Refund (auth) |
|
| Streamable HTTP MCP |
|
|
|
Stripe on Render
Key | Value |
| Live key |
|
|
|
|
| Long random secret for receipt HMAC |
| Confirm link lifetime. Default 86400 (24 hours). |
| Price-cap units at or above which a receipt with no email approver contact has |
| Leave unset. No email provider ships in this build. The caller delivers |
Webhook endpoint: https://botsupply.onrender.com/v1/stripe/webhook.
Tests
npm testCovers wallets, catalog purchases, Stripe credit application (fake client), escrow, and purchase receipts (create, proof, verify, tamper, confirm, payment flags, derived payment ref, and the redacted public view).
Deploy
Docker, Render, and Fly.io: DEPLOY.md.
License
Available Tools
13 toolsattach_proofAttach delivery proofA
Attach proof of delivery to a receipt. Requires the edit_token from record_approval. Moves approved to delivered, or to disputed when status is disputed. over_cap is true when actual_amount exceeds the price cap. Does not move money. Same as POST /v1/receipts/:id/proof.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Proof kind. Examples: order_confirmation, tracking, url, hash. | |
| value | Yes | The proof itself: confirmation id, tracking number, URL, or hash. | |
| status | No | Omit to mark an approved receipt delivered. Pass disputed to dispute it. | |
| edit_token | Yes | Secret returned once by record_approval. Required to attach proof. | |
| receipt_id | Yes | Receipt id from record_approval (rcpt_…). | |
| actual_amount | No | Amount actually charged. over_cap is true when this is above the price cap. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the state machine transitions, the auth dependency on record_approval's edit_token, the meaning of the over_cap flag, and an explicit negative guarantee ('Does not move money'). Annotations only say non-readonly/non-idempotent; the description supplies the operational consequences.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five short sentences, each load-bearing: purpose, prerequisite, state effects, semantic flag, and negative guarantee, ending with the REST endpoint. Front-loaded and free of repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers prerequisites, side effects, and at least one response signal (over_cap). It leaves the success payload shape and any post-attach follow-up (e.g. release_job) unaddressed, which keeps it just short of complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds meaning the schema doesn't: where edit_token and receipt_id come from, and that over_cap reflects actual_amount exceeding the price cap. It doesn't add syntax detail for type/value beyond the examples already in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Attach proof of delivery to a receipt') with the exact state transitions the call causes (approved→delivered, disputed→disputed). An agent can distinguish this from record_approval, verify_receipt, and release_job without reading any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States the prerequisite clearly ('Requires the edit_token from record_approval') and the condition for the disputed branch. It stops short of naming when NOT to use it or pointing at an alternative tool, so it gives strong context but no exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_checkoutCreate checkoutA
Start a Stripe Checkout credit top-up. Same as POST /v1/wallets/:id/checkout. Returns the checkout url (open that URL; it keeps Stripe's hosted-page fragment). credits is an integer from 500 to 100000 ($5 minimum). Credits are applied only after Stripe reports the session paid. Returns the API error when Stripe is not configured.
| Name | Required | Description | Default |
|---|---|---|---|
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. | |
| credits | Yes | Credits to buy. 1 credit = $0.01 USD. Minimum 500 credits ($5). Same limits as POST /v1/wallets/:id/checkout. | |
| wallet_id | No | Wallet to credit. Defaults to the wallet that owns the API key. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation/read-write profile, and the description adds genuinely useful behavior: it returns a checkout URL that must be opened, credits are only applied after Stripe reports the session paid, and an API error is returned when Stripe is not configured. That async-settlement and failure-mode context goes beyond what the annotations convey, though it stops short of covering repeat invocations or session expiry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the underlying route, and the operational notes (open the URL, credits applied post-payment) each earn their space. There is mild redundancy in restating the credits range already present in the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly compensates by explaining the return value (the checkout URL) and its handling. It also covers the Stripe-not-configured error path and the delayed credit application, leaving only minor gaps around wallet prerequisites and idempotency on repeat calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters are already documented, including the 500–100000 range and the 1 credit = $0.01 conversion. The description largely restates the credits bounds and adds little syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource: starting a Stripe Checkout credit top-up, and anchors it to the underlying POST /v1/wallets/:id/checkout route so the agent knows exactly what is invoked. It does not, however, distinguish itself from the sibling `purchase`, which an agent could plausibly confuse with this tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the agent can infer this is the way to buy credits via Stripe's hosted page, but there is no explicit when-to-use statement and no guidance on choosing between this and the sibling `purchase`. No prerequisites (e.g., needing a valid wallet) or exclusions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_jobCreate escrow jobAIdempotent
Hold credits in escrow for a job another agent will do; release when the work is delivered, refund if not. Debits amount_credits from the authenticated payer wallet and marks the job held. payee_wallet_id receives the credits on release. Rejects amount_credits below 1, a payer equal to the payee, a missing or other-mode payee wallet, and insufficient balance. idempotency_key makes a retry return the same job without debiting twice. Same as POST /v1/jobs.
| Name | Required | Description | Default |
|---|---|---|---|
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. | |
| description | Yes | What the payee is being paid to do. | |
| amount_credits | Yes | Credits to debit from the authenticated payer wallet and hold until release or refund. | |
| idempotency_key | Yes | Caller-chosen key scoped to the payer. A retry with the same key and the same parameters returns the original job and does not debit again. | |
| payee_wallet_id | Yes | Wallet that receives the credits when the payer releases the job. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: it names the exact funding source (authenticated payer wallet), enumerates the rejection conditions (amount_credits < 1, payer == payee, missing/other-mode payee wallet, insufficient balance), and spells out the idempotency contract that a retry returns the same job without double-debiting. The annotations already cover readOnly=false and idempotent=true, so this is useful amplification rather than the sole disclosure, and the one remaining gap is the response shape.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tightly packed sentences with the escrow purpose front-loaded, followed by debit mechanics, failure conditions, and idempotency. Every clause carries information and nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers funding, validation failures, idempotency, and the API equivalent, which is most of what an agent needs to invoke it safely. It never says what the created job object returns (job id, status field), which is the one item an agent must infer from 'returns the same job', so it is strong but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so every parameter is already documented in the schema, and the description largely restates that content (amount_credits minimum, idempotency_key retry behavior, payee receiving credits on release). It adds the cross-field rule that payer must differ from payee, but that is a small increment over an already complete schema, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb and resource ('Hold credits in escrow for a job') and pins down the exact lifecycle moment, which cleanly separates it from the sibling release_job and refund_job tools that act on an existing job. The closing 'Same as POST /v1/jobs' anchors it to a known API surface, so an agent can place it without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for when this tool applies: the escrow-hold step whose credits are later released or refunded, which implicitly routes the agent to release_job/refund_job for those follow-ups. It stops short of any explicit when-not or named alternative (e.g. create_checkout or purchase), so the guidance is contextual rather than directive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_balanceGet balanceARead-onlyIdempotent
Return the authenticated wallet id and prepaid credit balance. Same as GET /v1/balance. Does not return the API key.
| Name | Required | Description | Default |
|---|---|---|---|
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent and non-destructive behavior, so the safety profile is covered. The description adds genuinely new behavioral context: it maps to GET /v1/balance and explicitly states the API key is NOT returned, which is security-relevant output information absent from the annotations and schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short, front-loaded sentences with zero filler. The primary capability is stated first, followed by the REST equivalent and the explicit exclusion.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only wallet query with rich annotations and full parameter documentation, the description supplies what is missing (returned fields, REST mapping, no secret leakage). Only the absence of any error/authentication-failure behavior keeps this from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: the single api_key parameter is fully documented, including the Bearer fallback and the BOTSUPPLY_API_KEY env var. The description adds nothing about parameters, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource (returns the wallet id and prepaid credit balance), which clearly distinguishes it from siblings like create_checkout or purchase. It stops short of explicitly contrasting itself with any sibling tool, so it lands at 4 rather than 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use or when-not-to-use guidance and no alternatives are named. The agent can infer this is the tool for checking available credit, but nothing tells it how balance checking relates to purchase or open_wallet flows.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_jobGet escrow jobARead-onlyIdempotent
Return an escrow job's status (held, released, or refunded), the held amount, any release fee, and the payer and payee wallets. The caller must be the payer or the payee. A job from another Stripe mode is not visible. Same as GET /v1/jobs/:id.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Escrow job id returned by create_job (job_…). | |
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavioral context beyond the annotations: an authorization requirement (caller must be payer or payee) and a cross-mode visibility quirk. It still doesn't say what an errored or not-found call looks like, but the additions are substantive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the return payload, then access rules, then the REST endpoint mapping. Every sentence earns its place and none of it repeats structured fields verbatim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema present, the description must describe return values and it does so explicitly. Access constraints and mode scoping are covered, and the annotations handle the idempotency/read-only profile, so an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the job_… id format and the api_key fallback chain, so the schema already carries the parameter burden. The description adds no syntax or format detail beyond what the schema states, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return an escrow job's status') and enumerates the exact payload the agent will receive (status, held amount, release fee, payer/payee wallets). The read-only framing is clearly distinguishable from the sibling mutators create_job, release_job, and refund_job.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete eligibility precondition ('The caller must be the payer or the payee') and an exclusion ('A job from another Stripe mode is not visible'), which tells the agent when this call will fail or return nothing. It does not name an alternative tool for cases that fall outside those conditions, so it stops short of full when/when-not/alternatives guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_receiptGet purchase receiptARead-onlyIdempotent
Read a public purchase receipt: approval, scope, price cap, merchant, proofs, and content hash. No API key. The approver contact and the edit token are not included. Same as GET /v1/receipts/:id.
| Name | Required | Description | Default |
|---|---|---|---|
| receipt_id | Yes | Public receipt id (rcpt_…). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), but the description adds real value beyond them: it declares the authentication requirement ('No API key'), discloses what is deliberately withheld ('approver contact and the edit token are not included'), and maps to the underlying REST route. It stops short of 5 only because no rate-limit or pagination behavior is mentioned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the returned fields, then access requirements, then exclusions. Every sentence carries distinct information with no padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description correctly compensates by enumerating the returned content (approval, scope, price cap, merchant, proofs, content hash) and by calling out the sensitive fields that are omitted. Nothing an agent needs to call and interpret this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single receipt_id parameter is already documented with its rcpt_ prefix format in the schema. The description adds no syntax or constraint information beyond that, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read a public purchase receipt') and enumerates the payload fields an agent will get back, which is more than a restatement of the name. It does not differentiate itself from the sibling verify_receipt or get_job, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'No API key' implies it can be called without authentication, which is useful contextual guidance. However, there is no explicit statement of when to use this rather than verify_receipt, which is the obvious adjacent sibling, so usage remains implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_catalogList catalogARead-onlyIdempotent
List live BotSupply SKUs, credit prices, short descriptions, and what a purchase does not include. Payloads stay behind purchase. recipe.book-table, when listed, is recipe documentation only and does not place a reservation.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and non-open-world, so the safety profile is covered. The description adds genuinely new behavior context: only live SKUs are listed, payloads are withheld until purchase, and recipe.book-table entries are docs that do not trigger a reservation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the returned fields in one sentence, then adds two short qualifiers about payloads and recipe.book-table. Every sentence earns its place, though the phrase 'what a purchase does not include' is slightly abstract.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema and no parameters, the description carries the burden of describing what comes back, and it does so (SKUs, prices, descriptions, exclusions). An agent can invoke this correctly, though it never states format or pagination.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to clarify; the 4 baseline applies. The description instead spends its words on return content, which is appropriate here.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (live BotSupply SKUs) plus the fields surfaced: credit prices, short descriptions, and purchase exclusions. It also differentiates itself from the sibling purchase tool by noting payloads are withheld and that recipe.book-table is documentation, not a reservation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'Payloads stay behind purchase' hints that purchase is the route to payloads, and the recipe note implies this is a read-only reference. There is no explicit 'use this vs. purchase/create_checkout' routing statement or precondition guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
open_walletOpen walletA
Create a wallet and return wallet_id plus api_key once, with balance_credits 0. Same as POST /v1/wallets. This does not look up an existing wallet. Keep the api_key; later tools need it as Authorization: Bearer or as api_key.
| Name | Required | Description | Default |
|---|---|---|---|
| label | No | Optional label, 1 to 80 characters. Same field as POST /v1/wallets. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the safety profile (readOnly=false, destructive=false, idempotent=false, openWorld=false), and the description adds genuinely operational context beyond them: the api_key is returned only once, it must be retained, and it is consumed by later calls as a Bearer token. That once-only credential disclosure is exactly the kind of behavioral trait annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and the returned artifacts, then the negative scope, then the credential-handling requirement. Every clause carries non-redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema present, the description carries the return-value burden itself and does so by naming wallet_id, api_key, and balance_credits, plus how the api_key is subsequently used. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single optional 'label' parameter is fully documented in the schema, including its 1-80 character bound and its equivalence to POST /v1/wallets. The description adds no parameter-level detail, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Create a wallet") plus the exact return payload (wallet_id, api_key, balance_credits 0). It also negates a nearby misconception with "This does not look up an existing wallet," so an agent can tell it apart from any retrieval-style call and from siblings like get_balance or create_checkout.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-not guidance ("does not look up an existing wallet") and forward-looking usage ("later tools need it as Authorization: Bearer or as api_key"). It stops short of naming a concrete alternative sibling for wallet lookup, but no such sibling exists in the listed set, so the guidance is contextually sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
purchasePurchaseA
Buy one live catalog SKU with prepaid credits. Sends { sku } to POST /v1/purchase and returns that JSON, including the pack or recipe payload. Does not place a reservation. recipe.book-table is documentation the buying agent runs itself. An unknown SKU is rejected. Insufficient balance returns an error and does not deduct credits.
| Name | Required | Description | Default |
|---|---|---|---|
| sku | Yes | Live catalog SKU. The field name is sku, not sku_id. | |
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, non-idempotent, non-destructive, closed-world, so the bar is lower. The description still adds real value: the exact request shape and endpoint, the no-reservation guarantee, unknown-SKU rejection, and that an insufficient balance fails without deducting credits — all non-obvious failure semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five short sentences, front-loaded with the core action and credit implication, then progressively narrower caveats. Each sentence carries distinct information — mechanism, endpoint, return, exclusion, error behavior — with no repetition of the title or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description covers the return ('returns that JSON, including the pack or recipe payload') and the auth story is handled in the schema, so an agent has enough to call it. It stops short of stating retry/idempotency consequences of a failed or repeated purchase, which is the one remaining gap for a spend-credits operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so sku and api_key are already fully documented, including the sku-vs-sku_id warning and the BOTSUPPLY_API_KEY fallback. The description only restates that sku is the sent body field, adding no format or constraint detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (buy) and resource (one live catalog SKU) with the exact credit mechanism and endpoint (POST /v1/purchase). The scope phrase 'one live catalog SKU' cleanly separates it from list_catalog, create_checkout, and get_balance without needing to open any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It rules out adjacent behavior ('Does not place a reservation') and clarifies that recipe.book-table is documentation the caller runs itself, which prevents a mistaken tool call. However it never states when to choose this over siblings like create_checkout, so the when-to-use decision is only implied by the word 'buy'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
record_approvalRecord purchase approvalA
Record a human's approval of a purchase on any payment rail. BotSupply does not hold or move the money. Returns receipt_id, a public receipt_url, and an edit_token shown once. No wallet or API key. Rate limited per IP. Same as POST /v1/receipts.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | Yes | What the human approved, in plain text. | |
| agent_id | No | Optional id of the agent that will pay. Not a BotSupply API key. | |
| approver | Yes | Display name or handle of the human who approved the purchase. | |
| agent_name | No | Optional display name of the paying agent. | |
| merchant_url | No | Optional http or https URL for the merchant. | |
| payment_rail | Yes | How the agent will pay. Examples: stripe_link, card, x402, botsupply_wallet. | |
| merchant_name | Yes | Merchant or seller name. | |
| approver_contact | No | Optional email or phone. Stored only as a hash and never shown on the receipt. | |
| price_cap_amount | Yes | Maximum amount approved. A positive decimal, for example 25 or "19.95". | |
| price_cap_currency | Yes | Currency code, 3 to 10 letters, for example USD or USDC. | |
| external_payment_ref | No | Optional id from the payment rail. BotSupply does not look it up. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (not read-only, not destructive, not idempotent). The description goes well beyond: it clarifies no custody of funds, that edit_token is shown once (irrecoverable), no wallet/API key needed, and per-IP rate limiting. These are exactly the behavioral facts an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Terse and front-loaded: the core action leads, followed by tight sentences covering custody, returns, auth, and rate limits. No sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description helpfully names the return values (receipt_id, receipt_url, edit_token) and covers auth and rate limits, making it largely self-sufficient. Minor gap only in that it doesn't tie the tool to its sibling alternatives.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all 11 parameters are already documented in the schema. The description adds no parameter-level meaning beyond the structured fields, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Record') and resource ('a human's approval of a purchase') with the scope ('on any payment rail'), so the agent knows exactly what the tool does. It does not explicitly contrast with receipt-related siblings like get_receipt or verify_receipt, but the core action is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (to log a human's purchase approval) but gives no explicit when-not or alternative selection guidance. It never routes the agent to a sibling such as create_checkout or purchase, leaving the choice to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
refund_jobRefund escrow jobA
Return held escrow credits to the payer when the work is not delivered or the job is cancelled. The payer or the payee can refund, and only while the job is held. The full hold goes back to the payer; no platform fee is taken. Refunding twice, or refunding after release, is rejected and does not move credits again. Same as POST /v1/jobs/:id/refund.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Escrow job id returned by create_job (job_…). | |
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing the money movement (full hold returns to payer, no platform fee taken), the authorization model (payer or payee), and the rejection behavior on repeat or post-release calls. It also maps the tool to its REST equivalent (POST /v1/jobs/:id/refund). The non-idempotent-but-guarded behavior described is consistent with idempotentHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five tight sentences, front-loaded with the core action and its condition, then authorization, then the credit outcome, then the error guards. Every sentence carries distinct information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description covers the essential return behavior (full hold back to payer, no fee) and error cases, which is close to sufficient. It does not describe the response shape or any resulting job status, a minor gap for a mutation tool with no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters (job_id, api_key) are documented there, including the bsk_ prefix and the BOTSUPPLY_API_KEY fallback. The description adds no parameter-level detail beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return held escrow credits to the payer') plus the triggering conditions (work not delivered, job cancelled). It implicitly distinguishes itself from the sibling release_job by explaining that 'refunding after release is rejected', so an agent can route without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear preconditions: only while the job is held, and either payer or payee may invoke it. It also names the failure cases (double refund, refund after release) that should steer an agent away. It never explicitly names release_job as the alternative path, so it stops just short of full when/when-not/alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
release_jobRelease escrow jobA
Release held escrow credits to the payee when the work is delivered. Only the payer can release, and only while the job is held. ESCROW_FEE_BPS (default 0) is withheld on release, recorded on the job, and credited to nobody; the payee receives amount_credits minus that fee. Releasing twice, or releasing after a refund, is rejected and does not move credits again. Same as POST /v1/jobs/:id/release.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | Escrow job id returned by create_job (job_…). | |
| api_key | No | Wallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say readOnlyHint=false, idempotentHint=false, destructiveHint=false. The description goes well beyond that: caller authorization (payer only), lifecycle precondition (job must be held), fee withholding semantics (ESCROW_FEE_BPS recorded on job, credited to nobody), and duplicate/after-refund rejection behavior with no credit movement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then authorization, then fee mechanics, then failure modes, then the REST mapping. Every sentence carries a distinct fact and nothing is repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation tool with no output schema, the description covers permissions, preconditions, credit math, idempotency, and error outcomes — everything an agent needs to invoke it correctly and predict the effect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters are documented there (job_id format, api_key fallback behavior). The description adds no parameter-level detail beyond incidental mentions of amount_credits and the ESCROW_FEE_BPS config value, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (release held escrow credits to the payee) plus the triggering condition (work delivered). It is clearly separable from siblings like refund_job and get_job without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when/when-not conditions: only the payer may release, only while the job is held, and release after a refund or a second release is rejected. It stops short of explicitly naming refund_job as the alternative path, so it is strong context rather than full routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_receiptVerify purchase receiptARead-onlyIdempotent
Recompute the receipt hash chain and HMAC signature. valid is true when the stored receipt matches the chain and the server signature. valid is false when a row was altered. Same as GET /v1/receipts/:id/verify.
| Name | Required | Description | Default |
|---|---|---|---|
| receipt_id | Yes | Public receipt id (rcpt_…). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds genuinely new behavioral content: it explains the mechanism (hash chain plus HMAC recomputation) and the exact semantics of the valid flag in both the success and tampering cases — valuable since no output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the operation before the result semantics. No filler, no restating of the name or title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly documents the meaning of the returned valid flag in both branches, which is the key missing structured information. It omits error behavior (e.g., unknown receipt id) and authentication requirements, which is a minor gap for a read-only verification tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and there is a single parameter whose format (rcpt_…) is documented in the schema. The description adds no further parameter detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Recompute the receipt hash chain and HMAC signature.' This clearly describes an integrity-verification operation rather than a retrieval, so an agent can distinguish it from get_receipt. It does not explicitly contrast itself with the sibling, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the tool for checking whether a receipt has been tampered with. There is no explicit when-to-use-vs-get_receipt guidance, nor any statement of prerequisites such as the receipt needing to exist. The 'same as GET /v1/receipts/:id/verify' mapping is the only routing hint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
9 tool updates
v1.1.0- Added
attach_proof - Changed
create_checkout2 fields changed- changed
Input schema / properties / credits / descriptionPrevious value: -"Credits to buy. 1 credit = $0.01 USD. Same limits as POST /v1/wallets/:id/checkout."New value: +"Credits to buy. 1 credit = $0.01 USD. Minimum 500 credits ($5). Same limits as POST /v1/wallets/:id/checkout." - changed
Input schema / properties / credits / minimumPrevious value: -100New value: +500
- Added
create_job - Added
get_job - Added
get_receipt - Added
record_approval - Added
refund_job - Added
release_job - Added
verify_receipt
5 tool updates
v1.0.0- First observed
create_checkout - First observed
get_balance - First observed
list_catalog - First observed
open_wallet - First observed
purchase
TDQS
Scored across 13 tools
Each tool targets a distinct resource and action: jobs (get/create/release/refund), receipts (record/attach/get/verify), wallet/credits (open/checkout/balance), and catalog/purchase. The detailed descriptions clearly separate overlapping concepts like purchase vs. record_approval, and get vs. verify for receipts.
Almost all tools follow a consistent snake_case verb_noun pattern (get_job, list_catalog, create_job, release_job, etc.). Minor deviations exist: 'purchase' is a bare verb without a noun, and 'open_wallet' uses 'open' rather than 'create' for wallet creation, but the set remains predictable.
13 tools is well within the ideal 3–15 range for this payments/escrow/receipts platform. Every tool maps to a distinct endpoint or operation, and none appear redundant or excessive for the stated domain.
Core CRUD-like lifecycles are covered: wallets (open/balance/top-up), catalog (list), purchases (purchase), jobs (create/get/release/refund), and receipts (record/proof/get/verify). Minor gaps include no list operations for jobs or receipts, which could make it harder for agents to discover or manage multiple records, but single-item workflows are fully supported.
Maintenance
Related MCP Connectors
Related MCP Servers
- MIT
- AlicenseNot gradedqualityNot gradedmaintenanceThis is an MCP server that can be used with Netlify6-
- MIT
- AlicenseNot gradedqualityBmaintenanceOfficial MCP Server for Buildkite.56MIT