booklint
Measured conclusion: Deep-tested. L2 outcome: tools_ok.
Checks an agent's trades, spend, bookings and offers against its owner's limits. Facts, not advice.
| Author | com.booklint |
|---|---|
| Access | remote |
| Publisher key required | No |
| Measured state | Deep-tested |
| L1 liveness | alive |
| L1 latency | 2116 ms |
| Last measured | 2026-10-26 |
Add to your agent
Copy this into your MCP client config:
{
"mcpServers": {
"booklint": {
"url": "https://booklint.com/mcp",
"transport": "streamable-http"
}
}
}
Measured tools (8)
get_sampleread-onlyFree, no key, instant result: runs a public sample through the checks and returns the issues found plus the next step (run check_book on your data, and what to send), never counted against any cap. Call before confirming a booking, spend or subscription. Start with name "booking" (sample 3, a hotel offer and the limits its owner wrote): it finds 3 issues; check_book with sample="booking" returns the full result, shortened here: {"verdict":"FLAGGED","results":{"total":"STOP","fees":"WARN","refund":"MATCH","cancel":"STOP","page":"MATCH"},"flags":[{"code":"total_price_cap","derivation":"offer: 3 mandatory line items total 636.6 USD; the total price cap is 600 USD"}]} "subscription" (sample 4, a subscription checkout) is the other Fine-Print Check sample. name "spend" is sample 2, a purchasing and booking agent's actions and the limits its owner wrote. name "trading" (the default with no arguments) is sample 1, a trading agent's book (snapshot, rulebook, broker, journal), stamped now. Each issue gives its code, status and a one-line derivation with the figures. The editable request body of each sample is at GET /v1/sample?name=<name>. Every check_* tool also runs its own sample with sample=true or with no arguments.
Parameters:
name— string — trading (default, sample 1), spend (sample 2), booking (sample 3) or subscription (sample 4). The result lists the issues found in it.
Hints: read-only yes · destructive not declared · idempotent yes · open-world no
check_bookread-onlyFree, no key, instant result: call with sample="booking", or with no arguments, for a real STOP result now, never counted; a sample result ends with next, the fields to send for your own data. Call before confirming a booking, spend or subscription. Deterministic spending guardrails: send the agent's actions or one offer with the limits its owner wrote, and booklint checks each one against them and answers FLAGGED, CLEAN or NOT_VERIFIED, naming each limit broken. Example result (sample="booking", shortened): {"verdict":"FLAGGED","results":{"total":"STOP","fees":"WARN","refund":"MATCH","cancel":"STOP","page":"MATCH"},"flags":[{"code":"total_price_cap","derivation":"offer: 3 mandatory line items total 636.6 USD; the total price cap is 600 USD"}]} Without api_key: 5 own checks per client address per UTC day, shared by check_book and the finance tools; samples are never counted. A free key (get_free_key, no card, no e-mail) runs 20 own checks a day and 200 in all. Same as POST /v1/check. Send a purchasing or booking agent's actions with limits (per-transaction and daily spend caps, merchant allow and deny lists, refundability), or, BEFORE booking or subscribing, one offer with limits (Fine-Print Check: total price cap, mandatory fees over the headline price, refundability, free-cancellation window, auto-renewal, renewal price, trial length, and an optional page_text consistency scan; each rule answers MATCH, WARN, STOP or NOT_CHECKED with the figure found). Send plain text you already have. Do not send a URL; booklint will not fetch one. Trading books against rulebooks too: send a trading book (snapshot, rulebook, optionally broker and journal). Returns verdict (FLAGGED, CLEAN, NOT_VERIFIED, REFUSED), coverage and flags. Each rule reports passed, failed or not checked; missing data is not checked, never assumed, and a result with zero flags is not a pass. Pass sample=true (sample 1, trading), sample="spend" (sample 2, purchasing and booking), sample="booking" (sample 3) or sample="subscription" (sample 4) with no key, never counted against the free caps, to see a full result. Not advice; nothing is executed.
Parameters:
as_of— string — The current UTC time (ISO 8601). Time rules use it; the server clock is never used.offer— object — One offer, as structured fields your agent extracted: merchant, currency, headline_price, line_items [{label, amount, mandatory}], refund {refundable, free_cancel_until}, subscription {auto_renews, renewal_price, renewal_interval, trial_ends}. Send with limits.broker— object — Optional broker export (desk checks).limits— object — The owner's limits: a rulebook (version, declared, rules).sample— true runs sample 1 (trading); "spend", "booking" or "subscription" runs sample 2, 3 or 4 instead. A call with no arguments at all runs sample 3 (booking).actions— array — An agent's actions: each {id, time (ISO 8601; days are UTC), amount, currency, merchant, refundable, kind}. Send with limits.api_key— string — Optional key (vdk_...). Same as the Bearer header.journal— object — Optional journal of claims (desk checks).rulebook— object — The agent's own rules.snapshot— object — The book: positions, cash, as_of (ISO 8601).page_text— string — Optional plain text copied from the offer page, at most 64 KB. Scanned for amounts and refund or renewal phrases. Send plain text you already have. Do not send a URL; booklint will not fetch one.
Hints: read-only yes · destructive not declared · idempotent no · open-world no
check_invoiceread-onlyFree, no key, instant result. Without api_key: 5 own checks per client address per UTC day, shared by check_book and the finance tools; samples are never counted. A free key (get_free_key, no card, no e-mail) runs 20 own checks a day and 200 in all. Try it now: call with no arguments, or with sample=true, to run the published sample (made-up figures, no key, never counted against the caps) and see real flags; the result ends with next, the fields to send for your own data. Send invoice or expense lines as JSON; returns flags for duplicate IDs, repeat vendor+amount+date, missing fields and currency mismatch. Math only. Process-and-discard: nothing is stored or logged after the run. A request containing a Luhn-valid card number or a valid IBAN is refused before accept with reason sensitive_data_refused (not counted as a check). Desk: volume use. Top-level verdict is CLEAN, FLAGGED or NOT_VERIFIED.
Parameters:
lines— array — Required for your own data: invoice or expense lines. Each line needs id, vendor, date, amount and currency.sample— boolean — true runs the published sample (made-up figures) instead of your data; a call with no arguments does the same. Never counted against the caps.api_key— string — Optional key (vdk_...). Same as the Bearer header.options— object — Optional. round_number_note (bool, default true): informational note for amounts >= 1,000 that are exact multiples of 1,000.expected_currency— string — Required for your own data: the header currency all lines use (e.g. GBP).
Hints: read-only yes · destructive not declared · idempotent yes · open-world no
check_quote_mathread-onlyFree, no key, instant result. Without api_key: 5 own checks per client address per UTC day, shared by check_book and the finance tools; samples are never counted. A free key (get_free_key, no card, no e-mail) runs 20 own checks a day and 200 in all. Try it now: call with no arguments, or with sample=true, to run the published sample (made-up figures, no key, never counted against the caps) and see real flags; the result ends with next, the fields to send for your own data. Send quote or pricing sheet lines as JSON; returns flags for mismatched line totals, wrong discount amounts, subtotal and grand-total errors, and tier range conflicts (overlap and gap). Math only. Process-and-discard: nothing is stored or logged after the run. A request containing a Luhn-valid card number or a valid IBAN is refused before accept with reason sensitive_data_refused (not counted as a check). Desk: volume use. Top-level verdict is CLEAN, FLAGGED or NOT_VERIFIED.
Parameters:
lines— array — Required for your own data: quote lines. Each line needs line_id, qty, unit_price and line_total.tiers— array — Optional quantity tiers. Each tier needs min_qty (int), max_qty (int or null), unit_price (number). Checked for overlaps and gaps.total— number — Optional stated total after discount; checked against subtotal minus discount.sample— boolean — true runs the published sample (made-up figures) instead of your data; a call with no arguments does the same. Never counted against the caps.api_key— string — Optional key (vdk_...). Same as the Bearer header.currency— string — Optional currency code (e.g. GBP). Carried through but not used in arithmetic checks.discount— object — Optional discount block: rate_pct (number, 0-100), base (string label, e.g. 'subtotal'), amount (number).subtotal— number — Optional stated subtotal; checked against sum of line totals.
Hints: read-only yes · destructive not declared · idempotent yes · open-world no
check_budget_varianceread-onlyFree, no key, instant result. Without api_key: 5 own checks per client address per UTC day, shared by check_book and the finance tools; samples are never counted. A free key (get_free_key, no card, no e-mail) runs 20 own checks a day and 200 in all. Try it now: call with no arguments, or with sample=true, to run the published sample (made-up figures, no key, never counted against the caps) and see real flags; the result ends with next, the fields to send for your own data. Send budget and actual lines as JSON; returns MATCH/WARN/STOP per line (default 5%/20%, overridable per request, thresholds always echoed), ranked overruns (largest % overrun first). Overall = worst line status. Math only. Process-and-discard: nothing is stored or logged after the run. A request containing a Luhn-valid card number or a valid IBAN is refused before accept with reason sensitive_data_refused (not counted as a check). Desk: volume use. Top-level verdict is CLEAN, FLAGGED or NOT_VERIFIED. Per-line and overall status stay MATCH, WARN or STOP; those are not the top-level verdict.
Parameters:
lines— array — Required for your own data: budget vs actual lines. Each line needs line_id (string), budget (number) and actual (number). A line with budget 0 is reported as NOT_CHECKED (not a flag) and makes coverage incomplete.period— string — Optional period label (e.g. 2026-09). Carried through but not validated.sample— boolean — true runs the published sample (made-up figures) instead of your data; a call with no arguments does the same. Never counted against the caps.api_key— string — Optional key (vdk_...). Same as the Bearer header.currency— string — Optional currency code (e.g. GBP). Carried through but not used in checks.thresholds— object — Optional threshold overrides. match_max_pct (default 5): overspend % at or below this is MATCH. warn_max_pct (default 20): overspend % above match_max_pct and at or below this is WARN; above is STOP. Both must be non-negative and warn_max_pct >= match_max_pct.
Hints: read-only yes · destructive not declared · idempotent yes · open-world no
check_accounts_tieoutread-onlyFree, no key, instant result. Without api_key: 5 own checks per client address per UTC day, shared by check_book and the finance tools; samples are never counted. A free key (get_free_key, no card, no e-mail) runs 20 own checks a day and 200 in all. Try it now: call with no arguments, or with sample=true, to run the published sample (made-up figures, no key, never counted against the caps) and see real flags; the result ends with next, the fields to send for your own data. Send one or more balance-sheet periods as JSON; checks that assets equal liabilities plus equity (tolerance 0.01), that any stated subtotals sum correctly, that net income less dividends agrees with the change in retained earnings (tolerance ±1, per terms), and that consecutive periods (when start/end dates are supplied) have no gaps or overlaps. Process-and-discard: nothing is stored or logged after the run. A request containing a Luhn-valid card number or a valid IBAN is refused before accept with reason sensitive_data_refused (not counted as a check). Desk: volume use. Top-level verdict is CLEAN, FLAGGED or NOT_VERIFIED. NOT_VERIFIED when tieout fields are absent for any period or fewer than two periods carry parseable dates (period_sequence NOT_CHECKED).
Parameters:
sample— boolean — true runs the published sample (made-up figures) instead of your data; a call with no arguments does the same. Never counted against the caps.api_key— string — Optional key (vdk_...). Same as the Bearer header.periods— array — Required for your own data: a list of balance-sheet periods. Each period requires: period_id (string), total_assets (number), total_liabilities (number), total_equity (number). Optional per period: start and end (ISO date YYYY-MM-DD, for gap/overlap check), subtotals (array of {label, items: [number, ...], stated}), net_income (number), dividends (number, default 0), retained_earnings_open (number), retained_earnings_close (number). net_income_tieout runs only when net_income, retained_earnings_open and retained_earnings_close are all supplied.
Hints: read-only yes · destructive not declared · idempotent yes · open-world no
check_data_qualityread-onlyFree, no key, instant result. Without api_key: 5 own checks per client address per UTC day, shared by check_book and the finance tools; samples are never counted. A free key (get_free_key, no card, no e-mail) runs 20 own checks a day and 200 in all. Try it now: call with no arguments, or with sample=true, to run the published sample (made-up figures, no key, never counted against the caps) and see real flags; the result ends with next, the fields to send for your own data. Send a dataset as a list of row dicts (JSON) or a CSV string; checks null rate per field (flagged when above max_null_rate, default 0.2), type inconsistencies within a field (number / bool / string, nulls excluded), exact duplicate rows, and numeric outliers (values beyond Q1 − 3×IQR or Q3 + 3×IQR, requires ≥ 4 non-null values per field). Schema-drift excluded from v1. Process-and-discard: nothing is stored or logged after the run. A request containing a Luhn-valid card number or a valid IBAN is refused before accept with reason sensitive_data_refused (not counted as a check). Desk: volume use. Top-level verdict is CLEAN or FLAGGED.
Parameters:
csv— string — Dataset as a CSV string with a header row (CSV mode). Mutually exclusive with 'rows'.rows— array — Dataset as a list of row dicts (JSON mode). Mutually exclusive with 'csv'.sample— boolean — true runs the published sample (made-up figures) instead of your data; a call with no arguments does the same. Never counted against the caps.api_key— string — Optional key (vdk_...). Same as the Bearer header.max_null_rate— number — Null-rate threshold 0.0–1.0; fields above this are flagged. Default 0.2.
Hints: read-only yes · destructive not declared · idempotent yes · open-world no
get_free_keyFree, no card, no e-mail, instant result: returns a free key at once, the same as POST /v1/keys {"plan": "free"}, with the same daily limits on new keys per client and across the service. The key is shown once in this result and is not stored or logged; pass it as api_key to check_book or a finance tool. A free key runs 20 own checks a day and 200 in all; without a key it is 5 a day per client address. The result lists the limits. Optional label: 1 to 40 letters, digits, '.', '_' or '-'.
Parameters:
label— string — Optional label for your own records (1-40 of A-Z a-z 0-9 . _ -).
Hints: read-only no · destructive not declared · idempotent no · open-world no
Measured by MCPYP probing. Untested fields are omitted, never estimated. Listing is always free; MCPYP never proxies calls or stores user tokens.