Skip to main content
Glama

BotSupply

iambrettforbes/Botsupply- MCP server License: MIT

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/mcp
npx 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

record_approval

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 confirm_url for the caller to deliver. Optional public_view (full or redacted) and public_scope. Returns receipt_id, public receipt_url, and a one-time edit_token.

attach_proof

Attach delivery proof with the edit_token.

record_payment

Record a payment the agent already made (edit_token). Appends payment_recorded. Flags paid_before_confirmation and over_cap instead of rejecting them.

set_receipt_visibility

Change public_view later with the edit_token. Optional public_scope. Does not change the hash.

get_receipt

Public receipt JSON, including approver_confirmation, pay_allowed, and public_view. Pay only when pay_allowed is true.

verify_receipt

Recompute the hash chain and HMAC. valid means the record has not changed. It does not confirm who approved.

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_catalog

List live SKUs and credit prices.

open_wallet

Create a wallet. API key returned once.

get_balance

Prepaid credit balance.

purchase

Buy one catalog SKU with credits.

create_checkout

Live Stripe Checkout top-up (500 to 100000 credits, $5 to $1,000).

Escrow (prepaid credits)

Tool

What it does

create_job

Hold credits for another agent.

get_job

Read a job.

release_job

Pay the payee.

refund_job

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 Doe becomes J.D.)

  • Agent name as Agent (the agent id is omitted)

  • No email or phone, not even masked

  • Payment refs and proof values as on file plus the last 4 characters that remain after card phrases such as ending 1234 are removed

  • Merchant name and URL kept (emails and phones stripped from the name)

  • Scope kept, with those same contact and card phrases removed, unless public_scope is set, which replaces the public scope

  • Amounts, 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.competitor-snapshot

pack

50

$0.50

pack.venue-hours

pack

20

$0.20

recipe.book-table

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 start

The process binds 0.0.0.0 and listens on PORT, default 4317.

curl -s http://127.0.0.1:4317/health

Open 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

POST

/v1/receipts

Record what was reported as approved (no auth). Email contact also issues a confirm link. Optional public_view and public_scope.

POST

/v1/receipts/:id/proof

Attach proof (edit_token)

POST

/v1/receipts/:id/payment

Record a payment the agent already made (edit_token). Flags early and over-cap payments.

POST

/v1/receipts/:id/visibility

Set public_view (edit_token). Does not change the hash.

GET

/v1/receipts/:id

Public JSON, including approver_confirmation, pay_allowed, and public_view

GET

/v1/receipts/:id/verify

Integrity check and confirmation state

GET

/r/:id

Public HTML receipt

GET

/c/:token

Confirm page. Does not decide. Shows the stored text.

POST

/c/:token/confirm

One-time confirm

POST

/c/:token/decline

One-time decline

POST

/v1/wallets

Open wallet

POST

/v1/wallets/:id/checkout

Stripe top-up (auth)

GET

/v1/catalog

List SKUs

GET

/v1/balance

Balance (auth)

POST

/v1/purchase

Buy SKU (auth)

POST

/v1/jobs

Create escrow hold (auth)

GET

/v1/jobs/:id

Get job (auth)

POST

/v1/jobs/:id/release

Release (auth)

POST

/v1/jobs/:id/refund

Refund (auth)

POST

/mcp

Streamable HTTP MCP

GET

/health

{ status, service, storage, mode, database } (503 if the database ping fails)

Stripe on Render

Key

Value

STRIPE_SECRET_KEY

Live key sk_live_… on the hosted service. A test key sk_test_… selects test storage for a self-hosted process. Do not commit it.

STRIPE_WEBHOOK_SECRET

whsec_… for checkout.session.completed

PUBLIC_BASE_URL

https://botsupply.onrender.com

RECEIPT_SIGNING_KEY

Long random secret for receipt HMAC

RECEIPT_CONFIRM_TTL_SECONDS

Confirm link lifetime. Default 86400 (24 hours).

RECEIPT_CONFIRM_THRESHOLD

Price-cap units at or above which a receipt with no email approver contact has pay_allowed false. Default 100.

RECEIPT_EMAIL_PROVIDER

Leave unset. No email provider ships in this build. The caller delivers confirm_url.

Webhook endpoint: https://botsupply.onrender.com/v1/stripe/webhook.

Tests

npm test

Covers 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

MIT

Available Tools

13 tools
attach_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.

NameRequiredDescriptionDefault
typeYesProof kind. Examples: order_confirmation, tracking, url, hash.
valueYesThe proof itself: confirmation id, tracking number, URL, or hash.
statusNoOmit to mark an approved receipt delivered. Pass disputed to dispute it.
edit_tokenYesSecret returned once by record_approval. Required to attach proof.
receipt_idYesReceipt id from record_approval (rcpt_…).
actual_amountNoAmount actually charged. over_cap is true when this is above the price cap.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

NameRequiredDescriptionDefault
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.
creditsYesCredits to buy. 1 credit = $0.01 USD. Minimum 500 credits ($5). Same limits as POST /v1/wallets/:id/checkout.
wallet_idNoWallet to credit. Defaults to the wallet that owns the API key.

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 jobA
Idempotent

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.

NameRequiredDescriptionDefault
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.
descriptionYesWhat the payee is being paid to do.
amount_creditsYesCredits to debit from the authenticated payer wallet and hold until release or refund.
idempotency_keyYesCaller-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_idYesWallet that receives the credits when the payer releases the job.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 balanceA
Read-onlyIdempotent

Return the authenticated wallet id and prepaid credit balance. Same as GET /v1/balance. Does not return the API key.

NameRequiredDescriptionDefault
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.

TDQS

A3.6/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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 jobA
Read-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.

NameRequiredDescriptionDefault
job_idYesEscrow job id returned by create_job (job_…).
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 receiptA
Read-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.

NameRequiredDescriptionDefault
receipt_idYesPublic receipt id (rcpt_…).

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 catalogA
Read-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.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

NameRequiredDescriptionDefault
labelNoOptional label, 1 to 80 characters. Same field as POST /v1/wallets.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

NameRequiredDescriptionDefault
skuYesLive catalog SKU. The field name is sku, not sku_id.
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.

TDQS

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

NameRequiredDescriptionDefault
scopeYesWhat the human approved, in plain text.
agent_idNoOptional id of the agent that will pay. Not a BotSupply API key.
approverYesDisplay name or handle of the human who approved the purchase.
agent_nameNoOptional display name of the paying agent.
merchant_urlNoOptional http or https URL for the merchant.
payment_railYesHow the agent will pay. Examples: stripe_link, card, x402, botsupply_wallet.
merchant_nameYesMerchant or seller name.
approver_contactNoOptional email or phone. Stored only as a hash and never shown on the receipt.
price_cap_amountYesMaximum amount approved. A positive decimal, for example 25 or "19.95".
price_cap_currencyYesCurrency code, 3 to 10 letters, for example USD or USDC.
external_payment_refNoOptional id from the payment rail. BotSupply does not look it up.

TDQS

A4/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

NameRequiredDescriptionDefault
job_idYesEscrow job id returned by create_job (job_…).
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.

TDQS

A4.4/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

NameRequiredDescriptionDefault
job_idYesEscrow job id returned by create_job (job_…).
api_keyNoWallet API key (bsk_…). Optional when the MCP client sends Authorization: Bearer. The local stdio process also reads BOTSUPPLY_API_KEY.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 receiptA
Read-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.

NameRequiredDescriptionDefault
receipt_idYesPublic receipt id (rcpt_…).

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

  1. 9 tool updatesv1.1.0
    • Addedattach_proof
    • Changedcreate_checkout2 fields changed
      • changedInput schema / properties / credits / description
        Previous 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."
      • changedInput schema / properties / credits / minimum
        Previous value: -100New value: +500
    • Addedcreate_job
    • Addedget_job
    • Addedget_receipt
    • Addedrecord_approval
    • Addedrefund_job
    • Addedrelease_job
    • Addedverify_receipt
  2. 5 tool updatesv1.0.0
    • First observedcreate_checkout
    • First observedget_balance
    • First observedlist_catalog
    • First observedopen_wallet
    • First observedpurchase

TDQS

A4.1/5.0

Scored across 13 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityNo data
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers