Skip to main content
Glama

Server Details

Capture receipts, scan Gmail, analyze spending, and create reviewed reports from AI assistants.

If you are the author of this connector, you can claim ownership with GitHub, an HTTP challenge, or a DNS record. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
TotesMagotes/expensebot-mcp
GitHub Stars
0
Server Listing
ExpenseBot MCP

TDQS

A3.9/5.0

Scored across 59 tools

Disambiguation3/5

Many tools have clearly distinct targets, but the 59-tool surface includes ambiguous generic names (search, fetch) and several overlapping analytics and receipt-processing tools (get_spending_summary vs get_deep_analytics, scan_gmail vs process_gmail_receipts). The exceptionally detailed descriptions mitigate confusion, but an agent may still pick the wrong tool for vague user queries.

Naming Consistency4/5

The vast majority of tools follow a consistent verb_noun pattern (add_*, get_*, list_*, etc.), with families like search_expenses/update_expense/correct_expenses aligning well. The handful of generic single-word names (fetch, search) and the 'whatif_' prefix break the pattern, though these are isolated deviations in an otherwise readable convention.

Tool Count2/5

At 59 tools, the surface is far above what is typically considered well-scoped (3–15) and even exceeds the 'heavy' 25+ threshold. While the expense-management domain is broad, many tools could be consolidated (e.g., unified import flows or fewer summary variants), making the set feel sprawling and harder to navigate.

Completeness5/5

The toolset provides exceptionally thorough domain coverage: expense/income/mileage entry, receipt processing (image, PDF, Gmail), reporting, invoicing, accounting integration, compliance checking, analytics, and what-if scenarios. There are no obvious functional dead ends—the only minor omissions (delete/ungroup) appear intentional to enforce data integrity.

Available Tools

59 tools
add_cash_expenseAInspect

Add an expense without a receipt, or record money a client provided in advance for expenses. Writes directly to the user's expense spreadsheet after confirmation. For an ordinary expense, call list_categories first and provide a configured Expense Account. For a client advance, set isClientAdvance=true and clientName; ExpenseBot reuses or creates the canonical client group, applies Cash advance received, and stores the amount as a negative expense. Use this only for money supplied by a client before related spending, never for vendor refunds, reimbursements, earned fees, retainers, or generic deposits. Use the Manual expense link from get_spreadsheet_url instead when the user needs a reviewed form for multiple entries, credits/refunds, tax or tip breakdowns, per diem, or incomplete details.

ParametersJSON Schema
NameRequiredDescriptionDefault
taxNoTax amount
tipNoTip amount
cityNoCity/location
dateYesExpense date (YYYY-MM-DD)
notesNoNotes or description
totalYesPositive amount paid or received. ExpenseBot stores a client advance as negative.
categoryNoA configured Expense Account returned by list_categories. Do not invent a category.
currencyNoCurrency code (default: USD)
merchantNoMerchant/vendor name for an ordinary expense. Not needed for a client advance; ExpenseBot derives it from clientName.
subtotalNoSubtotal before tax
clientNameNoClient name for a client advance, in ordinary language. ExpenseBot resolves the canonical Client – Name group.
isClientAdvanceNoTrue only when a client supplied money in advance for expenses. Requires clientName and does not require category.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
expenseNo
messageYes
successYes
recordIdNo
rowNumberNo
finalAnswerNo
spreadsheetUrlNo
responseGuidanceNo
reviewExpensesUrlNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses concrete side effects: it writes directly to the spreadsheet after confirmation, reuses or creates the canonical client group, applies 'Cash advance received', and stores client advances as negative expenses. This goes well beyond the structured annotations, though it does not mention reversal or post-write behavior in much detail.

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?

The description is longer than average, but every sentence carries operational value and the two modes are clearly separated. The most important constraint, 'never for vendor refunds...', is explicitly front-loaded before naming the alternative, which keeps the structure scannable despite its length.

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 12-parameter, two-mode write tool, the description covers the required workflow, mode-specific parameter requirements, exclusions, and the fallback alternative. Since an output schema is present, the description does not need to explain return values, and nothing material appears missing for an agent deciding whether and how to invoke this tool.

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%, but the description adds meaningful cross-parameter semantics: category must come from list_categories, isClientAdvance requires clientName and does not require category, merchant is derived from clientName for advances, and total is stored as negative for advances. These relationships are not present in the individual parameter descriptions.

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?

The description opens with a specific verb and two identifiable actions: adding an expense without a receipt or recording a client advance. It also names the write target, 'user's expense spreadsheet', and distinguishes the client-advance mode from ordinary expenses, which sets it apart from sibling tools like add_income or update_expense.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: call list_categories first for ordinary expenses, set isClientAdvance=true and clientName for client advances, and never use this tool for vendor refunds, reimbursements, earned fees, retainers, or generic deposits. It also names the alternative, the Manual expense link from get_spreadsheet_url, with the exact conditions under which that alternative should be preferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_incomeAInspect

Log exactly one user-confirmed income payment manually (cash, check, Stripe payout, etc.). Never loop this tool over a statement, export, table, or multi-row list. For two or more payments, use add_income_from_csv for CSV/TSV/text or add_income_from_file for an image/PDF; those tools stage a duplicate-checked preview and require confirmation before writing. Writes to the Income tab of the user's expense spreadsheet. Useful for income that isn't auto-detected from Gmail or Plaid. Call list_income_categories first and use one of its fixed tax categories; an omitted category defaults to Service income and an unknown category is rejected.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoTag for client/project attribution
dateNoIncome date (YYYY-MM-DD). Defaults to today.
feesNoProcessor/transfer fees deducted
notesNo
amountYesIncome amount (>0)
sourceYesWho paid you (client name, customer, etc.)
categoryNoA category returned by list_income_categories (optional; defaults to Service income)
currencyNoCurrency code (default: home currency)
referenceNoInvoice or transaction reference
descriptionNoWhat the income was for
taxCollectedNoSales tax/GST/HST collected
paymentMethodYesHow you got paid. Canonical rails are Cash, Check, Bank transfer, Wallet app, Credit/Debit card, Payment processor, or Other; common labels such as Stripe and Venmo are normalized.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
dedupedNo
messageYes
successYes
recordIdNo
rowNumberNo
matchedRowNo
tabCreatedNo
finalAnswerNo
destinationsNo
responseGuidanceNo

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the tool writes to the Income tab, that an omitted category defaults to Service income, and that unknown categories are rejected. It could be even more explicit about the direct-write/no-confirmation behavior compared to the staging alternatives, but the annotations already signal this is not read-only.

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?

The description is dense but every sentence earns its place: scope, anti-patterns, sibling routing, side effects, use case, and category prerequisite. It is front-loaded and contains no filler.

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 single-write tool with high schema coverage and an output schema, the description provides all essential context: what it does, when not to use it, alternatives, side effects, and required category lookup. Nothing critical is missing.

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 92%, so the schema does most of the parametric work. The description adds valuable semantics beyond the schema: category must be a fixed tax category from list_income_categories, omitted categories default to Service income, and unknown categories are rejected.

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?

The description opens with a precise verb+resource: 'Log exactly one user-confirmed income payment manually'. It clearly distinguishes this tool from add_income_from_csv and add_income_from_file by scope and invocation model.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says never to loop this tool over multi-row data and names the exact alternate tools for CSV/TSV/text and image/PDF inputs. It also tells the agent to call list_income_categories first and clarifies when this tool is useful relative to auto-detection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_income_from_csvAInspect

Import income from a CSV/TSV/text export (Stripe, PayPal, Square, Cash App, Venmo, OnlyFans, Patreon, Clips4Sale, Ko-fi, Gumroad, Etsy, Uber/Lyft/DoorDash driver exports, bank statements, and similar; max 500 KB). Same two-step contract as add_income_from_file: STEP 1 call with csvContent and WITHOUT confirm parses the file with the same platform-agnostic importer as the app's Add Income screen (platform detection, fee handling, refunds, source aliases, ISO dates) and returns a duplicate-checked preview with a previewId. NOTHING is saved in step 1. Show the user the parsed rows and duplicates, then STEP 2 call again with confirm: true and the previewId to write exactly those rows, optionally with user-approved selectedIndexes, keepBothIndexes, rowEdits, tag, or bulkNote. Flagged duplicates are skipped unless the user explicitly keeps them. The preview expires after 15 minutes and an expired or unknown previewId never writes. After a successful confirm, show the returned spreadsheetUrl and reviewIncomeUrl.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoOptional client/project tag. In step 1 it pre-fills the staged rows; in step 2 it applies to the confirmed selection.
confirmNoStep 2 only: true writes the staged rows. Omit it (with previewId absent) to parse and preview without writing.
csvTextNoLegacy fallback for MCP clients that send raw CSV/TSV/text content inline. ChatGPT should use csvContent.
bulkNoteNoStep 2 only: one note (max 120 chars) prepended to every confirmed row's Notes, same as the app's 'Add note to all entries'.
rowEditsNoStep 2 only: user-approved corrections, at most 50 rows. Fields: date (ISO YYYY-MM-DD), source, amount, currency, category, paymentMethod, description, notes, reference, fees, taxCollected, tag.
previewIdNoStep 2 only: the previewId returned by the step-1 call.
csvContentNoAttached CSV/TSV/text file supplied by ChatGPT for step 1. The server downloads and decodes the attachment securely.
paymentMethodNoFallback payment rail for rows where the parser found none (Cash, Check, Bank transfer, Wallet app, Credit/Debit card, Payment processor, or Other).
keepBothIndexesNoStep 2 only: preview indexes of duplicate-flagged rows the user explicitly wants to keep anyway (the app's 'Keep Both').
selectedIndexesNoStep 2 only: preview row indexes to write. Omit to write all staged rows.

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalNo
failedNo
dedupedNo
entriesNo
messageYes
previewNo
successYes
writtenNo
warningsNo
confirmedNo
expiresAtNo
previewIdNo
duplicatesNo
entryCountNo
finalAnswerNo
unattemptedNo
rejectedRowsNo
duplicateCountNo
maxChatEntriesNo
refundRowCountNo
spreadsheetUrlNo
reviewImportUrlNo
reviewIncomeUrlNo
tooLargeForChatNo
expiresInMinutesNo
idempotentReplayNo
responseGuidanceNo
totalsByCurrencyNo
projectionTruncatedNo
confirmationContractNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint=false, destructiveHint=false, and openWorldHint=false, so the description carries the behavioral burden. It discloses the two-step write contract, the 15-minute preview expiry, that expired/unknown previewIds never write, duplicate skipping unless explicitly kept, and the max 500 KB file size. This is rich behavioral context that goes well beyond the annotations.

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?

The description is dense and front-loaded with the core action and supported sources, then walks through the two-step contract in a logical order. It is long, but nearly every sentence earns its place given the complexity of the two-step flow and the number of parameters. A small amount of redundancy exists (e.g., repeating the same two-step contract as add_income_from_file), but it is not bloated.

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?

Given the tool's complexity (10 params, nested objects, two-step contract, output schema present), the description covers the workflow, safety guarantees, expiry, duplicate handling, and post-confirm next steps (spreadsheetUrl and reviewIncomeUrl). The output schema exists, so return values need not be spelled out. Nothing essential is missing for an agent to invoke this correctly.

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 description coverage is 100%, so the baseline is 3. The description adds value by explaining the step-1/step-2 roles of parameters (e.g., confirm, previewId, selectedIndexes, keepBothIndexes, rowEdits, tag, bulkNote) and by clarifying that csvText is a legacy fallback while ChatGPT should use csvContent. That is meaningful semantic guidance beyond 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?

The description opens with a specific verb and resource ('Import income from a CSV/TSV/text export') and immediately enumerates supported sources, which distinguishes it from generic import tools. It also names the sibling add_income_from_file and frames this as the same two-step contract, so an agent can tell them apart.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives an explicit two-step protocol: step 1 with csvContent and without confirm, step 2 with confirm:true and previewId. It also states what not to do ('NOTHING is saved in step 1') and what to show the user, which is strong usage guidance beyond the schema.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_income_from_fileAInspect

Import income from an attached screenshot, image (JPEG, PNG, WebP, HEIC/HEIF), or PDF (payment screenshots, wallet apps, payout or bank statements; max 10 MB). This is a two-step tool. STEP 1: call it with the file and WITHOUT confirm — ExpenseBot parses the file with the same importer as the app's Add Income screen, checks every row against the user's Income tab for duplicates, and returns a preview with a previewId, exact row count, totals by currency, per-row details, duplicate flags, and any rejected rows. NOTHING is saved in step 1; treat the attachment as consent to parse, not consent to write. Show the user the parsed rows and duplicates, then STEP 2: call again with confirm: true and the previewId to write exactly those rows. Only include user-approved changes in step 2 (selectedIndexes, keepBothIndexes, rowEdits, tag, bulkNote). Flagged duplicates are skipped unless the user explicitly asks to keep them (keepBothIndexes). The preview expires after 15 minutes; an expired or unknown previewId never writes. After a successful confirm, show the returned spreadsheetUrl and reviewIncomeUrl. For a visually complex review (mixed income/expense rows, many edits), send the user to the Add Income app link returned by get_spreadsheet_url instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoOptional client/project tag. In step 1 it pre-fills the staged rows; in step 2 it applies to the confirmed selection.
photoNoAttached image or PDF supplied by ChatGPT for step 1. The server downloads and parses the attachment securely.
confirmNoStep 2 only: true writes the staged rows. Omit it (with previewId absent) to parse and preview without writing.
bulkNoteNoStep 2 only: one note (max 120 chars) prepended to every confirmed row's Notes, same as the app's 'Add note to all entries'.
mimeTypeNoMIME type of the file (default: image/jpeg)
rowEditsNoStep 2 only: user-approved corrections, at most 50 rows. Fields: date (ISO YYYY-MM-DD), source, amount, currency, category, paymentMethod, description, notes, reference, fees, taxCollected, tag.
previewIdNoStep 2 only: the previewId returned by the step-1 call.
photoBase64NoLegacy fallback for MCP clients that send complete image/PDF bytes as base64. ChatGPT should use photo.
paymentMethodNoFallback payment rail for rows where the parser found none (Cash, Check, Bank transfer, Wallet app, Credit/Debit card, Payment processor, or Other).
keepBothIndexesNoStep 2 only: preview indexes of duplicate-flagged rows the user explicitly wants to keep anyway (the app's 'Keep Both').
selectedIndexesNoStep 2 only: preview row indexes to write. Omit to write all staged rows.

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalNo
failedNo
dedupedNo
entriesNo
messageYes
previewNo
successYes
writtenNo
warningsNo
confirmedNo
expiresAtNo
previewIdNo
duplicatesNo
entryCountNo
finalAnswerNo
unattemptedNo
rejectedRowsNo
duplicateCountNo
maxChatEntriesNo
refundRowCountNo
spreadsheetUrlNo
reviewImportUrlNo
reviewIncomeUrlNo
tooLargeForChatNo
expiresInMinutesNo
idempotentReplayNo
responseGuidanceNo
totalsByCurrencyNo
projectionTruncatedNo
confirmationContractNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only provide readOnlyHint, openWorldHint, and destructiveHint, all false. The description takes on the full burden and thoroughly discloses that step 1 saves nothing, writes only happen with confirm, previews expire after 15 minutes, and duplicates are skipped unless keepBoth is requested.

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?

The description is lengthy but well-structured, beginning with purpose and formats, then breaking into STEP 1 and STEP 2. Every sentence earned its place in a complex two-step tool with 11 parameters.

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?

The definition covers file constraints, consent boundaries, preview details, expiration, duplicate handling, and the appropriate next integration. With an output schema present, it fully equips an agent to invoke the tool correctly.

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 baseline is 3. The description adds step-specific orchestration (selectedIndexes, keepBothIndexes, rowEdits, confirm, previewId) that links parameters to the preview/confirm workflow, raising it above baseline.

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?

The description begins with a specific verb and resource: 'Import income' from attached images/PDFs. It clearly enumerates supported file formats and references the same importer as the app's Add Income screen, making its scope unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives a complete two-step protocol, explaining when to call with confirm vs. without, how to handle duplicates, and when to route the user to the Add Income app link. It explicitly guides step 1 vs. step 2 behavior and leaves no ambiguity about when the tool should be used.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_mileage_entryAInspect

Log a business mileage trip in ExpenseBot. Useful for realtors, consultants, contractors, and anyone who drives for work. Requires the user to have configured their mileage rate (cents/km or cents/mi) and unit (mi/km) in ExpenseBot Settings. The trip writes a row to their expense spreadsheet with the calculated dollar value. Use the Mileage and travel link from get_spreadsheet_url instead when the user needs Google Maps route calculation, mileage settings, repeated trips, calendar/rideshare import, per diem, or visual review.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoTag for client/project attribution (optional)
cityNoCity (optional)
dateNoTrip date (YYYY-MM-DD). Defaults to today.
notesNoOptional user-supplied context stored with the mileage entry.
purposeYesBusiness purpose / description of the trip (e.g., 'Client meeting at 1234 Main St')
categoryNoOverride the user's default mileage category (optional)
distanceYesDistance traveled in the user's configured unit (miles or km)
roundTripNoIf true, doubles the distance (return trip)
destinationNoDestination address or location (optional)

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageYes
successYes
settingsNo
rowNumberNo
finalAnswerNo
spreadsheetUrlNo
responseGuidanceNo
reviewExpensesUrlNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish readOnlyHint=false, indicating a write operation. The description goes beyond this by specifying the concrete side effect: 'writes a row to their expense spreadsheet with the calculated dollar value.' It also discloses the requirement for pre-configured mileage settings. This adds useful behavioral context beyond the annotation, though it does not detail error handling or validation behavior.

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?

The description is three sentences with zero filler. The primary action is stated first, followed by prerequisites, the effect, and a clear alternative. Every sentence serves a distinct purpose and the structure is efficiently front-loaded.

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?

Given the tool's complexity (9 parameters, 2 required), the presence of an output schema, and the annotations, the description covers the essential context: what it does, prerequisites, side effects, and when to prefer an alternative. It does not explain potential error conditions or response format, but the output schema covers returns. This is sufficient for an agent to correctly invoke the 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%, with each parameter already documented in the input schema (e.g., distance described as 'in the user's configured unit', roundTrip as 'doubles the distance'). The tool description does not add any additional parameter-level meaning beyond what the schema provides. With high coverage, a 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?

The description opens with a clear verb and resource: 'Log a business mileage trip in ExpenseBot.' It specifies the target audience (realtors, consultants, contractors) and distinguishes itself from the alternative get_spreadsheet_url by listing explicit use cases it does not cover, such as route calculation or import. This makes the tool's unique role unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance ('Log a business mileage trip') and when-not-to-use guidance by naming the alternative tool and the exact conditions that should route the agent elsewhere (Google Maps, mileage settings, repeated trips, etc.). It also states the prerequisite (configured mileage rate and unit), leaving no ambiguity about the appropriate context for calling this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_complianceA
Read-only
Inspect

Use only when the user explicitly asks to check an existing report for compliance issues such as missing business purpose or policy violations. Creating a report, excluding Personal expenses, sharing a report, or billing a client is not a compliance request; never call this tool automatically as a preflight or follow-up for those workflows.

ParametersJSON Schema
NameRequiredDescriptionDefault
reportIdYesReport ID to check
userRequestYesThe user's exact request explicitly asking for compliance, policy, audit, substantiation, or business-purpose analysis. Do not paraphrase or invent intent.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false. The description goes beyond them by defining the required user intent and explicitly prohibiting automatic invocation, which is a meaningful behavioral constraint and clarifies that this is not a side-effect-free routine to run casually.

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?

The description is compact, front-loaded with the core condition, and uses the second sentence to prevent common misuse. Every clause contributes useful guidance with no wasted words.

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?

The definition covers what the tool does, when to use it, when not to use it, and the precise nature of the required user request. An output schema exists, so return values need not be described, and no critical operational context 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%, so the schema already documents both reportId and userRequest. The description reinforces that the report must already exist and that userRequest must be literal, but it adds only marginal meaning beyond the schema's own parameter descriptions.

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?

The description states a specific verb and resource: 'check an existing report for compliance issues,' with concrete examples like missing business purpose or policy violations. It also clearly distinguishes this from sibling workflows such as creating, sharing, or billing reports, so an agent can correctly identify the tool's scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is explicit: call only when the user explicitly asks for a compliance check, and never automatically as a preflight or follow-up. The description also names non-compliance workflows (creating a report, excluding Personal expenses, sharing, billing) to prevent misuse.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_featureA
Read-only
Inspect

Check whether ExpenseBot supports a specific feature ('does ExpenseBot support X', 'can it integrate with Y'). Searches the public knowledge base and returns a confidence-scored answer + related questions. Works with or without authentication.

ParametersJSON Schema
NameRequiredDescriptionDefault
featureYesFeature or integration to check (e.g., 'Xero', 'mileage tracking', 'Plaid')

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successYes

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already declaring readOnly/openWorld/destructive hints, the description adds useful behavioral context: it queries a public knowledge base, returns a confidence-scored answer plus related questions, and does not require authentication. No contradiction with annotations.

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?

Two concise sentences with examples front-loadedclause by clause. No filler, every sentence earns its place.

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 simple, read-only, single-parameter tool with rich annotationschedema and a described return shape, the description is fully adequate for an agent to select and invoke it 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 covers the single parameter 100%, including a description and example. The description's example queries reinforce semantics but don't add meaningful new information beyond the schema, so 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?

The description clearly states the tool's purpose: checking whether ExpenseBot supports a specific feature, with examples of natural language queries. It distinguishes from check_compliance and check_tax_deductibility by focusing on feature support, though it doesn't explicitly distinguish itself from the similar 'search' tool.

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?

Provides clear context with example phrasings ('does ExpenseBot support X', 'can it integrate with Y'). States that it searches the public knowledge base and works with or without authentication. Doesn't explicitly exclude alternatives, but the examples serve as strong usage signals.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_tax_deductibilityA
Read-only
Inspect

Look up whether a specific expense type or purchase is tax-DEDUCTIBLE (business write-off rules) based on the user's country/jurisdiction. This is a deductibility advice tool — use it for questions like 'is Uber deductible', 'can I write off home office', 'are client dinners 50% or 100%'. Do NOT use it for questions about tax REFUNDS received as income (use get_spending_summary with a 'tax refunds' query for those — they're routed to the Income tab, not deduction rules).

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesDeductibility question (e.g., 'is Uber tax deductible', 'home office write-off rules')
categoryNo
merchantNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is known. The description adds that this is an 'advice' tool and that results depend on country/jurisdiction, providing context beyond the annotations. It does not contradict any annotation.

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?

The description is two sentences, front-loaded with purpose and examples, then provides the exclusion. It is concise and well-structured, though the second sentence is somewhat long with multiple examples. No wasted words.

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?

The output schema exists, so return values are covered. The description includes examples, jurisdictional context, and explicit exclusions. Given the moderate complexity and that annotations cover safety, the description is nearly complete. The only minor gap is lack of parameter elaboration for optional fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 33% (only 'query' is described). The description does not mention 'category' or 'merchant' parameters, nor their purpose. Given the low coverage, the description should compensate, but it only explains the primary 'query' parameter implicitly. The agent is left without guidance on the optional parameters.

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?

The description clearly states the tool's function: to look up tax deductibility based on jurisdiction, with specific examples. It distinguishes itself from siblings like get_spending_summary, which handles tax refunds. The verb 'look up' and resource 'tax deductibility' are precise.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly provides when to use ('is Uber deductible', 'home office write-off') and when not to use (tax refunds, routed to get_spending_summary). Names the alternative tool and the condition for switching, leaving no ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

correct_expensesA
Destructive
Inspect

Safely correct the category, business purpose, or explicit attendees on an exact bounded set of recorded expenses. Examples: 'categorize these as Travel', 'add Client kickoff dinner as the business purpose for these meals', or 'add Fred, Rob, and Lamar to last night's business meal'. First use search_expenses to identify the exact rows, then pass their full expenseId values. A grounded preview is automatic: first call with confirm omitted/false, show the exact count and proposed before-to-after changes, and ask once for approval. Only after explicit approval repeat the same operationId, selection, and change with confirm:true. A premature confirm:true is converted to preview. Attendee names must come explicitly from the user; never infer them. attendeeMode add preserves existing attendees, while replace substitutes only the attendee segment. Business purpose and attendees preserve the structured Notes field, including card, description, inbox, and other typed segments. Formula Notes and changes that exceed the Notes limit are skipped safely. The confirmed result reports applied/conflicted/failed counts and supports Undo. This tool does not omit duplicates, change amounts or dates, infer business context, or run broad Calendar matching. For unsupported or more than 100-row cleanup, send the user to https://www.expensebot.ai/review-expenses?source=mcp.

ParametersJSON Schema
NameRequiredDescriptionDefault
undoNoUndo a completed correction within its Undo window.
changeNoExactly one correction. The selected type determines which matching value field is required.
statusNoRead operation status using operationId.
confirmNoOmit/false for preview; true only after explicit approval.
selectionNoExact expenses returned by search_expenses and approved for this bounded correction.
operationIdYesStable idempotency key generated once for preview and reused unchanged.

Output Schema

ParametersJSON Schema
NameRequiredDescription
undoNo
changeNo
statusYes
messageNo
previewNo
successYes
manifestNo
finalAnswerNo
operationIdNo
confirmationNo
responseGuidanceNo
reviewExpensesUrlNo
requiresConfirmationNo

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations supply destructiveHint=true, but the description goes far beyond that: premature confirm:true is converted to preview, formula Notes and over-limit changes are skipped safely, attendeeMode add vs replace semantics, Notes preservation, confirmed result counts, and Undo support. These are behavioral traits the structured annotations cannot express, and they materially change how an agent should invoke and interpret the tool.

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?

The description is long but every sentence earns its place for a complex two-phase tool. It front-loads the core purpose and examples, then walks through the preview/confirm lifecycle, then edge cases, then exclusions and fallback. Dense but highly structured, with no redundant filler or repetition of schema trivia.

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?

Given the tool's complexity (two-phase confirm flow, conflict detection, undo, attendee modes, 100-row limit, external fallback), the description covers all decision-relevant aspects: how to prepare the selection, how to execute the preview and confirmation, what happens on premature confirmation, what is preserved vs skipped, and what the confirmed result reports. The output schema covers return values, so nothing needed for correct use is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds crucial meaning beyond field names: operationId is a 'stable idempotency key generated once for preview and reused unchanged,' selection must 'never broaden this list after preview,' expected values are for 'optimistic-concurrency... conflict detection,' and attendees 'must come explicitly from the user; never infer them.' These semantics are essential for correct invocation and are absent from 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?

The opening sentence states a specific verb + resource + scope: 'Safely correct the category, business purpose, or explicit attendees on an exact bounded set of recorded expenses.' The examples further clarify real intent, and the closing exclusions (does not omit duplicates, change amounts/dates, infer business context, run broad Calendar matching) sharply delimit what this tool is not, distinguishing it from siblings like update_expense, fix_compliance, and group_expenses.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use and workflow: 'First use search_expenses to identify the exact rows, then pass their full expenseId values.' The preview/confirm protocol is spelled out step-by-step, and an explicit fallback is given: 'For unsupported or more than 100-row cleanup, send the user to https://...' There is also a clear list of things the tool does NOT do, which doubles as a negative usage guide.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_client_invoiceA
Destructive
Inspect

Create the exact invoice previously returned by prepare_client_invoice. This is a confirmed write: it revalidates the report snapshot and client identity, creates a private editable Google Doc plus private PDF and DOCX copies, records the issued invoice, and supersedes an older active invoice for the same report. It does not send email or create an Income row. If tax is positive, confirmTax must be true.

ParametersJSON Schema
NameRequiredDescriptionDefault
confirmTaxNoTrue only after the user confirms the displayed tax label and rate.
operationIdNoOptional retry key. Reuse it after an uncertain response.
preparationIdYesShort-lived ID returned by prepare_client_invoice.

Output Schema

ParametersJSON Schema
NameRequiredDescription
totalNo
pdfUrlNo
statusNo
docxUrlNo
dueDateNo
successYes
currencyNo
invoiceIdNo
issueDateNo
recoveredNo
clientNameNo
grandTotalNo
documentUrlNo
invoiceNumberNo
advanceAppliedNo
sourceReportIdNo
artifactWarningNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the destructiveHint annotation by detailing side effects: revalidating snapshot/client identity, creating Google Doc/PDF/DOCX copies, recording the invoice, and superseding an older active invoice. It also explicitly frames the operation as 'a confirmed write,' giving the agent accurate expectations.

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 written sentences deliver the core purpose first, then side effects, exclusions, and the key conditional rule. Every sentence earns its place with no filler or repetition of schema fields.

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?

Given this is a destructive write operation with an output schema, the description covers all essential context: preconditions, created artifacts, supersession effect, excluded side effects, and the tax confirmation requirement. An agent has enough information to decide when to invoke it and what to expect.

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 schema already documents all parameters. The description adds useful semantic context on top, such as confirmTax being required only when tax is positive and preparationId being the short-lived ID from prepare_client_invoice.

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 the exact invoice previously returned by prepare_client_invoice.' This clearly distinguishes it from read-only siblings like get_client_invoice and list_client_invoices, and from related actions like mark_client_invoice_paid.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly ties invocation to a prior call to prepare_client_invoice, and clarifies what the tool does not do ('does not send email or create an Income row'). It also gives a concrete conditional rule: 'If tax is positive, confirmTax must be true.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_reportAInspect

Create an expense report from a clear date, client, project, trip, category, or merchant request. Tags are ExpenseBot's grouping layer for clients, projects, project codes, and trips; call list_tags when the user's intended group is unclear. For requests such as 'all expenses in August except personal', set excludePersonal=true; this excludes both the Personal tag and Personal expense category, matching ExpenseBot's Report Wizard. Returns the report summary, exact report link, Bill Client link, applied filters, and a prefilled Report Wizard fallback for criteria that need visual review. Reports scoped to an existing client/project/trip group include matching expenses that are not already assigned to another ordinary report. Can optionally share with recipients. If no unreported matches remain, create no duplicate report and explain that the expenses are already in Reports. Terminal results also include role-appropriate accountingHandoffUrls from the server capability matrix and the existing reviewed file-export workflow. Use only the exact destination the user requested; the link opens the reviewed app flow and does not mean an export occurred. Complete the requested report directly; do not call check_compliance, get_report_details, or tax/deductibility tools before or after it unless the user explicitly asks for that separate analysis.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoExisting ExpenseBot groups to include, such as a client, project, project code, property, or trip. Use list_tags first when uncertain.
titleNoCustom report title
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.
shareWithNoEmail addresses to share the report with
categoriesNoOptional configured expense categories to include in the report.
excludedTagsNoExisting ExpenseBot groups to exclude from the report.
recipientRoleNoAccess for every shareWith recipient. Use reviewer for one-report review, comments, approval, or change requests. Use accountant only when the user explicitly wants ongoing report management and accounting-software access.reviewer
excludePersonalNoExclude expenses whose Tag is Personal or whose Expense Category is Personal.
excludedCategoriesNoExpense categories to exclude from the report.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
successYes
reportIdNo
reportUrlNo
finalAnswerNo
nextActionsNo
billClientUrlNo
creationStatusNo
responseGuidanceNo
accountingSetupUrlNo
accountingHandoffUrlsNo

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate readOnlyHint=false, openWorldHint=false, destructiveHint=false, but the description adds significant behavioral context: it explains the excludePersonal behavior (excludes both Personal tag and category), dedup behavior (no duplicate report if no unreported matches), and that the link 'opens the reviewed app flow and does not mean an export occurred'. It also clarifies that the report may include matching expenses not assigned to other reports. This goes beyond the annotations, so a 4 is appropriate.

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?

The description is long but well-structured audio. It starts with the main use case, then adds important notes about tags, examples, return value, duplicate handling, and guidance on when not to call other tools. Each sentence adds substantive guidance beyond the schema. Although it is verbose, it is front-loaded with the most critical information and avoids redundancy with the schema. A 4 is justified because it is detailed yet coherent, not full of fluff.

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?

Given that an output schema exists (context signal indicates it does), the description does not need to explain return values, but it still does mention key outputs (summary, links, filters). It also covers edge cases like duplicate reports. It is complete for a complex tool with 9 parameters and multiple date range variants. The description ensures an agent will not misuse it by calling forbidden redirects or skipping deduplication.

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 input schema has 100% description coverage, so the schema itself documents all 9 parameters. However, the description adds valuable insights: it explains the purpose of tags as grouping layer, the meaning of excludePersonal, and provides specific examples for dateRange variants. It also subtly hints at the purpose of recipientRole. This is above the baseline 3 because it goes beyond merely repeating schema descriptions.

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?

The description clearly states the tool's purpose: 'Create an expense report' with specific criteria (date, client, project, trip, category, or merchant). It also explicitly mentions tags as the grouping layer and contrasts with list_tags. The title 'Create expense report' reinforces the purpose, and the description effectively distinguishes this tool from siblings like get_report_details or send_report_to_accounting.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use guidance: it instructs to call list_tags when the user's intended group is unclear. It also gives clear examples like handling 'all expenses in August except personal' and sets expectations about duplicate reports and when not to call related tools (check_compliance, get_report_details). It explicitly tells the agent to complete the request directly and not call other analysis tools unless the user asks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_reportA
Read-only
Inspect

Get a short-lived direct PDF download for one exact authorized expense report, plus the exact highlighted in-app report link. Use the in-app report for CSV, XLSX, receipt ZIP (when available), comments, invoicing, and other visually reviewed actions. Use list_reports first to find the reportId.

ParametersJSON Schema
NameRequiredDescriptionDefault
reportIdYesReport ID from list_reports

Output Schema

ParametersJSON Schema
NameRequiredDescription
urlsYes
notesYes
reportYes
successYes
expiresAtYes
availableInReportYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context: the PDF is 'short-lived', the report must be 'authorized', and the in-app link is 'exact highlighted'. It also clarifies that the tool only provides URLs, not the actual file contents, which is useful behavioral information beyond the annotations.

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 sentences with zero waste. The core purpose is front-loaded in the first sentence, the alternative use case is in the second, and the prerequisite is in the third. Every sentence earns its place.

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 single-parameter read-only tool with an output schema, the description is complete. It covers what the tool returns (PDF URL + in-app link), when to use it, when not to use it, and the prerequisite. The output schema handles return value details, so nothing an agent needs to call it correctly is missing.

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% and the only parameter (reportId) is described as 'Report ID from list_reports'. The description reinforces this by saying 'Use list_reports first to find the reportId', which adds provenance context beyond the schema. With a single parameter and full schema coverage, the description adds just enough extra meaning.

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?

The description states a specific verb ('Get'), a specific resource ('one exact authorized expense report'), and the exact output format ('short-lived direct PDF download' plus 'exact highlighted in-app report link'). It clearly distinguishes itself from sibling tools like get_report_details and share_report by focusing on export URLs rather than details or sharing workflows.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says when to use this tool ('Use the in-app report for CSV, XLSX, receipt ZIP, comments, invoicing, and other visually reviewed actions') and provides a prerequisite ('Use list_reports first to find the reportId'). This gives clear routing guidance and tells the agent what to do before invoking.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fetchA
Read-only
Inspect

Fetch full details for a specific item returned by search. The id encodes the item type: • 'expense:' — e.g., 'expense:42' for row 42 of the user's Expenses tab • 'report:' — the alphanumeric Firestore document id from search or list_reports, e.g., 'report:FQqDglExofsyyQv7aYy4' Always use the id exactly as returned by search or list_reports — do not invent or modify the trailing portion. Returns the full text content + metadata for the AI to cite.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesItem ID from a previous `search` or `list_reports` call. Format: 'expense:<row>' (integer row number) or 'report:<reportId>' (alphanumeric Firestore doc id, ~20 chars).

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYesEchoed back from the input
urlNo
textYesFull text content for the AI to cite
titleYes
metadataNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds valuable behavioral context: it warns against inventing or modifying the trailing portion of the id, explains the id format rules, and states that the tool returns full text content plus metadata for citation. This goes beyond the annotations and helps avoid misuse.

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?

The description is moderately detailed but well-structured with bullets for the id types. Every sentence serves a purpose: stating the function, explaining formats, giving caution, and indicating return content. It is not excessively verbose, though it could be slightly tighter by merging the caution with the examples.

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?

Given the tool has only one parameter, an output schema exists, and the annotations provide safety context, the description is complete. It explains how to construct/obtain the id, what the id encodes, and what the return value contains (full content + metadata). No additional context is needed for correct invocation.

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 schema already covers the id parameter fully (pattern and description), so the baseline is 3. The description adds further meaning by providing concrete examples for both expense and report id formats, explaining the encoding ('expense:<rowNumber>' vs 'report:<reportId>'), and reinforcing the need to use exact ids from prior calls. This additional guidance compensates beyond schema coverage.

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?

The description clearly states the tool fetches full details for a specific item returned by `search`, using a specific verb and resource. It distinguishes itself by explaining the two id formats (expense and report) and emphasizing that the id must be used exactly as returned, which clarifies its scope as a unified fetch tool.

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?

The description gives clear context on when to use the tool: after a `search` or `list_reports` call. It instructs the agent to use the id exactly as returned and not to modify it. However, it does not explicitly mention alternatives like `get_expense_by_id` or `get_report_details`, so it lacks explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

fix_complianceA
Destructive
Inspect

Safely correct compliance issues on an exact bounded set of recorded expenses. Use only after the user explicitly asks to fix issues found by check_compliance. Use search_expenses to obtain each full expenseId, then pass those exact identities; never select every report row or infer a business purpose, category, or attendee. This compatibility tool uses the same reviewed workflow as correct_expenses: the first call always prepares a grounded preview and makes no change, even if confirm:true arrives early. Show the exact proposed changes and ask once for approval. Only after explicit approval repeat the same operationId, selection, and change with confirm:true. The confirmed result reports applied/conflicted/failed counts and supports status and Undo. For tags/groups use group_expenses; for unsupported or more than 100-row cleanup open https://www.expensebot.ai/review-expenses?source=mcp.

ParametersJSON Schema
NameRequiredDescriptionDefault
undoNoUndo a completed correction within its Undo window.
changeNoExactly one correction. The selected type determines which matching value field is required.
statusNoRead operation status using operationId.
confirmNoOmit/false for preview; true only after explicit approval.
selectionNoExact expenses returned by search_expenses and approved for this bounded correction.
operationIdYesStable idempotency key generated once for preview and reused unchanged.

Output Schema

ParametersJSON Schema
NameRequiredDescription
undoNo
changeNo
statusYes
messageNo
previewNo
successYes
manifestNo
finalAnswerNo
operationIdNo
confirmationNo
responseGuidanceNo
reviewExpensesUrlNo
requiresConfirmationNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint: false, destructiveHint: true), the description discloses the critical two-step workflow: first call always prepares a preview and makes no change even if confirm:true arrives early, explicit approval is required, and the confirmed result reports applied/conflicted/failed counts with status and Undo support. This is rich behavioral context that the annotations alone do not provide.

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?

The description is longer than average, but every sentence earns its place by adding operational detail. It is front-loaded with the purpose, then logically proceeds through usage, workflow, and alternatives. While dense, it is not verbose and remains well-structured.

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?

Given the tool's complexity (6 parameters, nested objects, output schema), the description covers all essential aspects: the two-step approval flow, the need for exact IDs, the constraints on selection and change, the output counts, and the alternatives. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 100% coverage, but the description adds critical semantic constraints: operationId must be stable and reused, selection must be exact from search_expenses and never broadened after preview, and change must be exactly one correction. It also warns against selecting every report row and inferring values, which goes beyond the schema's property descriptions.

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?

The description states a specific verb and resource: 'Safely correct compliance issues on an exact bounded set of recorded expenses.' It also clearly distinguishes itself from siblings by naming correct_expenses as the reviewed workflow, group_expenses for tags/groups, and providing a URL for unsupported cleanup. This leaves no ambiguity about what the tool does or which tool to pick.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs to use only after the user asks to fix issues found by check_compliance, mandates using search_expenses to obtain exact expense IDs, and warns against inferring business purpose, category, or attendee. It also names alternatives for other cases (group_expenses and the external URL), giving clear when-to-use and when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_accounting_integration_statusA
Read-only
Inspect

Check whether an accounting destination is connected and read-only setup state for the owner. Returns the selected organization/company/business, stored connection state, rollout state, and the single setup link for connecting or reconnecting the destination. When an existing ExpenseBot report is available, pass reportId so the link opens that exact report's provider setup control instead of the general Reports setup. This is read-only and never posts accounting data. Agent-driven posting is currently available only for Zoho Books (zoho_books); QuickBooks Online (quickbooks), Xero (xero), Wave (wave), and FreeAgent (freeagent, beta) are accepted here for connection/setup status only and report writesAuthorized=false until their canonical planning path is shared.

ParametersJSON Schema
NameRequiredDescriptionDefault
providerYesAccounting destination provider. QuickBooks Online, Xero, Wave, FreeAgent (beta), or Zoho Books.
reportIdNoOptional existing ExpenseBot report ID. When supplied, setupUrl opens this exact report and highlights the selected accounting provider's setup control.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoPer-provider connection and rollout state.
messageNo
successYes

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 and destructiveHint=false, so the description's claim of being read-only is redundant but consistent. However, the description adds context beyond annotations: it specifies that the tool returns selected organization/company/business, connection state, rollout state, and the setup link null, and notes that posting is not performed. It also mentions that some providers have writesAuthorized=false, which is useful behavioral context. No contradiction.

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?

The description is moderately long but well-structured: it states the core purpose first, then details the return valueschers, then the reportId usage, then the read-only/posting qualifier. It is front-loaded with the most important informationholistic. The latter part about providers is slightly verbose but provides necessary navigation between providers, so it earns its place.

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?

Given the tool has an output schema, the description does not need to list return fields in detail, but it does mention what is returned (organization, connection state, rollout state, setup link). It also clarifies the nuanced provider limitations (e.g., only Zoho Books has writesAuthorized=true). The tool is not overly complex, and with annotations and schema covering safety and parameters, the description provides sufficient context for correct invocation. A 4 is appropriate.

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 the schema already documents both parameters. The description adds a small amount of meaning beyond the schema: for reportId, it explains that the setup link opens the exact report's provider setup control, which is more specific than the schema's 'opens this exact report'. For provider, the description adds that certain providers are accepted for connection onlyholistic. But overall, since the schema already covers the parameters well, a 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?

The description clearly states the tool checks connection status and read-only setup state for an accounting destination, with a specific verb (check) and resource (accounting integration status). It distinguishes itself from siblings like request_accounting_integration (which initiates connection) and get_accounting_push_status (which is about posting), by explicitly mentioning connection/setup state and read-only behavior.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage guidance: when an existing ExpenseBot report is available, pass reportId to open the exact report's setup control. It also explicitly lists which providers are supported for what purpose—agent-driven posting only for Zoho Books, others for connection only. This clearly tells the agent when to use this tool and how it differs from posting-related tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_accounting_push_statusA
Read-only
Inspect

Read the authoritative posting and reconciliation status for one ExpenseBot report at an accounting destination. Use after a timeout or uncertain response before considering any retry. Returns status, submission time, posting mode, posted receipt count, any public error, and whether reconciliation is required. Never re-post a completed report or a report marked needs_reconciliation; show that state to the owner instead. This tool is read-only and owner-account only.

ParametersJSON Schema
NameRequiredDescriptionDefault
providerYesAccounting destination provider used for the prior posting attempt.
reportIdYesExact ExpenseBot report ID from the prior proposal or posting attempt.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false; description adds value by stating the tool is read-only and owner-account only, and by listing the exact fields returned (status, submission time, posting mode, posted receipt count, public error, reconciliation requirement). It also discloses a safety rule (never re-post) which goes beyond annotations. No contradiction with annotations.

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 sentences, each earning its place: purpose, usage trigger, return summary, and constraint. Front-loaded with the primary action and scope. No filler or redundancy.

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 two-parameter read-only tool with an output schema, the description covers the essential use case (checking status after timeout), the return contents, and the critical behavioral rule (don't re-post). It also notes the owner-account restriction. Nothing critical is missing for correct invocation.

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 descriptions already fully document both parameters: provider enum with its purpose and reportId with exact identification requirement. The description does not add extra parameter-level meaning beyond what the schema provides, so a baseline of 3 is appropriate given 100% schema coverage.

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 (read) and resource (posting and reconciliation status for one report at a destination). Distinguishes from siblings like get_accounting_integration_status (integration status) and get_report_details (report details) by specifying 'authoritative' and 'one report'. Clear and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Use after a timeout or uncertain response before considering any retry', giving a clear trigger condition. Also provides an exclusion: 'Never re-post a completed report or a report marked needs_reconciliation; show that state to the owner instead.' This is direct guidance on when to use and what not to do, even though it doesn't name specific alternative tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_client_advance_balancesA
Read-only
Inspect

Read the same per-client advance balances shown in ExpenseBot's Client advances section. Use for questions like 'how much of Acme's advance remains?', 'which client floats are still open?', or 'do I owe a client a refund?'. A negative ledger balance means money remains to refund; a positive balance means the client owes the user. Returns the existing app handoff for Refund leftover or Bill Client. Read-only: never records a refund, creates an invoice, or recomputes the ledger in model prose.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientNameNoOptional client name or canonical Client tag. Omit to list every open balance backed by a recorded client advance.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successYes
balancesNo
homeCurrencyNo

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces this with a strong behavioral guarantee: 'never records a refund, creates an invoice, or recomputes the ledger in model prose.' It also clarifies the meaning of positive/negative balances, which is not in the schema. This goes beyond annotations by explaining what the tool does NOT do, which is valuable for an agent to avoid accidental side effects.

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?

The description is concise but information-dense. It starts with the core purpose, then gives examples, then explains the sign convention, then the return value, and ends with the read-only guarantee. No sentence is redundant; each adds actionable detail. The structure is front-loaded with the main purpose, making it easy for an agent to scan.

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 read-only tool with two optional parameters and an output schema, the description covers the essential usage: how to invoke it, what the balance signs mean, and what it returns. It doesn't discuss error handling (e.g., invalid client name) but the output schema likely covers that. It also doesn't mention rate limits or auth, but given the read-only nature and annotations, this is sufficient. Slightly incomplete because it doesn't note any caveats about data freshness or multi-currency, but overall it's quite 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?

The schema covers both parameters with descriptions (coverage 100%), so the baseline is 3. The description adds extra value: for clientName, it clarifies that omitting it lists all open balances; for clientEmail, it restricts usage to accepted ExpenseBot clients. These clarifications are not in the schema and help the agent understand optionality and constraints. This exceeds the baseline.

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?

The description clearly states the tool reads per-client advance balances, references the exact UI section ('Client advances section'), and provides concrete example questions. It also explains the sign convention (negative means refund, positive means client owes), which removes ambiguity. This distinguishes it from any sibling that might deal with invoices or refunds, though it doesn't name a specific alternative.

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?

The description gives explicit use cases ('Use for questions like...') and explains the optional parameter behavior ('Omit to list every open balance'). It also mentions the return handoff for refund/bill actions. It doesn't explicitly state when not to use it or compare to alternatives, but the examples are clear enough for an agent to select it correctly. A slight gap is the lack of a note about using it vs. other financial tools like get_credits_refunds.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_client_invoiceA
Read-only
Inspect

Get the full financial and delivery summary for one issued client invoice, including subtotal, markup, tax, advance applied, balance due, dates, status, source report, and private Google Doc/PDF/DOCX links when available. Provide invoiceId or invoiceNumber — one is required; invoiceNumber is accepted only when it is unique. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
invoiceIdNoStable invoice ID from list_client_invoices. Required unless invoiceNumber is supplied.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.
invoiceNumberNoHuman invoice number when invoiceId is unavailable; it must identify one unique invoice.

Output Schema

ParametersJSON Schema
NameRequiredDescription
invoiceNoThe invoice record. Absent only on the error branch (not-found), which never carries structuredContent.
messageNo
successYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Description explicitly states read-only behavior, consistent with the annotation, and adds detail about return contents and the 'when available' caveat for private document links.

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 purpose, enumerates the key returned fields, states the input requirement and read-only nature. Dense but efficient; no filler.

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?

The description explains what data is returned, how to identify the invoice, availability caveats, and read-only safety. Combined with schema and annotations, nothing essential is missing for a getter.

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 descriptions already fully document the parameters; tool description reinforces the one-required rule and uniqueness condition but adds little beyond schema. No contradiction.

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?

Uses a specific verb ('Get') and a clear resource ('full financial and delivery summary for one issued client invoice'), and enumerates the returned fields. This distinguishes it from list/prepare/update invoice siblings.

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?

Provides clear guidance on the required identifier, the one-required rule, and the uniqueness constraint on invoiceNumber. Does not explicitly name alternatives, but the usage context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_credits_refundsA
Read-only
Inspect

List card refunds, cashback/rewards, and statement credits that ExpenseBot has already recorded — either as negative expenses or matched against the original charge. Examples: 'did my refund come through', 'show my statement credits', 'was that return recorded'. Returns the most recent items (default 25, newest first); narrow with dateRange. Read-only: it never scans cards, changes review decisions, or adds rows.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum results to return (default 25, max 100).
dateRangeNoOptional open-ended or closed window to narrow results. Supply startDate, endDate, or both; supplied bounds are inclusive YYYY-MM-DD dates.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
creditsNo
messageNo
refundsNo
successYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces this with 'Read-only: it never scans cards, changes review decisions, or adds rows.' This adds behavioral context beyond the annotations, clarifying what the tool does NOT do. It also discloses default behavior (most recent items, default 25, newest first) and the dateRange narrowing option.

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?

The description is compact and front-loaded: it states the resource and scope in the first sentence, provides example queries, and then gives behavioral and parameter context. Every sentence earns its place, and the read-only note is a useful addition without bloat.

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?

The description is complete for a read-only list tool: it covers what is returned, default behavior, narrowing options, and read-only guarantees. The output schema exists, so return values are documented elsewhere. It could mention the clientEmail parameter's purpose, but the schema already covers that, and the description's focus on usage and behavior is sufficient.

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 the schema already documents all three parameters (limit, dateRange, clientEmail). The description adds context for dateRange ('narrow with dateRange') and limit ('default 25, newest first'), but does not add significant meaning beyond the schema. Baseline 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?

The description states a specific verb ('List') and resource ('card refunds, cashback/rewards, and statement credits that ExpenseBot has already recorded'), and clarifies the scope ('either as negative expenses or matched against the original charge'). It also provides example user queries, which makes the tool's purpose immediately recognizable. It distinguishes itself from sibling tools like get_recent_activity or search_expenses by focusing on recorded credits/refunds.

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?

The description gives clear context for when to use the tool ('did my refund come through', 'show my statement credits', 'was that return recorded') and notes it returns recent items with a default limit and dateRange narrowing. It does not explicitly name alternative tools or state when not to use it, but the examples and scope make usage conditions clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_deep_analyticsA
Read-only
Inspect

Run deeper, multi-step analytics on the user's expenses. Use for explanatory questions like 'why did my spending increase' or 'compare Q1 vs Q2'. Takes 10-30 seconds (runs as a background job, polled automatically). Returns: { message, data: { ..., sampleMeta? } } where sampleMeta.isTruncated indicates whether the agent saw the full dataset.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesThe analytics question to answer
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoInline branch: computed analytics, or null when no spreadsheet / no data.
typeNoAsync branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId.
jobIdNoAsync branch only.
messageNoHuman-readable narrative (both branches).
successNoAsync branch only.
responseNoChat alias of message.
pollEndpointNoAsync branch only.
pollIntervalNoAsync branch only: milliseconds.
estimatedTimeNoAsync branch only: seconds.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description enriches this with important operational behavior: it runs as a background job, takes 10-30 seconds, is polled automatically, and may return truncated data via sampleMeta.isTruncated. This goes beyond the structured annotations and gives the agent accurate expectations for latency and result completeness.

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?

The description is three sentences with no fluff: purpose, example use cases, latency/background behavior, and return shape are each packed into distinct, front-loaded statements. Every sentence earns its place and the key operational constraint (10-30 seconds) appears early.

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 complex analytics tool, the description covers purpose, invocation context, asynchronous behavior, and important return metadata (sampleMeta.isTruncated). The schema and output schema handle the parameter and return details, so nothing critical is missing for an agent 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%, so the schema already documents both `query` and the `dateRange` variants in detail. The description reinforces the query semantics with examples but does not add substantial new parameter meaning beyond what the schema provides. This is the appropriate baseline.

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?

The description states a specific verb and resource ('Run deeper, multi-step analytics on the user's expenses') and gives concrete example questions that distinguish it from simpler reporting tools like get_spending_summary or get_pnl. The 'deeper, multi-step' phrasing and explanatory-question use cases make the tool's purpose clear and differentiated.

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?

The description explicitly says 'Use for explanatory questions' and provides examples, giving clear guidance on when to invoke this tool. It does not explicitly name alternatives or state when not to use it, so it stops short of a full when-to-use vs. when-not-to-use matrix, but the context is unambiguous enough for an agent to route correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_expense_by_idA
Read-only
Inspect

Fetch a single expense row by its sheet row number or by its ExpenseBot expenseId (the exact Receipt ID in Column Q). Returns the row's headers + values + a labeled {header → value} map so you can refer to a specific expense the user mentioned. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
expenseIdNoExact full ExpenseBot Receipt ID from Column Q
rowNumberNo1-indexed sheet row (row 1 is headers, so ≥ 2)

Output Schema

ParametersJSON Schema
NameRequiredDescription
expenseNoThe expense record.
successYes
rowNumberNoResolved sheet row for the expense.
reviewExpenseUrlNo

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds that it returns headers + values + a labeled map, which is useful behavioral context beyond the annotations. It also explicitly says 'Read-only' reinforcing the annotation. No contradiction.

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?

Two sentences, front-loaded with the core function and lookup keys, then return format and use case. No wasted words.

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?

The tool has an output schema, so return values are covered. The description explains the two lookup methods and the use case. It doesn't mention edge cases like what happens if both parameters are provided, but that's a minor gap given the schema and 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%, so the schema already documents both parameters well. The description adds the clarification that expenseId is the exact Receipt ID in Column Q, which reinforces the schema but doesn't add much beyond it. Baseline 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?

The description clearly states the tool fetches a single expense row by either sheet row number or ExpenseBot expenseId, and explicitly names the exact Receipt ID in Column Q. It distinguishes itself from sibling tools like search_expenses and get_expense_splits by focusing on a single expense row lookup.

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?

The description implies when to use this tool: when the user mentioned a specific expense and you need its row details. It doesn't explicitly name alternatives or exclusions, but the context of 'refer to a specific expense the user mentioned' gives clear usage context. Sibling tools like search_expenses exist, but the description doesn't explicitly contrast them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_expense_splitsA
Read-only
Inspect

Show how an expense was split across categories, clients, properties, or business vs personal portions. Returns the single parent payment with its nested allocation lines — split lines are never counted as separate expenses, so totals stay correct. Examples: 'how is that expense split', 'what was the business portion of that bill', 'show the allocation for this receipt'. Read-only — splits are edited in ExpenseBot's Review workspace.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax parent expenses to return (default 25, max 100).
dateRangeNoOptional open-ended or closed window to search for split expenses. Supply startDate, endDate, or both; supplied bounds are inclusive YYYY-MM-DD dates.
onlySplitNoReturn only expenses with active splits (default true). Set false to inspect an unsplit Receipt ID.
receiptIdNoOptional Receipt ID for one expense.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
splitsNo
messageNo
successYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint and destructiveHint annotations, the description discloses important behavior: split lines are never counted as separate expenses, so totals stay correct, and the tool returns a single parent payment with nested allocation lines. It also tells the agent that splits are edited elsewhere, which clarifies the tool's non-mutating role.

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?

The description is compact and front-loaded, leading with the core action, then key behavioral nuance, then examples, then a read-only note. No sentence is wasted, and the structure makes the tool's purpose immediately scannable.

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?

The description covers what the tool does, how results are shaped, how totals behave, when to use it via examples, and the read-only context. With a full input schema, annotations, and an output schema present, nothing essential is missing for correct selection and invocation.

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 five parameters are already documented with types, defaults, and constraints. The description adds useful conceptual context but does not need to restate parameter semantics; the baseline of 3 applies because the schema carries the burden.

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?

The description uses a specific verb ('Show') with a clear resource ('how an expense was split') and enumerates the dimensions of splits: categories, clients, properties, business/personal portions. It also clarifies that it returns parent payments with nested allocation lines, distinguishing it from ordinary expense lookup tools like get_expense_by_id or search_expenses.

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?

The description provides natural-language examples ('how is that expense split', 'what was the business portion of that bill') that signal when the tool is appropriate. It also adds the read-only note and directs editing to ExpenseBot's Review workspace, giving clear context, though it does not explicitly name alternative tools or state when not to use this one.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_income_summaryA
Read-only
Inspect

Get income totals, breakdowns, and analytics from the Income tab. Covers Schedule C / T2125 income, Schedule B drill-in (interest, dividends, tax refunds, security deposits), rental income, and per-source / per-payment-method / per-category / per-month / per-tag breakdowns. Schedule-C-style category exclusions match year-end T6 routing (security deposits, refunds excluded from taxable totals). Examples: 'income YTD', 'income by source', 'rental income by property', 'interest income this year', 'dividends YTD', 'tax refunds 2024', 'income this year vs last' (YoY). Supports period comparison phrasing — YoY ('vs last year'), MoM ('vs last month'), QoQ ('Q1 vs Q2'), same-month-prev-year. Returns: { message, data: { total, breakdown?, comparison?, sampleMeta? } }.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoNatural language income question (e.g., 'income YTD by source', 'rental income last month')
groupByNoHow to group the breakdown
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.
incomeTagPrefixNoOptional tag-prefix shortcut (e.g., 'Prop –' for rental income, 'Client –' for client billings, 'Wedding –' for events). When set, the tool filters to income rows tagged with this prefix.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoInline branch: computed analytics, or null when no spreadsheet / no data.
typeNoAsync branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId.
jobIdNoAsync branch only.
messageNoHuman-readable narrative (both branches).
successNoAsync branch only.
responseNoChat alias of message.
pollEndpointNoAsync branch only.
pollIntervalNoAsync branch only: milliseconds.
estimatedTimeNoAsync branch only: seconds.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is set. The description adds meaningful behavioral detail beyond that: the tax-routing exclusion ('security deposits, refunds excluded from taxable totals'), the support for period comparisons, and the exact return shape ({ message, data: { total, breakdown?, comparison?, sampleMeta? } }). These are not in the schema or annotations, giving the agent a clear picture of tool behavior.

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?

The description is dense but efficiently structured: purpose → coverage → exclusions → examples → comparison support → return format. Every sentence contributes new information; there is no filler or repetition. Despite its length, it remains front-loaded and scannable, making it easy for an agent to extract the key facts.

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 tool with four parameters (all optional) and complex breakdown logic, the description is remarkably complete. It specifies the data scope, the breakdown dimensions, the exclusions, the comparison phrases, and the return structure. The presence of an output schema further reduces the need for description-level explanation. Nothing an agent needs to invoke this tool correctly is missing.

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 each parameter (query, groupBy, dateRange, incomeTagPrefix) is already described in the schema. The description adds value through concrete examples ('income YTD by source', 'rental income last month') and explains how the query parameter supports comparison phrasing, which is not fully captured in the schema's generic description. This enriches parameter understanding without redundancy.

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?

The description opens with 'Get income totals, breakdowns, and analytics from the Income tab' – a clear verb, resource, and scope. It then enumerates specific income types (Schedule C/T2125, Schedule B drill-in, rental) and breakdown dimensions (source, payment method, category, month, tag), distinguishing it from sibling tools like get_spending_summary or get_pnl. The examples ('income YTD', 'rental income by property') further cement the tool's purpose.

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?

The description gives clear context on when to use this tool: for any income-related question, with explicit coverage of income categories and breakdown options. It does not explicitly name alternatives or state when NOT to use it (e.g., 'for spending use get_spending_summary'), but the scope is unambiguous enough that an agent can route correctly. The period comparison support (YoY, MoM, QoQ) also clarifies valid usage patterns.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_last_receipt_resultA
Read-only
Inspect

Check the authoritative final outcome of a receipt image/PDF batch submitted with submit_receipt. After submit_receipt returns submissionId, call this tool with that exact ID using the polling interval and time allowance in the submit_receipt response. A small batch allows at least 5 minutes; larger batches allow longer. A pending result is normal and must not trigger a duplicate resubmission. Returns added, duplicate, skipped, or errored verdicts with exact counts and up to 10 processed receipt summaries. found:false is pending and has no terminal verdict; found:true is terminal. On completion, tell the user what happened and show spreadsheetUrl plus reviewExpensesUrl. This is for uploaded receipts; use get_scan_status for Gmail scans. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
submissionIdNoExact submissionId returned by submit_receipt. Strongly preferred because it binds the result to this upload instead of an earlier receipt.
withinSecondsNoFallback lookback window when submissionId is unavailable (30-3600 seconds; default 600).

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
foundYes
stateNoPresent on pending polls for a specific submission.
countsNo
messageYes
successYes
verdictNoTerminal branch only.
receiptsNo
timestampNo
submissionIdNo
spreadsheetUrlNo
reviewExpensesUrlNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, but the description adds rich behavioral context beyond that: it explains the pending vs. terminal semantics (found:false vs. found:true), the verdict types (added, duplicate, skipped, errored), the counts and summaries returned, and that on completion the agent should show specific URLs. It also notes the tool is read-only, but since that's already in annotations, the extra behavioral details carry the weight. No contradiction with annotations.

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?

The description is relatively long but every sentence delivers meaningful guidance (workflow, polling, pending handling, return semantics, URLs to show, alternative tool). It is front-loaded with the core purpose. The only minor redundancy is the final 'Read-only.' which duplicates the annotation, but overall it is well-structured and dense with useful content.

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?

Given the tool's complexity, the description covers all necessary aspects: what it does, how to call it (submissionId and polling), what happens when pending vs. terminal, what the return values are (verdicts, counts, URLs), and when to use an alternative. There is an output schema, but the description already explains the key return semantics in a way the agent can act on. Nothing critical is missing.

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 input schema already covers both parameters with descriptions, so the baseline is 3. The description adds value by clarifying that submissionId must be the exact ID returned by submit_receipt and that the polling interval and time allowance from that response should be used. It reinforces the relationship between the parameters and the submission workflow, slightly exceeding schema information.

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?

The description states a specific verb ('Check') and resource ('authoritative final outcome of a receipt image/PDF batch submitted with submit_receipt'), making the tool's purpose immediately clear. It also explicitly distinguishes itself from the sibling get_scan_status by saying 'use get_scan_status for Gmail scans', which helps the agent differentiate 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 Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to call this tool: after submit_receipt returns a submissionId, using the exact ID and polling interval from the response. It warns that a pending result is normal and should not trigger duplicate resubmission. It also names the alternative tool for Gmail scans, giving a clear exclusion condition.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_mileage_summaryA
Read-only
Inspect

Mileage analytics — totals, breakdowns by month / client / purpose / category, plus deduction framing (cents-per-mile or cents-per-km × distance, country-aware IRS / CRA rates). Examples: 'mileage this year', 'miles driven for Acme', 'mileage by month', 'mileage deduction estimate', 'business miles last quarter'. Supports YoY / MoM / QoQ comparison phrasing. Returns: { message, data: { totalDistance, deductionEstimate?, breakdown?, comparison?, sampleMeta? } }.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoNatural language mileage question (e.g., 'mileage this year', 'miles driven for Acme client')
groupByNoHow to group the breakdown
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successNoPresent only on the error branch (out of scope) / async path.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the read-only, non-destructive safety profile. The description adds genuine behavioral context: country-aware IRS/CRA rates, cents-per-mile/km deduction framing, and YoY/MoM/QoQ comparison handling. It does not discuss edge cases like empty data, but that is a minor gap for a read-only summary tool.

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?

The description is compact, front-loads the core purpose, and packs example queries, grouping dimensions, comparison support, and return shape into two sentences worth reading. There is no filler, repetition, or tautology.

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 a rich output schema, full parameter documentation, and read-only annotations, the description only needs to cover scoping and use conditions. It does so with practical examples, comparison semantics, and country-aware deduction behavior. It could still be more explicit about sibling-tool routing or how query, groupBy, and dateRange interact, but nothing essential is missing for correct invocation.

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 the baseline is 3; the description adds useful example queries and return-shape context. However, it mentions breakdowns 'by client' while the groupBy enum exposes 'tag' rather than 'client', creating a mild mismatch between prose and schema. The dateRange guidance is helpful but largely restates schema intent.

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?

The description opens with a specific action-target pair—'Mileage analytics'—and enumerates totals, breakdown dimensions, and deduction framing, making the tool's scope unmistakable. The mileage focus clearly distinguishes it from sibling reporting tools like get_income_summary and get_spending_summary.

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?

Concrete natural-language examples ('mileage this year', 'miles driven for Acme', 'mileage deduction estimate') give clear context for when this tool applies. It also mentions comparison phrasing support, but it does not explicitly state when to prefer an alternative analytics sibling or what conditions rule this tool out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_monthly_books_reviewA
Read-only
Inspect

Month-end summary of the user's books for one calendar month: income recorded, money spent, net, top spending categories and merchants, plus alerts for anything unusual that month. Examples: 'how did last month go', 'close out my books for June', 'monthly review', 'what did I make and spend in May'. Defaults to the last completed month. Figures come from the user's own recorded data; advisory notes are estimates, not tax advice.

ParametersJSON Schema
NameRequiredDescriptionDefault
periodNoCalendar month in YYYY-MM format. Defaults to the last completed month.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, covering the safety profile. The description adds valuable context: figures come from the user's own data, advisory notes are estimates and not tax advice, and it defaults to the last completed month. These disclosures go beyond the annotations and are relevant for an agent deciding whether to invoke this tool.

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?

The description is concise, front-loaded with the core summary, and includes examples and a caveat in a compact form. It avoids redundancy and stays focused. While it could be slightly more structured, it is efficient and easy to scan.

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 an output schema present and annotations covering safety, the description adequately covers what the tool does, its default behavior, and a caveat about data sources. It does not mention edge cases like missing data for the month, but that is not critical given the output schema and overall completeness. The description provides sufficient context for an agent to call it 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 coverage is 100%, so both parameters (period and clientEmail) are fully documented in the input schema. The description reiterates the default for period but adds no new semantic detail beyond what the schema provides. Per the rubric, the baseline of 3 is appropriate when the schema already handles parameter documentation.

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?

The description states a specific verb and resource: provides a month-end summary of the user's books for a calendar month, enumerating contents (income, spending, net, categories, merchants, alerts). It distinguishes itself from sibling tools like get_pnl and get_income_summary by focusing on a comprehensive monthly overview. The inclusion of example queries reinforces the tool's purpose.

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?

Clear context is provided via example queries ('how did last month go', 'close out my books for June'), indicating when to use this tool for month-end reviews. However, it does not explicitly name alternative tools or state when not to use it, so it lacks explicit exclusions. The context is strong enough for an agent to infer appropriate usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_per_tag_pnlA
Read-only
Inspect

Per-tag P&L — revenue, cost, profit, and margin grouped by tag (per-client, per-property, per-event, per-realtor-deal). Requires both income AND expense rows to be tagged with matching labels. Common tag-prefix shortcuts: 'Prop –' (rentals), 'Client –' (client billings), 'Wedding –' (events), 'Realtor –' (real estate deals). Examples: 'per-tag P&L this year', 'profit by client', 'profit by property', 'profit on the Smith wedding', 'per-client P&L this year vs last' (YoY). Supports YoY / MoM / QoQ comparison phrasing. Margin renders as multiplier in loss territory. Defaults to year-to-date if no date range given.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoNatural language per-tag P&L question
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.
tagPrefixNoOptional prefix to limit which tags are bucketed (e.g., 'Prop –' for properties only, 'Client –' for clients only). When omitted, all tags are included.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoInline branch: computed analytics, or null when no spreadsheet / no data.
typeNoAsync branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId.
jobIdNoAsync branch only.
messageNoHuman-readable narrative (both branches).
successNoAsync branch only.
responseNoChat alias of message.
pollEndpointNoAsync branch only.
pollIntervalNoAsync branch only: milliseconds.
estimatedTimeNoAsync branch only: seconds.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint=true and destructiveHint=false annotations, the description discloses key behaviors: the requirement for matching tags on income and expense rows, that margin renders as a multiplier in loss territory, and that the tool defaults to year-to-date when no date range is given. These are valuable behavioral details not captured in annotations.

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?

The description is long but well-organized: it leads with the core purpose, then prerequisites, tag prefixes, examples, and behavioral quirks. Every sentence adds value, and the structure is front-loaded with the most important information. It is slightly verbose but not padded.

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 tool with three parameters (including a complex dateRange schema) and an output schema, the description covers the main use cases, preconditions, defaults, and output quirks. Nothing essential is missing for an agent to invoke it correctly.

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 schema already provides descriptions for all parameters (100% coverage), but the description adds significant contextual meaning: it explains tag-prefix shortcuts (e.g., 'Prop –' for properties), provides example natural-language queries for the query parameter, and clarifies the default behavior of the dateRange parameter. This enriches the schema beyond its raw definitions.

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?

The description clearly states the tool produces per-tag P&L (revenue, cost, profit, margin) grouped by tag, and explicitly lists the tag categories (client, property, event, realtor-deal). It includes concrete example queries that make the purpose unmistakable and distinguishes it from broader P&L tools like get_pnl.

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?

The description provides explicit example queries that indicate when to use this tool (e.g., 'profit by client', 'per-tag P&L this year') and states the prerequisite that both income and expense rows must be tagged with matching labels. It does not name sibling tools to avoid, but the examples and focused scope imply the appropriate usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_pnlA
Read-only
Inspect

Compute Profit & Loss (P&L / net income / margin) by combining the Income tab with expense tabs. Examples: 'am I profitable this year', 'P&L for Q1', 'net income last quarter', 'what's my margin', 'P&L this year vs last' (YoY). Supports period comparison — YoY, MoM, QoQ, same-month-prev-year. Margin renders as multiplier in loss territory ('expenses 5.4× revenue') so the user gets a readable signal instead of '-436.9% margin'. Returns: { message, data: { revenue, expenses, netIncome, margin, comparison?, sampleMeta? } }.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoNatural language P&L question (e.g., 'P&L for Q1 2025', 'am I profitable')
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoInline branch: computed analytics, or null when no spreadsheet / no data.
typeNoAsync branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId.
jobIdNoAsync branch only.
messageNoHuman-readable narrative (both branches).
successNoAsync branch only.
responseNoChat alias of message.
pollEndpointNoAsync branch only.
pollIntervalNoAsync branch only: milliseconds.
estimatedTimeNoAsync branch only: seconds.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly=true and destructiveHint=false, so the safety profile is established. The description adds meaningful behavior beyond that: it combines Income and expense tabs, supports comparison modes, and discloses the unusual loss-territory margin rendering ('expenses 5.4× revenue'). This is useful behavioral context that the annotations do not provide.

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?

The description is front-loaded with the core action, then supplies illustrative examples, supported comparisons, an edge-case behavior, and the return shape in a compact, structured way. Every sentence contributes operational value with no filler or repetition of schema details.

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 natural-language analysis tool with three parameters, the description covers the core calculation, query phrasing, comparison capabilities, the loss-territory margin behavior, and the return structure. Since an output schema exists, return values do not need further explanation, and nothing an agent needs to invoke the tool correctly appears to be 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%, so the schema already documents query, dateRange, and clientEmail thoroughly. The description's example phrases add some color to the query parameter, but it does not materially extend the semantic information already present in the schema. Baseline 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?

The description starts with a specific verb and resource: 'Compute Profit & Loss (P&L / net income / margin) by combining the Income tab with expense tabs.' It also lists concrete question phrasings and clearly distinguishes this from the sibling get_per_tag_pnl by framing it as the aggregate P&L tool. An agent can tell what it does and when it applies 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?

The description gives a clear situational context through example queries ('am I profitable this year', 'P&L for Q1', 'net income last quarter') and states the supported period comparisons (YoY, MoM, QoQ). It does not explicitly name alternatives or say when not to use this tool, so it stops short of a 5, but the usage scope is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_recent_activityA
Read-only
Inspect

Show what the user (or their AI assistants) has recently done in ExpenseBot via this MCP server: which tools were called, when, with what arguments, and whether they succeeded. This is a log of assistant TOOL CALLS, not the processing history of a document. Useful for questions like 'what did I do this week' or 'which tools has my assistant run', and to give the user transparency into AI-assisted actions. Returns the most recent N entries from the audit log (default 20, max 100).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
actionIdNoOptional: filter to a single tool/action name
sinceDaysNoOnly show actions from the last N days (default 7)

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
actionsYes
successYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only and non-destructive nature, and the description adds valuable context about what the log contains (tool calls, arguments, timestamps, success/failure). It also states the default limit and maximum, which are not in annotations. Since annotations cover safety, the description provides additional behavioral detail without contradicting them.

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?

The description is three sentences with no fluff. The primary purpose is stated first, followed by a clarifying distinction and then usage context and parameters. Every sentence earns its place, and the length is proportional to the tool's complexity.

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?

The tool has an output schema, so return format is covered. The description covers purpose, use cases, data scope, and parameter defaults. It does not explicitly mention pagination or error cases, but for a read-only audit log with a limit parameter, those are not critical. It is complete enough for correct invocation.

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 67% (actionId and sinceDays have descriptions, limit does not). The description compensates for limit by stating 'default 20, max 100', which is not in the schema. However, it does not add beyond the schema for actionId or sinceDays, so overall it meets baseline without enriching beyond what is already clear. A 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?

The description clearly states a specific verb ('Show') and resource (recent activity log) and explicitly distinguishes it from document processing history. It names the underlying content (tool calls, arguments, success/failure) and directly differentiates from the sibling 'trace_document' by clarifying it is not processing history. This 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 Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete use cases: 'what did I do this week' and 'which tools has my assistant run', and states it provides transparency into AI-assisted actions. It also clarifies it is not for document processing history, though it does not explicitly name an alternative tool. It could be stronger by pointing to specific siblings, but the guidance is clear and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_report_detailsA
Read-only
Inspect

Get full details of a specific expense report including all expenses, totals, and compliance status. Use only when the user explicitly asks to inspect an existing report's details. Never call this as a preflight or follow-up to creating, sharing, or billing from a report; those tools already return the required result and links.

ParametersJSON Schema
NameRequiredDescriptionDefault
reportIdYesThe report/spreadsheet ID
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.
userRequestYesThe user's exact request asking to inspect this report. Do not paraphrase or invent diagnostic intent.

Output Schema

ParametersJSON Schema
NameRequiredDescription
reportYesThe full stored report record.
successYes

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, establishing the tool as a safe read operation. The description adds the scope of returned content and a strict anti-preflight rule, but does not disclose additional behavioral traits such as error conditions, permissions, or data freshness. It is consistent with annotations, so no contradiction.

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?

Two sentences: the first states the purpose, the second states usage constraints. There is no filler, and the core function is front-loaded before the usage warnings.

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?

The tool has an output schema, so return values are covered. All three parameters are documented in the schema, and the description provides clear when-to-use and when-not-to-use guidance. There are no missing pieces for an agent to call it 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%, with each parameter having a meaningful description (reportId, clientEmail, userRequest). The tool description itself does not add parameter-level context, so it meets the baseline of 3 for schema-documented parameters.

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?

The description names a specific verb ('Get'), a resource ('a specific expense report'), and the scope of details (expenses, totals, compliance status). This distinguishes it from sibling tools like list_reports (which lists reports) and get_expense_by_id (which targets a single expense).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use the tool ('only when the user explicitly asks to inspect an existing report's details') and when not to use it ('Never call this as a preflight or follow-up to creating, sharing, or billing'), and points to alternatives that already return the required results. This leaves no ambiguity for an agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_scan_statusA
Read-only
Inspect

Check the authoritative status of the user's Gmail receipt scans. Returns the active scan lock, the same live phase and item progress shown by ExpenseBot's in-app status pill, queued or attention-needed years, completed calendar years, current merchant/category exclusions, and recent outcomes. Call when the user asks whether a scan is running, finished, stuck, or what it is doing. When complete, show the returned spreadsheetUrl or reviewExpensesUrl; when setup or reconnection is needed, show gmailScanUrl. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
lockNoScan-lock state (active, startedAt, ageSeconds, dispatchComplete, pendingProcessingCount).
statusNoScan lifecycle state.
messageNo
successYes
latestScanNoMost recent scan outcome (success, emailsFound, emailsTagged, timestamp).
gmailScanUrlNo
scanInProgressNo
spreadsheetUrlNo
reviewExpensesUrlNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces this with 'Read-only.' It goes beyond the annotations by detailing the fields returned (spreadsheetUrl, reviewExpensesUrl, gmailScanUrl) and instructing which to display under which condition, plus noting the data mirrors the in-app status pill. No contradictions with annotations.

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?

The description is well-structured: it opens with the core purpose, then lists returned data, then gives usage triggers and follow-up actions, and closes with 'Read-only.' Every sentence adds value; it is compact without being terse, and the most critical info (purpose and when to call) is front-loaded.

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 read-only status tool with no parameters and an output schema (which presumably documents the return structure), the description covers the essential agent needs: what it returns, when to call, and how to act on the results. It could mention edge cases (e.g., no active scan) but these are likely implied by the output schema, so it is sufficiently 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?

The tool has zero parameters, so the description carries no parameter burden. The baseline for 0 parameters is 4, and the description adds no unnecessary parameter info. Schema coverage is trivially 100% (empty schema), so this score 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?

The description opens with a specific verb and resource: 'Check the authoritative status of the user's Gmail receipt scans.' It enumerates the exact returned data (scan lock, live phase, item progress, years, exclusions, outcomes) and explicitly ties it to a status-pill context, which clearly differentiates it from siblings like scan_gmail (which initiates scans) and get_last_receipt_result (which returns a single result).

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?

The description gives an explicit trigger: 'Call when the user asks whether a scan is running, finished, stuck, or what it is doing.' It also provides follow-up actions (show spreadsheetUrl/reviewExpensesUrl when complete, gmailScanUrl when setup needed). However, it does not explicitly state when NOT to use it or name alternative tools, so it lacks exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_spending_summaryA
Read-only
Inspect

Summarize the user's recorded expenses with totals and breakdowns by category, merchant, month, tag, source, or payment method. Supports date ranges, period comparisons, and total, count, or average metrics. Read-only. Returns: { message, data: { total, breakdown?, comparison?, sampleMeta? } }.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoNatural language question (e.g., 'how much did I spend in March', 'top merchants this quarter')
metricNo
groupByNo
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.
categoriesNoOptional configured expense categories to include in the summary.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoInline branch: computed analytics, or null when no spreadsheet / no data.
typeNoAsync branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId.
jobIdNoAsync branch only.
messageNoHuman-readable narrative (both branches).
successNoAsync branch only.
responseNoChat alias of message.
pollEndpointNoAsync branch only.
pollIntervalNoAsync branch only: milliseconds.
estimatedTimeNoAsync branch only: seconds.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered by structured data. The description adds a compact return shape ('Returns: { message, data: { total, breakdown?, comparison?, sampleMeta? } }'), which gives some behavioral context beyond annotations. It does not describe auth requirements, rate limits, or edge cases, but the annotations cover the important safety dimension.

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?

The description is three sentences long, front-loaded with the core capability, then covering options, read-only status, and return shape. There is no filler or redundant elaboration; every clause contributes to an agent's understanding.

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?

After accounting for the existing output schema and annotations, the description fills the main gap by documenting the enum parameters and the overall purpose. It lacks context about natural-language query usage (e.g., that query can be a free-form question) and does not mention the clientEmail restriction, but these are already in the schema. The main omitted guidance about which sibling to use instead is captured in the usage_guidelines dimension.

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 description coverage is 67%, and the two undocumented parameters (metric and groupBy) are clear from the description: it lists 'category, merchant, month, tag, source, or payment method' and 'total, count, or average metrics', mapping directly to the enum values. This adds real semantics beyond the schema. Other params (query, dateRange, categories, clientEmail) are adequately described in the schema.

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 states a specific verb and resource: 'Summarize the user's recorded expenses with totals and breakdowns...' It also enumerates grouping dimensions and metrics, making the intent concrete. It does not explicitly name sibling alternatives like get_income_summary or get_pnl, but the 'expenses' scope and read-only nature implicitly distinguish it from those.

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?

No explicit when-to-use or when-not-to-use guidance is given. The description mentions capabilities ('Supports date ranges, period comparisons...') but does not clarify when to choose this rather than sibling tools like get_income_summary, get_pnl, or get_deep_analytics. With a large sibling list, the absence of route-to-alternative guidance is a significant gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_spreadsheet_urlA
Read-only
Inspect

Return the user's master ExpenseBot Google Sheet plus authenticated ExpenseBot workspace links, each with a label and a description of when to use it. Use this when the user asks to open, view, check, or edit their spreadsheet; review expenses or income; manually scan Gmail; reconcile; connect or manage a bank/credit card; open Automation Hub or General Settings; create or open reports; or asks where a submitted receipt went. Choose and show the one or two links relevant to the request instead of listing the entire catalog. After a receipt submission, prefer Review expenses plus the Google Sheet. After an income write, prefer Review income plus the Sheet. For a Gmail scan or connection request, use the Scan Gmail link, which opens the existing Gmail scanning interface. Bank/card requests use the Reconcile link; configuration requests use the returned Automation Hub or General Settings link. Category, G/L, and account-code requests use Category management; client, project, and trip groups use Group management; questions about what counts as Personal use Personal rules. For client billing setup, use the returned clientBillingHandoffs instead of giving a generic dashboard tour: manageClients creates or manages the client list, tagReadyExpenses opens Review Expenses filtered to blank or default-Business rows, and createClientReport opens report creation by group after expenses have been assigned. Choose the one next step that matches the user's current state. If the user names a client and an exact expense scope and asks the assistant to do the work, use search_expenses and group_expenses instead; show its grounded preview and require explicit confirmation before changing any rows. When the user asks to choose receipt images from Google Photos, use the returned Google Photos link; it opens the existing authenticated picker and handles any required Google consent in ExpenseBot. When they ask where ExpenseBot stores receipt files, return the Drive folder link only when it is available; never invent or request a folder ID. For a complete, unambiguous cash expense or mileage trip, use the direct write tool. Use the returned Manual expense link for multiple entries, credits/refunds, detailed tax/tip entry, per diem, incomplete details, or visual review. Use the Mileage and travel link for route calculation, mileage settings, repeated trips, calendar/rideshare imports, per diem, or visual review. These links open the existing reviewed app forms. When the user wants to import income from a screenshot, PDF, or CSV but no attachment is available in chat (or the review is visually complex), use the returned Import income links — they open the existing Add Income importer, which parses the file and shows every row for review before anything is saved. Team setup requests use the returned role-aware Team setup handoff: eligible solo business owners open Add teammates, while existing team owners and co-admins open License Manager. If the handoff says owner access is required, explain that instead of presenting a broken link. Complex or visually reviewed report requests use the returned Create report link. Read-only; this tool does not create or modify spreadsheet rows.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
messageYes
successYes
reportsUrlYes
dashboardUrlYes
gmailScanUrlYes
spreadsheetIdYes
spreadsheetUrlYes
reviewIncomeUrlYes
reviewExpensesUrlYes
gmailActionNeededUrlYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces this with 'Read-only; this tool does not create or modify spreadsheet rows.' Beyond that, it discloses non-obvious behavioral traits: only the one or two relevant links should be shown rather than the whole catalog, the Drive folder link must not be invented ('never invent or request a folder ID'), and if a handoff requires owner access, explain instead of presenting a broken link. With annotations lowering the bar, this level of added context is excellent.

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?

The description is long (a single dense paragraph) and could be improved with bullets or paragraph breaks, which would make it easier for an agent to consult. However, it is front-loaded with the core purpose and general when-to-use trigger, and nearly every sentence carries unique routing information for a handoff that touches many workflows. Acceptably sized at the upper bound, but not a model of concise prose.

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 zero-parameter tool with a large routing surface, the description covers an extraordinary number of cases: spreadsheet access, Gmail scans, bank reconciliation, configuration, category/group management, Google Photos, Drive-storage questions, client billing handoffs, team setup, imports, and reports. It also anticipates failure modes (using owner-access handoffs, never inventing folder IDs) and points to alternative sibling tools when a different action is required. Alongside the provided output schema, the agent has everything it needs to call and interpret this tool correctly.

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 disambiguate and the schema trivially covers 100% of parameters. Per the rubric, a zero-parameter tool starts at baseline 4, and the description adds no param-related meaning because no params exist. The routing context it provides is rich, but it belongs to usage guidance rather than parameter semantics.

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?

The first sentence states a specific verb ('Return') and resource ('master ExpenseBot Google Sheet plus authenticated ExpenseBot workspace links'), and clarifies that each link carries a label and a use-case description. This clearly frames the tool as a link-dispatch/router and distinguishes it from siblings like scan_gmail or submit_receipt, which actually perform those operations rather than returning links to them. The only minor friction is that the tool name (get_spreadsheet_url) undersells its broader role, but the description itself removes that ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description is effectively a decision tree: it states explicit triggers ('Use this when the user asks to open, view, check, or edit their spreadsheet'), gives per-scenario link preferences ('After a receipt submission, prefer Review expenses plus the Google Sheet'), and names when-not-to-use alternatives ('If the user names a client and an exact expense scope..., use search_expenses and group_expenses instead'). It even distinguishes selection rules for Gmail, bank/card, category, group, and billing requests. This is the strongest possible usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_subscription_auditA
Read-only
Inspect

Subscription audit — wraps the Subscription Auditor engine to find recurring charges, duplicates, price increases, and trial-conversion suspects in the user's expenses. Examples: 'recurring subscriptions', 'duplicate subscriptions', 'price increases', 'trial conversions', 'subscriptions over $20/month'. Returns: { message, data: { recurring, duplicates, priceIncreases, trialConversions, totalMonthlyCost, sampleMeta? } }.

ParametersJSON Schema
NameRequiredDescriptionDefault
focusNoNarrow the audit to a single category (default: all)
queryNoNatural language subscription question (e.g., 'find duplicate subscriptions', 'price increases this year')
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
messageNo
successNoPresent only on the error branch (out of scope) / async path.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The structured annotations already say readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description meaningfully adds that the tool wraps a 'Subscription Auditor engine' and enumerates the output categories, which helps the agent predict behavior. It does not contradict any annotation.

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?

The description is compact and front-loaded: first sentence states the purpose, then a short example list, then a brief return signature. Every part earns its place; no verbose filler or circular wording.

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?

Combined with a rich input schema and an existing output schema, the description supplies the tool's engine, domain keywords, natural-language examples, and return shape. There is no material gap that would prevent an agent from choosing and calling the tool 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%, so baseline is 3. The description's natural-language examples give useful phrasing for the `query` parameter, but it does not clarify the relationship between `focus` and `query` (e.g., whether query overrides focus or they combine), which is a real semantic gap beyond the schema.

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 resource ('subscriptions') and a clear verb ('audit/find'), enumerates the exact categories it returns (recurring, duplicates, price increases, trial conversions), and gives natural-language examples. It does not explicitly contrast itself with sibling tools like get_spending_summary or get_deep_analytics, 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 Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The examples ('recurring subscriptions,' 'duplicate subscriptions,' 'subscriptions over $20/month') establish a clear trigger context for an agent deciding to invoke this tool. It does not name alternatives or exclusion conditions, but the type of question this tool handles is unmistakable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_trip_suggestionsA
Read-only
Inspect

Show ExpenseBot's current high-confidence Trip Intelligence proposals from Review Expenses. Read-only: never groups, tags, creates reports, or writes to the spreadsheet. Each proposal returns strict YYYY-MM-DD dates, evidence, locations, and the exact Receipt IDs with expected current tags. Do not infer a client/project from geography. When nextAction is present, use exactly its group_expenses params with confirm:false, show the canonical preview, then ask for explicit confirmation before any write. Never send confirm:true from this read result alone. In accountant clientEmail mode this tool can read accepted clients but may return no executable nextAction; hand off to Review Expenses or the owner's own assistant connection to apply.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum high-confidence proposals to return (default 3).
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countNo
messageNo
successYes
proposalsNoRead-only trip proposals; accepting one continues through group_expenses.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, but the description goes well beyond that: it reinforces the read-only nature with concrete examples of what is never done, specifies the exact return format (strict YYYY-MM-DD dates, evidence, locations, Receipt IDs, expected tags), and discloses a non-obvious rule: 'Never send confirm:true from this read result alone.' It also exposes the accountant-mode limitation. These details add significant behavioral context that annotations alone do not provide, with no contradiction.

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?

The description is dense but every sentence earns its place. It leads with the primary purpose, then layers read-only constraints, return format, the critical nextAction workflow, and a mode-specific caveat. There is no filler or redundancy; the structure is logical and the most safety-critical guidance ('Never send confirm:true') is emphasized. The length is justified by the complexity of the tool's behavior.

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?

Given the tool's complexity—read-only retrieval with a conditional write handoff and accountant-specific behavior—the description covers all necessary aspects: what it returns, what the agent should do with nextAction, what not to do (infer client from geography, send confirm:true), and when to hand off. The presence of an output schema reduces the need to explain return values, and the description fills the remaining gaps about usage policy and edge cases.

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% for both parameters (limit and clientEmail), each with clear descriptions and constraints. The tool description does not add any meaning about the parameters themselves—it only contextualizes how to use the returned nextAction, which is about output handling, not parameter semantics. Per the rubric, with high schema coverage, the baseline is 3, and the description does not elevate it further.

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?

The description opens with a precise statement of what the tool does: it shows ExpenseBot's high-confidence Trip Intelligence proposals from Review Expenses. It clearly distinguishes itself from write operations by explicitly listing what it never does (groups, tags, creates reports, writes to spreadsheet) and provides a concrete handoff path (Review Expenses or owner's assistant) that separates it from sibling tools. The purpose is unambiguous and specific.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use and how-to-proceed instructions: it states the tool is read-only, and when nextAction is present, exactly which parameters to use (group_expenses with confirm:false), how to present results (show canonical preview), and when to ask for confirmation before any write. It also details the accountant clientEmail mode and directs the agent to hand off when no executable nextAction is returned. This is thorough, actionable guidance that removes ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

group_expensesA
Destructive
Inspect

Group an exact set of recorded expenses for a client, project, trip, job, or other user-named purpose. Examples: 'group my Mexico meals for client Rob', 'put these Vegas expenses under the Vegas project', or 'group these for client Rob and create a report'. The user does not need to know about tags: ExpenseBot resolves the requested name against existing groups and proposes creating one only when needed. Use exact expenseId values returned by search_expenses. A grounded preview is automatic for every bulk request; the user does not need to ask for one. First call with confirm omitted/false, show the returned exact rows, count, totals, proposed group, exclusions, and conflicts, then ask for approval. Only after explicit user approval, repeat the same operationId and selection with confirm:true. A premature confirm:true is converted to preview. When the request includes a report, set createReport:true on that confirmed group_expenses call and use its report result; do not run a separate broader create_report query. For 'without personal expenses', set excludePersonal:true; ExpenseBot removes Personal-tagged and Personal-category rows before preview so their Personal marker is never overwritten. The confirmed operation returns exact report and Bill Client links. Expenses already assigned to another ordinary report are excluded; if none remain, no duplicate report is created and the result links to Reports instead. Keep the user-facing response concise and do not add unsolicited tax or substantiation advice. Do not call check_compliance, get_report_details, or tax/deductibility tools before or after this workflow unless the user explicitly asks for that separate analysis. In user-facing prose call the destination a group, not a tag. Treat preview totals as provisional; after confirmation use only the terminal result's exact count, total, and currency without reconciling it against the preview. A returned Bill Client URL opens the reviewed billing handoff and does not mean an invoice was created, sent, or confirmed. Sharing remains a separate share_report action with recipient confirmation.

ParametersJSON Schema
NameRequiredDescriptionDefault
undoNoUndo a completed grouping within its undo window.
groupNoThe user-named destination group to apply to every eligible selected expense.
statusNoRead operation status using operationId.
confirmNoOmit/false for preview; true only after explicit approval.
selectionNoExact expenses returned by search_expenses and approved for this bounded operation.
operationIdYesStable idempotency key generated once for the preview and reused unchanged.
reportTitleNoOptional title when createReport is true; otherwise ExpenseBot derives one from the group.
createReportNoCreate a report from the exact eligible grouped expenses.
excludedTagsNoExisting groups to exclude before preview and grouping.
approveNewGroupNoTrue only when the preview says a new group is required.
excludePersonalNoExclude Personal-tagged and Personal-category expenses from both grouping and the exact report.
excludedCategoriesNoExpense categories to exclude before preview and grouping.

Output Schema

ParametersJSON Schema
NameRequiredDescription
undoNo
groupNo
reportNo
statusYes
messageNo
previewNo
successYes
manifestNo
candidatesNo
exclusionsNo
reportsUrlNo
finalAnswerNo
operationIdNo
confirmationNo
suggestedTagNo
creationStatusNo
responseGuidanceNo
reviewExpensesUrlNo
requiresConfirmationNo
requiresNewGroupApprovalNo

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate destructiveHint=true, and the description is exceptionally transparent about side effects: preview is automatic, premature confirm converts to preview, personal expenses are excluded before preview, existing report assignments cause exclusion, and Bill Client URL does not confirm invoice. Adds critical behavioral context beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but dense and front-loaded with the core purpose and examples. Every sentence adds operational detail, but it feels overly verbose for an agent, risking cognitive overload. Some redundancy exists in the workflow description, though it is informative.

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?

Given the tool's complexity (12 params, nested objects, destructive mutation), the description covers the full workflow, parameter usage, exclusions, edge cases, and output interpretation. The output schema exists, so return values are likely documented there. Highly complete for safe invocation.

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 the description adds limited parameter-specific detail. It does clarify the confirm parameter's dual preview/confirmation role and that selection must not be broadened, but the schema already documents all fields accurately. 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?

The description clearly states the tool groups expenses under a user-named purpose, with concrete examples. It distinguishes from siblings by noting it's for grouping (not creating reports or compliance checks), though it does not explicitly name a specific sibling for comparison.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit when-to-use and when-not-to-use guidance: instructs to use exact expenseIds from search_expenses, clarifies that check_compliance and get_report_details should not be called unless explicitly requested, and details the two-step preview/confirm workflow. Strong contrast with create_report and share_report.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_categoriesA
Read-only
Inspect

List the user's configured expense categories and billing accounts. Use this BEFORE calling tools that need a category (add_cash_expense, add_mileage_entry, create_report) so you pass the user's actual category names, not guesses. Returns the live list from their spreadsheet.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
successYes
categoriesYesExpense categories for the user.
billingAccountsNoBilling/card accounts, when configured.

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint, safeHint, and destructiveHint, so the read-only behavior is covered. The description adds a meaningful behavioral detail: it returns the 'live list from their spreadsheet', clarifying that freshness depends on the user's spreadsheet state. That is useful beyond the annotations.

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?

The description is three short sentences with no filler, and the most decision-critical information (what it lists and when to call it) comes first. The final sentence adds live-data context without redundancy.

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 zero-parameter read-only listing tool, the description covers the what, the when, the why (avoid guesses), and the data source. The annotations already carry the safety profile, and the output schema exists, so nothing an agent needs to correctly invoke it is missing.

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?

There are zero parameters and the schema is fully described (100% coverage) as an empty object, so the baseline is 4. The description focuses on the output value, communicating what the returned categories 'are the user's actual category names' rather than guesses, which supports the purpose but is not about input semantics.

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?

The description lists a specific verb ('list') and precise resource ('the user's configured expense categories and billing accounts'). It distinguishes itself from sibling tools such as list_income_categories by explicitly limiting to expense categories and adding billing accounts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly tells agents when to use it: 'Use this BEFORE calling tools that need a category' and gives concrete sibling examples (add_cash_expense, add_mileage_entry, create_report). This goes beyond general timing and directly maps to concrete workflows.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_client_invoicesA
Read-only
Inspect

List the user's issued client invoices (accounts receivable) — who owes them money, how much, and when it is due. Examples: 'which invoices are outstanding', 'what does Acme still owe me', 'any overdue invoices', 'how much am I waiting to get paid'. status accepts 'active' (default), 'open', 'overdue', 'needs_review', 'paid', 'void', 'superseded', or 'all'. Returns invoice numbers, status, totals by currency, delivery state, and private document links. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax invoices to return (default 25, max 100).
statusNoFilter by invoice status (default active/outstanding).
clientNameNoOptional: exact client name (case-insensitive).
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
successYes
invoicesYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context by listing the returned fields (invoice numbers, status, totals by currency, delivery state, private document links) and the default status behavior, which goes beyond the annotations without contradicting them.

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?

The description is well-structured: it opens with the core purpose, then gives examples, then details status options and return fields. Each section earns its place, though the examples and enumeration could be trimmed without loss. It is appropriately sized for a tool with four optional parameters.

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?

Given the tool's complexity (four optional parameters, an output schema, and a clear read-only role), the description covers the essential context: what it lists, how to filter, and what it returns. The limit parameter is documented in the schema, and the output schema handles return details. Nothing critical is missing for an agent to call it 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%, so the baseline is 3. The description does not add extra meaning for the parameters beyond what the schema already documents; it only reiterates the status enum values and default, which are already in the schema. No additional semantic value is provided.

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?

The description states a clear verb ('list') and resource ('the user's issued client invoices'), with a plain-language explanation of accounts receivable and concrete example queries. It clearly distinguishes from sibling tools like get_client_invoice (singular) by framing itself as a listing operation.

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?

The description gives example phrasings that map to typical use cases and enumerates the status filter options, providing clear context for when to use this tool. It does not explicitly name alternatives or say when not to use it, but the examples imply the intended scope, so this is strong but not explicit on exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_income_categoriesA
Read-only
Inspect

List ExpenseBot's fixed income tax categories. Unlike Expense Accounts, these are not user-configured. Use this BEFORE calling add_income so you pass an exact canonical category instead of guessing.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
notesNo
legacyNoDeprecated income categories still accepted on read.
successYes
categoriesYes

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide read-only and non-destructive hints. The description adds that the categories are fixed and not user-configured, which is a useful behavioral fact but largely reinforces the existing openWorldHint=false annotation. There is no contradiction.

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?

Two sentences, first is front-loaded with the core purpose, second provides usage context and the rationale for the action. Every sentence earns its place with no waste.

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 zero-parameter list tool with an output schema present and annotations covering read-only/destructive behaviors, this description is complete. It tells the agent when to use it, what it is, and why it matters, so nothing essential is missing.

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?

This tool has zero parameters and 100% schema description coverage. The description does not need to add parameter detail, so the high baseline of 4 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?

Clearly identifies the specific action (list) and resource (ExpenseBot's fixed income tax categories), distinguishing it from user-configured Expense Accounts. The mention of income tax and the unmodifiable nature makes the purpose unambiguous.

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?

Explicitly instructs to call this tool before add_income and warns against guessing categories, indicating when to use it. It contrasts with Expense Accounts without naming the exact sibling tool, so it stops short of a fully explicit when-not/alternative tool list.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_reportsA
Read-only
Inspect

List the user's expense reports with pagination. Filter by status (All, Draft, Submitted, Shared). Each exact report includes its app, Bill Client, and accounting handoff URLs. Use the matching accounting URL only when the user explicitly asks to send or export that report; the app keeps organization, mapping, preview, and final confirmation.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoOne-based results page to return.
limitNoMaximum reports to return on this page.
filterNoOptional report-status filter; All returns every authorized status.All
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
pageNo
limitNo
filterNo
reportsNoPresent when the user has reports.
successYes
creationStatusYesProvenance of the listing, e.g. "existing_only".
responseGuidanceNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint, the description discloses that results embed accounting handoff URLs and warns against acting on them unless explicitly asked. The note that 'the app keeps organization, mapping, and final confirmation' clarifies the tool's limits, adding meaningful behavioral context.

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?

The description is short and front-loaded with the core action, followed by filter options, return contents, and a safety caveat. There is minor ambiguity in 'each exact report' and the phrase 'the app keeps organization, mapping, and final confirmation,' but overall it is efficient.

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 listing tool with an output schema, the description covers its purpose, filtering, pagination, relevant returned data, and an important usage caveat. It does not specify when to prefer sibling tools, but that is not essential for a straightforward list 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%, with page, limit, filter, and clientEmail all described. The description adds only high-level context about pagination and status, and does not meaningfully extend the parameter explanations beyond what the schema already provides.

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?

The description opens with a specific verb and resource: 'List the user's expense reports with pagination.' It is unambiguous against siblings like add_expense or export_report because the focus is purely read-only listing. The mention of status filtering and returned URLs further distinguishes it from detail or send operations.

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 gives a clear operational caveat—use the accounting URL only when the user explicitly asks to send/export—but it does not explicitly route an agent away from or toward sibling tools such as get_report_details or export_report. The filtering and pagination context is useful, yet alternative selection guidance is missing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tagsA
Read-only
Inspect

List the user's configured groups. ExpenseBot stores clients, projects, project codes, properties, and trips as tags (for example 'Client: Acme', 'Vegas Trip', or 'Property: 123 Main'). Use this when the user asks 'what groups/projects/clients do I have?' and before filtering, grouping, or reporting when the intended existing name is unclear.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
tagsYesClient / project / trip groups (Column K values).
successYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the main safety concern is covered by structured data. The description adds clarity about what data is listed (clients, projects, project codes, properties, trips), but it does not disclose any deeper behavioral traits such as pagination, response limits, or auth requirements. This is adequate though not exceptional.

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?

Three sentences, front-loaded with the core responsibility, followed by helpful examples and usage timing. Nothing is wasted, though the example list could be slightly shorter without loss of value.

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 zero-parameter read-only listing tool, the description fully covers what it returns conceptually, how the data is modeled, and when to invoke it. The output schema exists, so return structure does not need to be spelled out in the description. Minor ambiguity about whether all tags are returned or just top-level groups is not significant.

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 and schema coverage is 100%, so there are no parameter semantics to explain. The description compensates by making the meaning of the tool's resource domain clear, which is more useful here than parameter documentation would be.

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 ('List the user's configured groups') and explains what counts as a group by giving concrete tag examples like 'Client: Acme' and 'Property: 123 Main'. It is clearly differentiated from sibling list tools such as list_categories and list_reports because it focuses on user-configured tags representing clients/projects/trips, though it does not explicitly name an alternative.

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?

The description gives explicit use-case guidance: use it when the user asks 'what groups/projects/clients do I have?' and before filtering/grouping/reporting when an existing name is unclear. It lacks an explicit when-not-to-use clause naming alternatives, but the context it provides is sufficient for an agent to make an appropriate selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mark_client_invoice_paidA
Destructive
Inspect

Mark an issued client invoice as paid after explicit confirmation. Requires a strict calendar-valid paidDate in YYYY-MM-DD format. This updates the accounts-receivable invoice record only; it never creates or moves an Income row. Record the actual payment separately or link an existing Income row.

ParametersJSON Schema
NameRequiredDescriptionDefault
paidViaNoOptional payment method or source, such as bank transfer or check.
paidDateYesCalendar-valid payment date in YYYY-MM-DD format.
invoiceIdYesStable invoice ID from list_client_invoices.
paidAmountNoOptional amount received.

Output Schema

ParametersJSON Schema
NameRequiredDescription
statusYes
messageYes
paidViaYes
successYes
paidDateYes
invoiceIdYes
paidAmountYes
invoiceNumberNo
incomeRowCreatedYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false and destructiveHint=true, indicating a write/destructive operation. The description adds meaningful scope: it specifies the update is limited to the invoice record and explicitly states what it does not do (create/move Income rows). It also enforces a strict date format requirement. This goes beyond the annotations and provides useful behavioral context.

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?

The description is three concise sentences with no filler. The primary action and key constraint are front-loaded, and each sentence earns its place by adding scope or exclusion information. It is well-structured for quick parsing.

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?

Given that an output schema exists and the tool has only four parameters, the description covers the essential context: the action, the required date format, the scope of the update, and what it does not do. It does not explain the meaning of 'explicit confirmation' in workflow terms, but that is a minor gap given the output schema and annotations provide the rest.

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 all four parameters are already described in the schema. The description reinforces the paidDate format ('strict calendar-valid paidDate in YYYY-MM-DD format'), but this largely duplicates the schema's format and description. It adds no new meaning to the parameters beyond what the schema provides, so a baseline 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?

The description states a specific action ('Mark an issued client invoice as paid') and clearly differentiates it from income-recording siblings by noting it 'updates the accounts-receivable invoice record only; it never creates or moves an Income row.' This distinguishes it from add_income and similar tools, making the purpose unambiguous.

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?

The description gives clear context: it is for marking an invoice paid 'after explicit confirmation' and explicitly directs the user to 'Record the actual payment separately or link an existing Income row.' This implies the tool is not for recording income itself. It doesn't name a specific alternative tool, but the guidance is sufficient to route an agent appropriately.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

parse_expenseA
Read-only
Inspect

Parse a natural language expense description into structured fields. Does NOT add the expense — just returns the parsed fields for review. Example: "Lunch at Chipotle $15.50 today" → {merchant: "Chipotle", total: 15.50, ...}

ParametersJSON Schema
NameRequiredDescriptionDefault
textYesNatural language expense (e.g., "Coffee at Starbucks $6.50 yesterday")

Output Schema

ParametersJSON Schema
NameRequiredDescription
successYes
expensesYes
categoryNamesYes
validationErrorsYes

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 and destructiveHint=false, and the description reinforces and adds context by stating the tool does not add anything and only returns parsed fields. It goes beyond the annotation in explaining that the result is for review, but it does not discuss failure modes or edge cases; the annotation bar is low here, making this more than strong enough.

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?

The description is compact: two clear sentences and an example. It front-loads the core purpose, adds the key behavioral caveat, and illustrates the input/output transformation. There is no redundant phrase or irrelevant detail.

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 a single parameter, a full output schema, and annotations that signal read-only safety, the description is fully sufficient. It tells an agent what the tool does, what input it takes, what kind of output to expect, and that it has no side effects. No critical information needed 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%; the schema already describes the `text` parameter with its own example. The description adds another example and shows the mapping to output, but it does not enrich parameter semantics beyond what the schema already conveys, so the baseline of 3 is maintained.

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?

The description opens with a specific verb and resource ('Parse a natural language expense description') and immediately clarifies it does NOT add the expense, distinguishing it from sibling add/search tools. The example illustrates a concrete merchant/total/date format, leaving no ambiguity about its 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?

The description clearly frames the tool as a parse-and-review step, stating 'Does NOT add the expense' and 'just returns the parsed fields for review.' It gives context for when to use it but does not explicitly name an alternative add tool such as add_cash_expense, so the routing is clear but not directly explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

prepare_client_invoiceAInspect

Prepare a client invoice from a saved ExpenseBot report without creating it. Reads canonical report rows, allocates a unique invoice number, verifies the client ledger identity and advance, and returns exact totals plus a short-lived preparationId. Call this first, show the preview to the user, then call create_client_invoice after explicit confirmation. It reserves the invoice number and preview for 30 minutes but creates no invoice, document, Income row, email, or payment.

ParametersJSON Schema
NameRequiredDescriptionDefault
taxPctNoTax percentage applied after markup and custom line items; use 0 for no tax.
reportIdYesSaved ExpenseBot report ID to invoice.
taxLabelNoTax label such as HST, GST, or VAT.
issueDateYesCalendar-valid invoice date in YYYY-MM-DD format.
markupPctNoMarkup applied only to rebilled expense rows.
clientNameYesFull client or business name shown on the invoice.
receiptIdsNoOptional exact report receipt IDs. Defaults to every current report expense.
billToEmailNoOptional client email printed on the invoice. This does not send email.
paymentTermsNoInvoice due terms. Defaults to the client's billing profile or net30.
clientAddressNoOptional billing address printed in the invoice's Bill To section.
invoiceNumberNoOptional custom invoice number. ExpenseBot allocates one when omitted.
advanceAppliedNoVerified client advance to apply against this invoice.
customLineItemsNoOptional fee/service lines. They are taxed but never marked up.
mentionSupportingReceiptsNoWhen true, note on the invoice that supporting receipts are available.

Output Schema

ParametersJSON Schema
NameRequiredDescription
previewYes
successYes
expiresAtYes
preparationIdYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already state destructiveHint=false and openWorldHint=false, but the description adds the crucial contract: it reserves the invoice number and preparationId for 30 minutes, returns no persistence, and explicitly lists what it does not create ('no invoice, document, Income row, email, or payment'). This is substantive behavioral transparency beyond the annotations.

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?

The description is dense but every sentence earns its place: purpose, behavior, workflow, and side-effect limitations are all front-loaded and concise. It avoids padding while covering a multi-step, state-reserving operation.

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?

Given the lifecycle complexity (requirements parameters, short-lived reservation, and linking to create_client_invoice), the description gives the exact sequence and side-effect model needed to call it correctly. Output schema already covers return values, so missing return details are not a gap.

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?

Although the schema already documents all 14 parameters thoroughly (100% coverage), the description enriches the meaning of key parameters by explaining canonical report rows, unique invoice number allocation, client ledger verification, advance verification, and preparationId. That moves it beyond a bare schema restatement.

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?

The description clearly states a specific action ('Prepare a client invoice'), the resource ('a saved ExpenseBot report'), and the key constraint ('without creating it'). It also distinguishes itself from the sibling create_client_invoice by defining the prepare-then-confirm workflow, so an agent can select this tool rather than its sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit ordering and conditions: 'Call this first, show the preview to the user, then call create_client_invoice after explicit confirmation.' This directly tells the agent when to use this tool and when the alternative applies, leaving no ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

process_gmail_receiptsAInspect

Process specific Gmail emails as receipts. Pass Gmail message IDs and they'll be converted to PDF, extracted by AI, and added to the user's expense spreadsheet. Max 25 emails per request. Requires Gmail to be connected in ExpenseBot settings.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailIdsYesGmail message IDs to process as receipts
accountEmailNoOptional: which Gmail account to use (for users with multiple linked accounts)

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
errorNo
messageYes
successYes
emailCountNo
processInfoNo
submissionIdNo
processedItemsNo
spreadsheetUrlNo
reviewExpensesUrlNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate readOnlyHint=false and destructiveHint=false, consistent with the write operation described (adding to a spreadsheet). The description adds valuable behavioral context beyond annotations: the pipeline (converted to PDF, AI-extracted, added to sheet), the 25-email cap, and the prerequisite of a connected Gmail account. It doesn't address idempotency or duplicate handling, but given the moderate annotations, the additional detail justifies a 4.

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?

The description is two sentences with zero filler. It front-loads the purpose and directly states input, outcome, limit, and prerequisite. Every clause is necessary and informative, making it highly concise and well-structured.

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 tool with a simple 2-parameter schema, an output schema present, and annotations covering safety and world effects, the description covers all essential usage aspects: input type, processing steps, limit, and prerequisite. The output format is likely deferred to the output schema. Minor gaps like error handling or idempotency are not critical given the existing structured data, so a 4 is appropriate.

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 descriptions already cover both parameters (emailIds and accountEmail) with 100% coverage, giving a baseline of 3. The description adds the key constraint 'Max 25 emails per request' for emailIds and the prerequisite of a connected Gmail, enriching parameter usage. It also clarifies accountEmail's optionality implicitly via 'Requires Gmail to be connected'. This extra guidance raises the score.

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 clearly states the verb 'process', the resource 'specific Gmail emails', and the outcome (converted to PDF, AI-extracted, added to expense spreadsheet). It also specifies the input format (Gmail message IDs) and a hard limit (max 25). While it doesn't explicitly name sibling tools like scan_gmail or scan_gmail_years, the focus on 'specific' emails and message IDs makes the purpose distinct enough. However, an explicit contrast would push it to 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?

The description provides practical constraints: it requires Gmail to be connected and limits to 25 emails per request. It also implies usage by passing specific message IDs, which differentiates from broader scan tools. However, there is no explicit when-to-use versus scan_gmail/scan_gmail_years, and no 'when not to use' guidance. Thus, it gives context but leaves alternative selection to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

request_accounting_integrationAInspect

Request support for an accounting package only after checking ExpenseBot's reviewed direct and import-file destinations and finding no matching package. Do not use this for a listed or Beta destination, a general compatibility question, or without the exact package name. This is a confirmation-gated write: after the user approves, it creates one deduplicated request bound to the authenticated ExpenseBot account and emails ExpenseBot's internal team. It does not create an integration or make the requested package immediately available. On accepted or previously recorded requests, tell the user ExpenseBot will email them within one week with an update.

ParametersJSON Schema
NameRequiredDescriptionDefault
packageNameYesExact accounting package requested by the user.

Output Schema

ParametersJSON Schema
NameRequiredDescription
messageYes
successYes
duplicateYes
packageNameYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnlyHint=false, destructiveHint=false), the description details the behavior: it is a confirmation-gated write that creates a deduplicated request bound to the account, emails the internal team, does not create an integration, and includes post-acceptance user communication. This fully discloses side effects and limitations.

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?

The description is dense but each sentence serves a purpose: usage condition, exclusions, behavior, and outcome. It is front-loaded with the primary condition. Slightly verbose but well-structured and free of redundancy.

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 confirmation-gated write with an output schema, the description covers the workflow, side effects, and expected user communication. It clearly states what it does not do (create integration) and what happens on accepted requests, leaving no critical gaps for an agent to invoke it 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?

The schema already describes packageName as 'Exact accounting package requested by the user' with 100% coverage. The description reinforces exactness and the requirement for an exact name but does not add significant new meaning beyond the schema's existing description.

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?

The description clearly states the tool's purpose: request support for an accounting package, with explicit conditions for when it applies. It distinguishes itself from siblings by specifying not to use it for listed/Beta destinations or general compatibility questions, making its scope unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use and when-not-to-use guidance: only after checking reviewed destinations and finding no match, and explicitly excludes listed/Beta destinations, general compatibility questions, and missing exact package names. It also notes it is confirmation-gated, which is a critical usage constraint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scan_gmailAInspect

Trigger a background Gmail scan to discover and process receipt emails from the last ~60 days (default). Runs asynchronously — returns immediately, user gets an email summary when done. Like clicking "Find Receipts in Gmail" in the UI. For whole PAST YEARS (e.g. 2023, or 2020-2022) use scan_gmail_years instead; to check a scan's progress use get_scan_status.

ParametersJSON Schema
NameRequiredDescriptionDefault
endDateNoOptional: explicit end date (YYYY-MM-DD)
startDateNoOptional: explicit start date (YYYY-MM-DD) instead of lookbackDays
accountEmailNoOptional: which Gmail account to scan
lookbackDaysNoHow many days back to scan (default 60, max depends on subscription)

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
statusNo
messageNo
successYes
_metadataNo
sessionIdNo
orchestratedNo
submissionIdNo
scanInProgressNo
spreadsheetUrlNo
reviewExpensesUrlNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses key behavioral traits not visible in annotations: it runs asynchronously, returns immediately, and sends an email summary when complete. This substantially informs the agent's expectations beyond the readOnlyHint/openWorldHint/destructiveHint fields.

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?

The description is concise, front-loaded with the core action and async behavior, and uses three focused sentences. The UI analogy and sibling routing add value without redundancy.

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?

Given the output schema exists and there are no required parameters, the description covers what an agent needs: the action, async nature, follow-up status tool, and alternative for longer ranges. Minor gaps like interaction between startDate and lookbackDays are already addressed in the 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%, so the schema already documents all four parameters. The description adds a useful default context ('last ~60 days (default)') but does not materially expand parameter meaning beyond what the schema provides.

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?

The description states a specific verb and resource ('Trigger a background Gmail scan to discover and process receipt emails') with a time scope ('last ~60 days'). It clearly differentiates from siblings by naming scan_gmail_years and get_scan_status, which serve different scopes and purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says when to use this tool versus alternatives: use scan_gmail_years for whole past years and get_scan_status to check progress. It also clarifies the asynchronous behavior so an agent knows not to expect results in the immediate response.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scan_gmail_yearsAInspect

Scan one or more COMPLETED PRIOR years of the user's Gmail for receipts (e.g. years:[2023] or years:[2020,2021,2022]). Long-running background job: the first eligible year starts immediately and the rest queue, running one at a time (each full year typically takes a couple of hours; the user can close the app). ALWAYS call first WITHOUT confirmStart to preview which years are eligible, then ask the user to confirm, then call again with confirmStart:true. For receipts from the last ~60 days use scan_gmail instead. To check how a scan is going, use get_scan_status. The current in-progress year cannot be year-scanned.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearsYesCompleted prior years to scan, e.g. [2020, 2021]. Max 10.
accountEmailNoOptional: which connected Gmail inbox to scan (multi-inbox users). Defaults to the primary.
confirmStartNoOmit or false = preview only (no scan starts). Must be exactly true to start scanning.

Output Schema

ParametersJSON Schema
NameRequiredDescription
accountNo
messageYes
previewNo
successYes
eligibleNo
gmailUrlNo
scanningNo
notEligibleNo
queuedYearsNo
startedYearNo
alreadyQueuedNo
alreadyScannedNo
archiveThroughYearNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that this is a long-running background job, that years queue and run one at a time, that each year takes a couple of hours, that the user can close the app, and that the current in-progress year cannot be year-scanned. These behavioral traits go well beyond the annotations (readOnlyHint=false, openWorldHint=true, destructiveHint=false) and give the agent critical operational context.

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?

The description is dense but every sentence earns its place: scope, timing, queueing behavior, call sequence, sibling routing, and an exclusion constraint. It is front-loaded with the core purpose and immediately gives the critical usage pattern. No fluff.

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?

Given the tool's complexity (long-running, queued, multi-step confirmation), the description covers everything an agent needs: what it does, when to use it, how to invoke it safely, what to expect, and how to monitor it. The output schema exists, so return values need no description. This is 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 schema already documents all three parameters. The description adds meaning by explaining the confirmStart preview-then-confirm workflow and the constraint that the current in-progress year cannot be scanned. It doesn't add much about accountEmail, but the schema covers it. Baseline 3 plus the confirmStart workflow context justifies a 4.

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?

The description clearly states the tool scans completed prior years of Gmail for receipts, with a specific verb and resource. It distinguishes itself from scan_gmail by noting the ~60-day boundary, and from get_scan_status for monitoring. The title 'Scan past years of Gmail' reinforces the purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use guidance: use for completed prior years, use scan_gmail for last ~60 days, use get_scan_status to check progress. It also gives a precise call sequence: first call without confirmStart to preview, then confirm with the user, then call with confirmStart:true. This is exemplary usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_expensesA
Read-only
Inspect

Search and filter the user's expenses. Returns matching expense rows from their spreadsheet. Filter by category, merchant, date range, amount, or tags. Results are paginated: when hasMore is true, call again with nextCursor and the same filters. Do not split a date range into repeated overlapping searches.

Use the optional query parameter for deterministic natural-language recall over merchant, city/location, Notes (including receipt items, delivery source, payer, and Business purpose), Tag, and category. Each matching result includes matchedFields and a short matchReason so you can explain why it was selected. When several rows plausibly match, a disambiguation list is returned; each option carries the exact expenseId. Structured filters (categories, merchants, dateRange, tags, minAmount, maxAmount) combine with the query using AND semantics. Each result includes expenseId, the exact durable Receipt ID required by update_expense.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoFilter by tags
limitNoResults per page (default 20, maximum 50)
queryNoOptional natural-language recall over the user's existing expense fields (merchant, city/location, Notes including receipt items, delivery source, payer, and Business purpose, Tag, category). Deterministic case-insensitive matching — no embeddings or model classifiers. Combine with structured filters using AND semantics. Examples: 'Tribeca restaurant', 'Bodewell project hardware store', 'client dinner note'.
cursorNoOpaque nextCursor returned by the previous search_expenses page. Reuse the same filters; never construct or edit this value.
dateRangeNoTime period filter. Use exactly one variant — pick the shape that matches the user's phrasing.
maxAmountNoMaximum expense amount
merchantsNoFilter by merchant names (e.g., ['Uber', 'Starbucks'])
minAmountNoMinimum expense amount
categoriesNoFilter by expense categories (e.g., ['Travel', 'Meals'])
hasReceiptNoWhen true, return only expenses with a receipt link. When false, return only expenses without one.
clientEmailNoClient account email. Accountants may use this only for an accepted ExpenseBot client.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYesRows matched by the filters.
totalYesSum of the matched set in home currency.
hasMoreNo
messageNo
expensesYesMatching expense rows, newest first, paginated.
pageInfoNo
nextCursorNoOpaque signed continuation; reuse with identical filters.
queryAppliedNo
totalMatchedNoPresent for free-text searches.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnlyHint/destructiveHint annotations by disclosing pagination semantics, deterministic natural-language matching, AND-combination of structured filters, disambiguation behavior, and the fact that each result includes an exact durable Receipt ID needed by update_expense. It also warns against splitting date ranges and constructing cursors, which helps agents avoid known misuse.

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?

The description is dense but efficient: the first sentence states the core purpose, and each subsequent clause adds necessary behavior or important operational constraints. Avoidable redundancy is minimal, and the length is justified by the complexity and the number of behaviors an agent must know to call the tool correctly.

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?

Given the tool's complexity — 11 parameters, pagination, disambiguation, mixed structured and natural-language filtering — the description covers all critical aspects: pagination flow, cursor reuse, AND semantics, deterministic recall, and the significance of expenseId/Receipt IDs. The output schema exists, so it need not describe exact return formats, and the description still goes beyond the schema to cover usage pitfalls.

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?

The input schema already has 100% description coverage, so the baseline is satisfied by the schema. The tool description mostly summarizes or restates filter semantics already present in the schema, such as the query combining with structured filters via AND and the pagination cursor behavior. Because the description adds little new meaning beyond the schema's rich per-parameter descriptions, it earns the baseline but not more.

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?

The description clearly states the specific operation: 'Search and filter the user's expenses' and explicitly says it returns matching expense rows from their spreadsheet. This clearly distinguishes it from add, update, report, and tax-related sibling tools. The scope is precise: it is for retrieving already-recorded expenses, not for creating or modifying them.

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?

The description gives concrete usage instructions: paginate with hasMore/nextCursor, reuse the same filters, do not split a date range into overlapping searches, and expect a disambiguation list when multiple rows plausibly match. It does not explicitly name alternatives or when-not-to-use conditions, but the context and procedural guidance are clear enough to guide an agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_knowledgeA
Read-only
Inspect

Search ExpenseBot's complete product and help knowledge base. Use this before guessing when the user asks how a feature works, what ExpenseBot supports, or needs setup, billing, Gmail, scan, report, workflow, or troubleshooting instructions. Set fullAnswer:true on the first call when the user asks for complete, detailed, or step-by-step instructions. Use the default excerpt mode for discovery and quick answers; if an excerpt is truncated, call again with fullAnswer:true before presenting complete instructions. Each result has a stable id.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of ranked matching articles to return (1-10).
queryYesSearch terms
fullAnswerNoSet true on the first call for complete, detailed, or step-by-step instructions. Leave false for discovery or quick-answer excerpts.

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultsYes
successYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the read-only behavior is known. The description adds value beyond annotations by explaining the excerpt-vs-fullAnswer behavior, the truncation retry guidance, and that results are stable. These are meaningful behavioral details, though it doesn't touch on any edge cases or limitations.

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?

The description is concise, front-loaded with the primary purpose, and every sentence earns its place. It covers what, when, and how to advance detail level without repetitive or filler content. The distinction between 'discovery'' and 'complete instructions' is compact and clear.

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 a read-only annotation, an output schema, and 100% schema parameter descriptions, the structure already carries a lot. The description completes the remaining decisions: when to use it, how to get full answers, when to retry, and the stability property. No significant gap remains for the agent.

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% and the schema already documents query, limit, and fullAnswer. The description adds semantic value by contextualizing fullAnswer: set true on the first call when complete/detailed instructions are needed, and use excerpt mode for discovery. This gives agents a decision rule beyond the schema's bare default of false.

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?

The description names a specific action and resource: 'Search ExpenseBot's complete product and help knowledge base.' It enumerates typical use categories (setup, billing, Gmail, scan, report, workflow, troubleshooting), which makes the tool's purpose unambiguous and clearly sets it apart from expense-search siblings like 'search_expenses' or the more generic 'search'.

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?

The description explicitly states when to use the tool: 'Use this before guessing when the user asks how a feature works, what ExpenseBot supports, or needs setup, billing, Gmail, scan, report, workflow, or troubleshooting instructions.' It also distinguishes between excerpt mode and fullAnswer mode with a retry rule. However, it does not explicitly say when NOT to use it or name sibling alternatives, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

send_report_to_accountingAInspect

Review and then post an ExpenseBot report to the owner's accounting destination. STEP 1: call with provider, reportId, and optional mode/mappings, without confirm. The server reads the live report and destination, applies Omit/Personal/split/date/currency rules, checks Zoho bank-feed matches, and returns the complete proposal plus proposalId. NOTHING is posted in step 1. Show the complete proposal and ask for approval. STEP 2: call with only provider, proposalId, and confirm:true. The server posts only the frozen, account-bound proposal, revalidates live state, and rejects changed reports or mappings. Never add mapping fields to the confirmation call. Owner accounts only; acting for a client is not supported. Agent-driven posting is currently available only for Zoho Books (zoho_books); QuickBooks Online, Xero, Wave, and FreeAgent are intentionally not accepted by this tool yet because their previews cannot freeze/revalidate the canonical provider plan that shareReport executes. Use those providers' web flows until they satisfy the full push contract.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNoStep 1 only (Zoho Books): automatic document treatment, paid expenses, or bills.
confirmNoStep 2 only: true posts the exact staged proposal. No other options may change.
providerYesAccounting destination provider. Agent-driven posting is currently available only for Zoho Books.
reportIdNoStep 1 only: ExpenseBot report ID owned by the signed-in account.
proposalIdNoStep 2 only: proposalId returned by the read-only preview.
forceRepushNoStep 1 only: explicitly include disclosed uncertain prior outcomes in the frozen proposal.
taxMappingsNoStep 1 only: observed tax-rate string to live destination tax ID overrides.
accountMappingsNoStep 1 only: ExpenseBot category to live destination account ID overrides.
reportingTagMappingsNoStep 1 only: ExpenseBot tag to live destination reporting-tag option.

Output Schema

ParametersJSON Schema
NameRequiredDescription
phaseYes
unitsNo
countsNo
createdNo
successYes
providerYes
reportIdNo
expiresAtNo
proposalIdYes
finalAnswerNo
organizationNo
matchedExistingNo
omittedExpensesNo
idempotentReplayNo
responseGuidanceNo
confirmationContractNo
confirmationQuestionNo
confirmationRequiredNo
skippedAlreadyPushedNo
reconciliationRequiredNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations indicate readOnlyHint=false and destructiveHint=false, but the description adds critical behavioral context: step 1 is read-only (nothing posted), step 2 posts only the frozen proposal after revalidation. It also discloses the provider limitation and the fact that client-account posting is unsupported. This goes far beyond what annotations provide, making the tool's behavior fully transparent.

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?

The description is lengthy but well-organized, front-loading the purpose and then clearly delineating steps. Every sentence adds essential information—step details, provider limitations, and warnings. There is no fluff; the length is justified by the tool's complexity. The structure with step labels enhances readability.

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?

Given the tool's complexity (9 parameters, two-step process, nested objects) and the presence of an output schema, the description covers all necessary aspects: the workflow, step-specific parameters, provider restrictions, and safety checks. It tells the agent exactly what to do and what not to do, making it complete for correct invocation.

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 schema has 100% description coverage, so the baseline is 3. The description adds step-specific associations (e.g., mode is step 1 only, confirm is step 2 only) and explains the purpose of mappings and forceRepush. This goes beyond the schema's basic descriptions, though the schema already covers the parameters well. The added workflow context justifies a 4.

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?

The description clearly states the tool's purpose: to review and then post an ExpenseBot report to the owner's accounting destination. It specifies the two-step process and distinguishes it from siblings like share_report by emphasizing the posting action. The verb 'post' and resource 'report' are specific, and the mention of 'review' and 'approval' clarifies the workflow.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit step-by-step usage instructions: step 1 without confirm, step 2 with confirm and only proposalId. It explicitly states which providers are supported (Zoho Books only) and directs users to use web flows for others. It also warns against adding mapping fields to the confirmation call, leaving no ambiguity about when and how to use the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

share_reportA
Destructive
Inspect

Share one existing expense report after confirmation. Default to reviewer: they can open and edit that report's Google Sheet, inspect receipts, comment, approve, or request changes, but cannot act for the owner or use accounting integrations. Use accountant only when the user explicitly asks for ongoing accounting access; it creates the established accountant relationship and broader report-management workflow.

ParametersJSON Schema
NameRequiredDescriptionDefault
reportIdYes
recipientsYes
recipientRoleNoUse reviewer for report-only approval. Use accountant only for explicit ongoing accountant access.reviewer

Output Schema

ParametersJSON Schema
NameRequiredDescription
messageYes
successYes
sharedWithYes
finalAnswerNo
recipientRoleYes
responseGuidanceNo

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate mutating and destructive behavior, but the description adds valuable context: it specifies what the reviewer can and cannot do (open/edit the Google Sheet, comment, approve, but not act for owner or use accounting integrations) and explains that the accountant role creates a broader relationship. This goes beyond the annotations without contradicting them.

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?

The description is two sentences and front-loaded with the core action. It packs role behavior into a compact but readable form. No unnecessary filler, though it could be slightly more concise without losing nuance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the main decision point (role selection) thoroughly, and an output schema exists so return values are not needed. However, it does not explicitly clarify the semantics of reportId and recipients beyond what the schema shows, and it leaves questions like whether sharing is reversible or what happens on re-share unanswered. Given the tool's mutation and destructive annotation, a bit more detail would be helpful.

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 only 33% (only recipientRole has a description). The description compensates well for recipientRole by explaining when to use each value, but it does not explicitly describe reportId or recipients beyond the context of 'sharing a report' and the email format implied by the schema. This is a partial compensation.

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 clearly states the tool shares an existing expense report, which is a specific verb and resource. It differentiates the reviewer and accountant roles, though it does not explicitly contrast with sibling tools like send_report_to_accounting. The purpose is unambiguous and useful for an agent.

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?

The description gives explicit guidance on when to use each role: default to reviewer unless the user explicitly requests ongoing accountant access. This helps the agent decide between recipientRole values, but it does not mention when to prefer this tool over alternatives like send_report_to_accounting, which is a minor gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

submit_receiptAInspect

Submit a photo or PDF of a receipt for processing. Covers requests phrased as 'log this', 'log this receipt', 'save this receipt', 'expense this', or 'add this to my expenses', including when the user simply shares a photo of a receipt or invoice. The receipt image is validated, uploaded to cloud storage, and processed by AI to extract vendor, amount, date, tax, and category. The expense appears in the user's spreadsheet in about 1-3 minutes, and longer for PDFs or large batches. Handles images and PDFs, mixed together in one batch.

TO SEND FILES (preferred, and required for PDFs): call this tool with filesToUpload listing every file the user gave you. It returns one signed upload URL per file. Upload them ONE AT A TIME with an HTTP PUT, telling the user which file you just finished and how many remain, then call this tool ONCE with uploadRefs for all of them — that processes the whole set as a single batch, like the ExpenseBot web app. Do not call this tool once per file.

Use the photo parameter for one image or PDF attached in ChatGPT. MCP clients that cannot supply file references may use photoBase64 for one small image; use the upload flow for large files or batches.

Optional note and tag values use the same receipt metadata path as ExpenseBot's camera, file uploader, and forwarded-email intake. The note is stored in the Notes column (L); the tag is stored in the Tag column (K). Batch defaults apply to every file, and each uploadRefs item may override either value for that file.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagNoBatch-level project or client tag applied to every expense row. Individual files may override it. Stored in the Tag column (K) through the same path as the web receipt uploader.
noteNoBatch-level context note applied to every file in the upload. Individual files may override this with their own note. Stored through the existing receipt-note pipeline in the Notes column (L).
photoNoSingle attached receipt image or PDF supplied by ChatGPT. For multiple files or large files, use filesToUpload and uploadRefs instead.
filenameNoOptional filename (e.g., 'lunch_receipt.jpg')
mimeTypeNoMIME type of the file (default: image/jpeg)
uploadRefNoSingle-file shorthand for uploadRefs. Use uploadRefs when there is more than one file.
uploadRefsNoSubmit previously uploaded files as ONE batch. Include every uploadRef from the filesToUpload step. If any file fails validation the whole batch is rejected and nothing is processed.
photoBase64NoLegacy fallback for MCP clients that send one small image as complete base64 data. ChatGPT should use photo or uploadRefs instead.
filesToUploadNoRequest upload URLs for one or more files. Include EVERY file the user provided in a single call. Returns one signedUrl + uploadRef per file; upload each, then call this tool again with uploadRefs.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNo
filesNo
statusNo
messageNo
successYes
fileCountNo
statusCodeNo
submissionIdNo
spreadsheetUrlNo
reviewExpensesUrlNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotation contradiction – the description aligns with readOnlyHint=false by describing a mutating multi-step operation. It discloses the full pipeline (validation, cloud upload, AI extraction), the expected latency (1-3 minutes, longer for PDFs/batches), atomic batch failure semantics ('If any file fails validation the whole batch is rejected'), and storage mappings (Notes column L, Tag column K). This significantly enriches the annotations.

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 the purpose and primary use case, then logically organized into protocol steps, allowed parameter paths, and metadata behavior. Despite the length, every sentence earns its place — the batch-flow warning and column references are all functional, not filler. The structure guides the agent from 'what' to 'how' without redundancy.

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?

This is one of the most complex tools in the set (9 params, nested objects, a multi-step upload protocol, atomic batch behavior), and the description covers every operational aspect: parameter-path selection, ordering constraints, timing expectations, column storage, validation failure semantics, and fallbacks. With an output schema present, the agent has everything needed to invoke this correctly.

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 protocol-level meaning the schema alone cannot convey: the ordering dependency between filesToUpload and uploadRefs, the requirement that MIME types match the PUT Content-Type exactly, and the per-file override semantics for tag and note. It elevates raw parameter names into a usable workflow without losing the schema's per-field detail.

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 ('Submit a photo or PDF of a receipt for processing') and maps the natural-language triggers ('log this', 'expense this'). The description goes beyond a simple definition to clarify exactly what it processes (images and PDFs, mixed batches) and distinguishes it from siblings like add_cash_expense, which handle non-receipt cash entries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Extremely explicit routing: the upload flow is declared 'preferred, and required for PDFs', photo handles a single ChatGPT attachment, photoBase64 is the legacy fallback for clients lacking file references. It also gives step-by-step procedure (filesToUpload → one HTTP PUT per file → call once with uploadRefs) and explicitly warns 'Do not call this tool once per file'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

trace_documentA
Read-only
Inspect

Trace what happened to a specific receipt, invoice, forwarded email, Gmail receipt, or PDF in ExpenseBot processing. Use when the user asks where a document went, why it did not show up, whether it was skipped, routed to income, deduped, or removed as a duplicate. Returns a read-only timeline from the user's lineage audit trail.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNoHow many days back to search.
limitNoMaximum lineage events to return.
queryNoMerchant, sender, subject, invoice number, or phrase to search for, e.g. 'Blue Rocket', 'Driversnote', 'Uber receipt'.
outcomeNoOptional processing outcome filter.all
threadIdNoGmail thread ID if known.
messageIdNoGmail message ID if known.
receiptIdNoExpenseBot receipt/invoice ID if known, e.g. IR-123, RO-abc, RR-456.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
typeYes
messageYes
successYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the description is not required to repeat that. It adds value by specifying 'Returns a read-only timeline from the user's lineage audit trail,' which clarifies the data source and nature of the output. This goes beyond the annotations without contradicting them. No side effects or permission requirements are mentioned, but given the read-only annotation, the description adequately covers behavior.

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?

The description is three sentences long, front-loaded with the primary action and resource, then the use cases, then the output type. Every sentence carries information, and there is no fluff. It is concise and well-structured, though slightly longer than necessary, which is why it doesn't get a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, use cases, and output type. However, it does not explicitly state that the user must provide at least one of the search criteria (query, threadId, messageId, or receiptId) to get a meaningful trace. Since all parameters are optional in the schema, an agent might call it without any parameters and get an empty or broad result. The output schema exists but is not described; still, it is not needed. This missing guidance is a notable gap for a tool that is otherwise well-defined.

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?

All seven parameters have descriptions in the input schema (100% coverage), so the schema already explains each parameter's meaning. The description does not add any additional context about parameters, such as how they combine or that at least one search identifier is required. Since schema coverage is high, the baseline of 3 is appropriate; the description does not need to repeat parameter details.

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?

The description clearly states the verb ('Trace'), the resource ('receipt, invoice, forwarded email, Gmail receipt, or PDF in ExpenseBot processing'), and the specific purpose: to trace what happened in processing. It distinguishes itself from generic search tools by focusing on processing outcomes like 'skipped, routed to income, deduped, or removed as a duplicate.' The title also reinforces this. This is a precise, unambiguous purpose.

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?

The description provides explicit 'use when' conditions: 'when the user asks where a document went, why it did not show up, whether it was skipped, routed to income, deduped, or removed as a duplicate.' It does not name alternative sibling tools or explicitly say when not to use it, but the scope is clear enough that an agent can distinguish it from search or general listing tools. It could improve by mentioning alternatives like 'search' for locating documents without processing context, but that is a minor gap.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_expenseA
Destructive
Inspect

Update a single existing expense row's category, tag, merchant, or business purpose (e.g. 'recategorize expense X to Meals' or 'tag it Client – Acme'). Identify it only by the exact expenseId returned by search_expenses (the full Receipt ID from Column Q). Never use a date, displayed number, or sheet row number as expenseId. Two-phase operation: calls with confirm omitted or false return a preview of the current→proposed change and make no change. After user confirmation, a call with confirm:true applies the proposed change. If the expense is not found, search once for a current exact expenseId; never retry the same stale ID. If a business-purpose update exceeds the Notes capacity, stop and send the user to https://www.expensebot.ai/review-expenses?source=mcp instead of retrying. Only category/tag/merchant/businessPurpose are editable — amounts, dates, and notes are not editable via the assistant. Does not create or delete rows.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsYesPartial update object. Include one or more of these optional keys; omit every field that should remain unchanged.
confirmNoOmit or false = preview only (no write). Must be exactly true to apply the change.
expenseIdYesExact full Receipt ID from Column Q, returned as expenseId by search_expenses.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
messageYes
successYes
finalAnswerNo
responseGuidanceNo

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the annotations. It discloses the two-phase preview/confirm behavior, the exact semantics of confirm (omitted/false = preview, true = apply), the fact that stale IDs must not be retried, the capacity limitation for businessPurpose, and the non-editable fields. The annotations only say destructiveHint=true, but the description adds crucial context about what 'destructive' means here (only after confirm:true) and how to avoid mistakes. No contradiction with annotations.

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?

The description is dense but well-organized. It front-loads the core purpose and editable fields, then explains the two-phase behavior, then the error handling. Every sentence earns its place, though it is somewhat long. The structure is logical: purpose → identification → preview/confirm → error handling → non-editable fields → scope. A 4 because it's slightly verbose but highly informative.

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?

Given the tool's complexity (two-phase operation, strict ID requirements, capacity limits, non-editable fields), the description covers all the critical context an agent needs. The output schema exists, so return values don't need to be described. The description also addresses edge cases (stale ID, capacity overflow) and provides a fallback URL. This is complete for safe and correct invocation.

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. The description adds meaningful semantics beyond the schema: it explains that expenseId is the exact Receipt ID from Column Q returned by search_expenses, and that confirm must be exactly true to apply. It also clarifies that fields is a partial update object. However, the description doesn't add much about the individual field values (e.g., allowed formats for category/tag), but the schema already documents the structure well. A 4 is appropriate because the description adds important operational context for the parameters.

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?

The description states a specific verb ('Update') and resource ('a single existing expense row'), and enumerates exactly which fields are editable (category, tag, merchant, businessPurpose). It also explicitly distinguishes itself from create/delete operations ('Does not create or delete rows') and from search_expenses, which returns the expenseId. This is a clear, specific purpose that an agent can act on without ambiguity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit when-to-use guidance: use it to recategorize/tag/change merchant/business purpose, and explicitly says amounts, dates, and notes are not editable via the assistant. It also names the alternative for finding the ID (search_expenses) and the fallback for capacity issues (send user to a URL). It even gives a concrete example ('recategorize expense X to Meals'). This is exemplary usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whatif_affordA
Read-only
Inspect

Can I afford $X/month? Recomputes the user's Safe Monthly Draw (how much they can safely pay themselves) with an added recurring monthly cost, and returns a yes/tight/no verdict plus the before/after numbers. Use for questions like 'can I afford a $500/mo hire' or 'what if I add a $200/mo software subscription'. Requires at least 3 months of income history — otherwise returns insufficient_data rather than a guess.

ParametersJSON Schema
NameRequiredDescriptionDefault
deltaMonthlyYesThe new recurring monthly cost being considered, in the user's home currency

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoThe full what-if scenario: assumptions, evidence, and computed outcome.
messageNoScenario narrative; may be absent if the scenario carried no template or evidence.
successYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark readOnlyHint=true and destructiveHint=false, so the read-only nature is covered. The description adds noteworthy behavioral detail beyond annotations: the requirement of at least 3 months of income history and the insufficient_data non-guess response, which helps an agent anticipate edge conditions.

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?

The description is three sentences: a functional summary with output types, a practical use-case framing, and a key prerequisite/edge behavior. Every sentence has value, the most important facts are front-loaded, and nothing is redundant or verbose.

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?

Given the single param, full schema coverage, non-destructive readOnly annotations, and the presence of an output schema, this description covers the tool's purpose, prerequisites, behavior, and result shape. No significant information an agent needs to select or invoke it 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?

The schema covers the single parameter completely with a clear description, including minimum value and currency context. The tool description adds no new parameter-specific information since 100% of the schema is already described, 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?

Description clearly states it recomputes the user's Safe Monthly Draw with an added monthly cost and returns a yes/tight/no verdict plus before/after numbers. It does not explicitly name or differentiate the whatif_client and whatif_tax_setaside siblings, but the affordability context is specific enough.

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?

The description provides concrete usage examples like 'can I afford a $500/mo hire' and mentions a precondition (3 months of income history) including the failure mode (returning insufficient_data). It does not give an explicit when-not or alternative tool recommendation among the siblings, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whatif_clientA
Read-only
Inspect

What if a client pays late or leaves? mode='late30' shifts that client's OPEN invoice amounts out of the near-term expectation (they still owe it, it's just not landing this month). mode='gone' removes that client's trailing monthly income contribution and recomputes Safe Draw against the reduced baseline. Use for questions like 'what if Acme Corp pays 30 days late' or 'what happens if I lose my biggest client'. Client identity is matched against the Income tab's tag/source/description fields — best effort, not a guaranteed match.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeYes'late30' = shift open invoices 30 days late; 'gone' = client stops paying entirely
clientNameYesThe client's name as it appears on invoices or income rows

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoThe full what-if scenario: assumptions, evidence, and computed outcome.
messageNoScenario narrative; may be absent if the scenario carried no template or evidence.
successYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Despite readOnlyHint=true and destructiveHint=false, the description adds valuable behavioral context: 'late30' shifts open invoices without removing the debt, while 'gone' removes trailing monthly income and recomputes Safe Draw. The best-effort matching caveat against Income tab fields is an important disclosure beyond the annotations.

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?

Three sentences deliver the entire picture: purpose, mode semantics, usage examples, and caveat. It is front-loaded with the 'what if' framing and has little wasted prose—just slightly redundant with the opening question and the example phrasing.

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 two-parameter, read-only what-if tool with an output schema, the description covers the core effect, usage scenarios, and matching caveat. It doesn't explicitly describe the return shape, but with an output schema present that is not required. Minor omission: it doesn't explain what 'Safe Draw' means, but it's a domain term utilized for context.

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 baseline is 3, but the description enriches both parameters. It clarifies the real-world meaning of 'late30' and 'gone' and adds that clientName matching is best-effort, which is not captured in the schema's field description.

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?

The description states a specific scenario ('client pays late or leaves') and explains the effect of each mode, making the tool's purpose unambiguous. The two example questions ('what if Acme Corp pays 30 days late', 'what happens if I lose my biggest client') clearly distinguish this tool from the sibling whatif_afford and whatif_tax_setaside tools.

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?

The description explicitly says to use it for questions like 'what if a client pays 30 days late' or 'what if I lose my biggest client', giving the agent a clear when-to-use signal. It doesn't name alternatives or state when not to use it, but the scenario-based guidance is strong enough to route correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whatif_tax_setasideA
Read-only
Inspect

What should I set aside for taxes? Surfaces the same monthly tax set-aside estimate already computed for Safe Monthly Draw — wiring, not new math. Flat-rate estimate (default 30%) against trailing income minus recurring + variable spend. Use for 'how much should I set aside for taxes this month'.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataNoThe full what-if scenario: assumptions, evidence, and computed outcome.
messageNoScenario narrative; may be absent if the scenario carried no template or evidence.
successYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the tool safe and read-only. The description adds meaningful behavior beyond that: it mentions the estimate is not newly computed but reuses the Safe Monthly Draw value ('wiring, not new math') and reveals the flat 30% default rate applied to income minus spend. These details help the agent understand derivation and variability.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded, but it repeats the key idea: the opening 'What should I set aside for taxes?' and the closing 'Use for...' convey the same usage scenario. This redundancy makes it slightly less concise than it could be.

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 zero-parameter estimation tool with a schema and existing output schema, the description is largely complete. It gives the calculation basis and the invocation scenario. The only slight omission is that the default rate's adjustability is implied but not stated; for the estimation accuracy for context this is still sufficient.

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?

With zero parameters and 100% schema coverage, the baseline is 4. The description still adds value by mentioning the conceptual formula inputs (trailing income minus recurring + variable spend), which helps the agent understand what data the estimate is based on.

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 clearly says the tool surfaces the monthly tax set-aside estimate and frames it as answering 'What should I set aside for taxes?'. It doesn't explicitly name sibling what-if tools, but the tax-specific focus and the reference to Safe Monthly Draw make it distinguishable.

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?

The description explicitly states when to use it: for the question 'how much should I set aside for taxes this month'. It doesn't mention exclusions or alternatives, but the when-to-use is clear and direct.

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. 23 tool updates
    • Changedadd_cash_expense1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "expense": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "category": {
        +          "type": "string"
        +        },
        +        "currency": {
        +          "type": "string"
        +        },
        +        "date": {
        +          "format": "date",
        +          "type": "string"
        +        },
        +        "isClientAdvance": {
        +          "type": "boolean"
        +        },
        +        "merchant": {
        +          "type": "string"
        +        },
        +        "receivedAmount": {
        +          "type": "number"
        +        },
        +        "recordId": {
        +          "type": "string"
        +        },
        +        "rowNumber": {
        +          "minimum": 1,
        +          "type": "integer"
        +        },
        +        "tag": {
        +          "type": "string"
        +        },
        +        "total": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "recordId": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "rowNumber": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedadd_income1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "deduped": {
        +      "type": "boolean"
        +    },
        +    "destinations": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "matchedRow": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "amount": {
        +          "type": "number"
        +        },
        +        "currency": {
        +          "type": "string"
        +        },
        +        "date": {
        +          "format": "date",
        +          "type": "string"
        +        },
        +        "rowNumber": {
        +          "minimum": 1,
        +          "type": "integer"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "recordId": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "rowNumber": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "tabCreated": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedadd_income_from_csv1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "allOf": [
        +    {
        +      "if": {
        +        "properties": {
        +          "preview": {
        +            "const": true
        +          }
        +        },
        +        "required": [
        +          "preview"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "previewId",
        +          "expiresAt",
        +          "entryCount",
        +          "entries",
        +          "confirmationContract"
        +        ]
        +      }
        +    },
        +    {
        +      "if": {
        +        "properties": {
        +          "confirmed": {
        +            "const": true
        +          }
        +        },
        +        "required": [
        +          "confirmed"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "previewId",
        +          "written",
        +          "deduped",
        +          "failed",
        +          "unattempted",
        +          "total"
        +        ]
        +      }
        +    }
        +  ],
        +  "properties": {
        +    "confirmationContract": {
        +      "type": "string"
        +    },
        +    "confirmed": {
        +      "type": "boolean"
        +    },
        +    "deduped": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "duplicateCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "duplicates": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "entries": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "amount": {
        +            "type": "number"
        +          },
        +          "currency": {
        +            "type": "string"
        +          },
        +          "date": {
        +            "format": "date",
        +            "type": "string"
        +          },
        +          "duplicate": {
        +            "type": "boolean"
        +          },
        +          "index": {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "payer": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "entryCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "expiresAt": {
        +      "format": "date-time",
        +      "type": "string"
        +    },
        +    "expiresInMinutes": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "failed": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "idempotentReplay": {
        +      "type": "boolean"
        +    },
        +    "maxChatEntries": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "preview": {
        +      "type": "boolean"
        +    },
        +    "previewId": {
        +      "type": "string"
        +    },
        +    "projectionTruncated": {
        +      "type": "boolean"
        +    },
        +    "refundRowCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "rejectedRows": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewImportUrl": {
        +      "type": "string"
        +    },
        +    "reviewIncomeUrl": {
        +      "type": "string"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "tooLargeForChat": {
        +      "type": "boolean"
        +    },
        +    "total": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "totalsByCurrency": {
        +      "additionalProperties": {
        +        "type": "number"
        +      },
        +      "type": "object"
        +    },
        +    "unattempted": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "warnings": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "written": {
        +      "minimum": 0,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedadd_income_from_file1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "allOf": [
        +    {
        +      "if": {
        +        "properties": {
        +          "preview": {
        +            "const": true
        +          }
        +        },
        +        "required": [
        +          "preview"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "previewId",
        +          "expiresAt",
        +          "entryCount",
        +          "entries",
        +          "confirmationContract"
        +        ]
        +      }
        +    },
        +    {
        +      "if": {
        +        "properties": {
        +          "confirmed": {
        +            "const": true
        +          }
        +        },
        +        "required": [
        +          "confirmed"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "previewId",
        +          "written",
        +          "deduped",
        +          "failed",
        +          "unattempted",
        +          "total"
        +        ]
        +      }
        +    }
        +  ],
        +  "properties": {
        +    "confirmationContract": {
        +      "type": "string"
        +    },
        +    "confirmed": {
        +      "type": "boolean"
        +    },
        +    "deduped": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "duplicateCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "duplicates": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "entries": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "amount": {
        +            "type": "number"
        +          },
        +          "currency": {
        +            "type": "string"
        +          },
        +          "date": {
        +            "format": "date",
        +            "type": "string"
        +          },
        +          "duplicate": {
        +            "type": "boolean"
        +          },
        +          "index": {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "payer": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "entryCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "expiresAt": {
        +      "format": "date-time",
        +      "type": "string"
        +    },
        +    "expiresInMinutes": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "failed": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "idempotentReplay": {
        +      "type": "boolean"
        +    },
        +    "maxChatEntries": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "preview": {
        +      "type": "boolean"
        +    },
        +    "previewId": {
        +      "type": "string"
        +    },
        +    "projectionTruncated": {
        +      "type": "boolean"
        +    },
        +    "refundRowCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "rejectedRows": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewImportUrl": {
        +      "type": "string"
        +    },
        +    "reviewIncomeUrl": {
        +      "type": "string"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "tooLargeForChat": {
        +      "type": "boolean"
        +    },
        +    "total": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "totalsByCurrency": {
        +      "additionalProperties": {
        +        "type": "number"
        +      },
        +      "type": "object"
        +    },
        +    "unattempted": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "warnings": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "written": {
        +      "minimum": 0,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedadd_mileage_entry1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "rowNumber": {
        +      "minimum": 1,
        +      "type": "integer"
        +    },
        +    "settings": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "allowancePerUnit": {
        +          "type": "number"
        +        },
        +        "unit": {
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedcorrect_expenses2 fields changed
      • addedInput schema / properties / change / oneOf
        Added value: +[
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "category"
        +      }
        +    },
        +    "required": [
        +      "category"
        +    ]
        +  },
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "businessPurpose"
        +      }
        +    },
        +    "required": [
        +      "businessPurpose"
        +    ]
        +  },
        +  {
        +    "properties": {
        +      "type": {
        +        "const": "attendees"
        +      }
        +    },
        +    "required": [
        +      "attendees"
        +    ]
        +  }
        +]
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "change": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "confirmation": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "manifest": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "operationId": {
        +      "type": "string"
        +    },
        +    "preview": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "requiresConfirmation": {
        +      "type": "boolean"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "undo": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "status"
        +  ],
        +  "type": "object"
        +}
    • Changedcreate_client_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "advanceApplied": {
        +      "type": "number"
        +    },
        +    "artifactWarning": {
        +      "type": "string"
        +    },
        +    "clientName": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "currency": {
        +      "type": "string"
        +    },
        +    "documentUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "docxUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "dueDate": {
        +      "format": "date",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "grandTotal": {
        +      "type": "number"
        +    },
        +    "invoiceId": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "invoiceNumber": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "issueDate": {
        +      "format": "date",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "pdfUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "recovered": {
        +      "type": "boolean"
        +    },
        +    "sourceReportId": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "total": {
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedcreate_report1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "accountingHandoffUrls": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "accountingSetupUrl": {
        +      "type": "string"
        +    },
        +    "billClientUrl": {
        +      "type": "string"
        +    },
        +    "creationStatus": {
        +      "type": "string"
        +    },
        +    "data": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "appReportUrl": {
        +          "type": "string"
        +        },
        +        "appliedFilters": {
        +          "additionalProperties": true,
        +          "type": "object"
        +        },
        +        "billClientUrl": {
        +          "type": "string"
        +        },
        +        "creationStatus": {
        +          "type": "string"
        +        },
        +        "functionalTotal": {
        +          "type": "number"
        +        },
        +        "homeCurrency": {
        +          "type": "string"
        +        },
        +        "link": {
        +          "type": "string"
        +        },
        +        "personalExcludedCount": {
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "receiptCount": {
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "reportId": {
        +          "type": "string"
        +        },
        +        "title": {
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "nextActions": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "reportId": {
        +      "type": "string"
        +    },
        +    "reportUrl": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedexport_report1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "availableInReport": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "expiresAt": {
        +      "format": "date-time",
        +      "type": "string"
        +    },
        +    "notes": {
        +      "type": "string"
        +    },
        +    "report": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "spreadsheetId": {
        +          "type": "string"
        +        },
        +        "status": {
        +          "type": "string"
        +        },
        +        "title": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "title",
        +        "spreadsheetId"
        +      ],
        +      "type": "object"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "urls": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "pdf": {
        +          "type": "string"
        +        },
        +        "report": {
        +          "type": "string"
        +        },
        +        "view": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "view",
        +        "pdf",
        +        "report"
        +      ],
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "report",
        +    "urls",
        +    "expiresAt",
        +    "availableInReport",
        +    "notes"
        +  ],
        +  "type": "object"
        +}
    • Changedfix_compliance12 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • removedInput schema / properties / action
        Removed value: -{
        -  "enum": [
        -    "add_purpose",
        -    "set_category",
        -    "add_tag"
        -  ],
        -  "type": "string"
        -}
      • addedInput schema / properties / change
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Exactly one correction. The selected type determines which matching value field is required.",
        +  "oneOf": [
        +    {
        +      "properties": {
        +        "type": {
        +          "const": "category"
        +        }
        +      },
        +      "required": [
        +        "category"
        +      ]
        +    },
        +    {
        +      "properties": {
        +        "type": {
        +          "const": "businessPurpose"
        +        }
        +      },
        +      "required": [
        +        "businessPurpose"
        +      ]
        +    },
        +    {
        +      "properties": {
        +        "type": {
        +          "const": "attendees"
        +        }
        +      },
        +      "required": [
        +        "attendees"
        +      ]
        +    }
        +  ],
        +  "properties": {
        +    "attendeeMode": {
        +      "description": "Use add unless the user explicitly asks to replace existing attendees.",
        +      "enum": [
        +        "add",
        +        "replace"
        +      ],
        +      "type": "string"
        +    },
        +    "attendees": {
        +      "description": "Attendee names explicitly supplied by the user when type is attendees; never infer names.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "maxItems": 25,
        +      "minItems": 1,
        +      "type": "array"
        +    },
        +    "businessPurpose": {
        +      "description": "User-supplied business purpose to apply when type is businessPurpose.",
        +      "type": "string"
        +    },
        +    "category": {
        +      "description": "Configured expense category to apply when type is category.",
        +      "type": "string"
        +    },
        +    "type": {
        +      "description": "The one correction kind to apply to every exact selected expense.",
        +      "enum": [
        +        "category",
        +        "businessPurpose",
        +        "attendees"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "type"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / confirm
        Added value: +{
        +  "description": "Omit/false for preview; true only after explicit approval.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / operationId
        Added value: +{
        +  "description": "Stable idempotency key generated once for preview and reused unchanged.",
        +  "pattern": "^expense-bulk:[a-zA-Z0-9_-]{8,100}$",
        +  "type": "string"
        +}
      • removedInput schema / properties / reportId
        Removed value: -{
        -  "type": "string"
        -}
      • addedInput schema / properties / selection
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Exact expenses returned by search_expenses and approved for this bounded correction.",
        +  "properties": {
        +    "items": {
        +      "description": "One exact receipt identity per selected expense; never broaden this list after preview.",
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "expected": {
        +            "additionalProperties": false,
        +            "description": "Optional optimistic-concurrency values copied from the search result.",
        +            "properties": {
        +              "category": {
        +                "description": "Current category observed before preview for conflict detection.",
        +                "type": "string"
        +              },
        +              "notes": {
        +                "description": "Current structured Notes value observed before preview for conflict detection.",
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "receiptId": {
        +            "description": "Exact full expenseId/Column-Q receipt identity from search_expenses.",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "receiptId"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 100,
        +      "minItems": 1,
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "items"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "description": "Read operation status using operationId.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / undo
        Added value: +{
        +  "description": "Undo a completed correction within its Undo window.",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / value
        Removed value: -{
        -  "description": "The value to apply",
        -  "type": "string"
        -}
      • changedInput schema / required
        Previous value: -[
        -  "reportId",
        -  "action",
        -  "value"
        -]New value: +[
        +  "operationId"
        +]
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "change": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "confirmation": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "manifest": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "operationId": {
        +      "type": "string"
        +    },
        +    "preview": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "requiresConfirmation": {
        +      "type": "boolean"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "undo": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "status"
        +  ],
        +  "type": "object"
        +}
    • Changedgroup_expenses1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "candidates": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "confirmation": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "creationStatus": {
        +      "type": "string"
        +    },
        +    "exclusions": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "group": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "manifest": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "operationId": {
        +      "type": "string"
        +    },
        +    "preview": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "report": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "reportsUrl": {
        +      "type": "string"
        +    },
        +    "requiresConfirmation": {
        +      "type": "boolean"
        +    },
        +    "requiresNewGroupApproval": {
        +      "type": "boolean"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "suggestedTag": {
        +      "type": "string"
        +    },
        +    "undo": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "status"
        +  ],
        +  "type": "object"
        +}
    • Changedmark_client_invoice_paid1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "incomeRowCreated": {
        +      "const": false,
        +      "type": "boolean"
        +    },
        +    "invoiceId": {
        +      "type": "string"
        +    },
        +    "invoiceNumber": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "paidAmount": {
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "paidDate": {
        +      "format": "date",
        +      "type": "string"
        +    },
        +    "paidVia": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "const": "paid",
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "invoiceId",
        +    "status",
        +    "paidDate",
        +    "paidAmount",
        +    "paidVia",
        +    "incomeRowCreated",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedparse_expense1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "categoryNames": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "expenses": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "amount": {
        +            "type": "number"
        +          },
        +          "category": {
        +            "type": "string"
        +          },
        +          "currency": {
        +            "type": "string"
        +          },
        +          "date": {
        +            "format": "date",
        +            "type": "string"
        +          },
        +          "merchant": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "validationErrors": {
        +      "items": {},
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "expenses",
        +    "validationErrors",
        +    "categoryNames"
        +  ],
        +  "type": "object"
        +}
    • Changedprepare_client_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "expiresAt": {
        +      "format": "date-time",
        +      "type": "string"
        +    },
        +    "preparationId": {
        +      "type": "string"
        +    },
        +    "preview": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "advanceApplied": {
        +          "type": "number"
        +        },
        +        "balanceDue": {
        +          "type": "number"
        +        },
        +        "clientName": {
        +          "type": "string"
        +        },
        +        "clientTag": {
        +          "type": "string"
        +        },
        +        "currency": {
        +          "type": "string"
        +        },
        +        "customLineCount": {
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "dueDate": {
        +          "format": "date",
        +          "type": "string"
        +        },
        +        "expenseCount": {
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        "grandTotal": {
        +          "type": "number"
        +        },
        +        "hasTaxRegistration": {
        +          "type": "boolean"
        +        },
        +        "invoiceNumber": {
        +          "type": "string"
        +        },
        +        "issueDate": {
        +          "format": "date",
        +          "type": "string"
        +        },
        +        "markupAmount": {
        +          "type": "number"
        +        },
        +        "markupPct": {
        +          "type": "number"
        +        },
        +        "paymentTerms": {
        +          "type": "string"
        +        },
        +        "reportId": {
        +          "type": "string"
        +        },
        +        "reportTitle": {
        +          "type": "string"
        +        },
        +        "subtotal": {
        +          "type": "number"
        +        },
        +        "taxAmount": {
        +          "type": "number"
        +        },
        +        "taxConfirmationRequired": {
        +          "type": "boolean"
        +        },
        +        "taxLabel": {
        +          "type": "string"
        +        },
        +        "taxPct": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "preparationId",
        +    "expiresAt",
        +    "preview"
        +  ],
        +  "type": "object"
        +}
    • Changedprocess_gmail_receipts1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "emailCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "error": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "processInfo": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "processingCompleted": {
        +          "type": "boolean"
        +        },
        +        "sessionId": {
        +          "type": "string"
        +        },
        +        "status": {
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "processedItems": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "submissionId": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedrequest_accounting_integration1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "duplicate": {
        +      "type": "boolean"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "packageName": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "duplicate",
        +    "packageName",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedscan_gmail1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "_metadata": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "orchestrated": {
        +      "type": "boolean"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "scanInProgress": {
        +      "type": "boolean"
        +    },
        +    "sessionId": {
        +      "type": "string"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "submissionId": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedscan_gmail_years1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "allOf": [
        +    {
        +      "if": {
        +        "properties": {
        +          "preview": {
        +            "const": true
        +          }
        +        },
        +        "required": [
        +          "preview"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "account",
        +          "eligible",
        +          "alreadyScanned",
        +          "notEligible"
        +        ]
        +      }
        +    }
        +  ],
        +  "properties": {
        +    "account": {
        +      "type": "string"
        +    },
        +    "alreadyQueued": {
        +      "items": {
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "alreadyScanned": {
        +      "items": {
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "archiveThroughYear": {
        +      "type": "integer"
        +    },
        +    "eligible": {
        +      "items": {
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "gmailUrl": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "notEligible": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "code": {
        +            "type": "string"
        +          },
        +          "reason": {
        +            "type": "string"
        +          },
        +          "year": {
        +            "type": "integer"
        +          }
        +        },
        +        "required": [
        +          "year",
        +          "reason"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "preview": {
        +      "type": "boolean"
        +    },
        +    "queuedYears": {
        +      "items": {
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "scanning": {
        +      "items": {
        +        "type": "integer"
        +      },
        +      "type": "array"
        +    },
        +    "startedYear": {
        +      "type": [
        +        "integer",
        +        "null"
        +      ]
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedsend_report_to_accounting1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "allOf": [
        +    {
        +      "if": {
        +        "properties": {
        +          "phase": {
        +            "const": "preview"
        +          }
        +        },
        +        "required": [
        +          "phase"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "expiresAt",
        +          "confirmationRequired",
        +          "confirmationQuestion",
        +          "confirmationContract"
        +        ]
        +      }
        +    },
        +    {
        +      "if": {
        +        "properties": {
        +          "phase": {
        +            "const": "completed"
        +          }
        +        },
        +        "required": [
        +          "phase"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "reportId",
        +          "finalAnswer",
        +          "responseGuidance"
        +        ]
        +      }
        +    }
        +  ],
        +  "properties": {
        +    "confirmationContract": {
        +      "type": "string"
        +    },
        +    "confirmationQuestion": {
        +      "type": "string"
        +    },
        +    "confirmationRequired": {
        +      "type": "boolean"
        +    },
        +    "counts": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "created": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "expiresAt": {
        +      "format": "date-time",
        +      "type": "string"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "idempotentReplay": {
        +      "type": "boolean"
        +    },
        +    "matchedExisting": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "omittedExpenses": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "organization": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "phase": {
        +      "enum": [
        +        "preview",
        +        "completed"
        +      ],
        +      "type": "string"
        +    },
        +    "proposalId": {
        +      "type": "string"
        +    },
        +    "provider": {
        +      "type": "string"
        +    },
        +    "reconciliationRequired": {
        +      "type": "boolean"
        +    },
        +    "reportId": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "skippedAlreadyPushed": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "units": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "phase",
        +    "provider",
        +    "proposalId"
        +  ],
        +  "type": "object"
        +}
    • Changedshare_report1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "recipientRole": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "sharedWith": {
        +      "items": {
        +        "format": "email",
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message",
        +    "sharedWith",
        +    "recipientRole"
        +  ],
        +  "type": "object"
        +}
    • Changedsubmit_receipt1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "allOf": [
        +    {
        +      "if": {
        +        "properties": {
        +          "status": {
        +            "const": "upload_required"
        +          }
        +        },
        +        "required": [
        +          "status"
        +        ]
        +      },
        +      "then": {
        +        "required": [
        +          "data"
        +        ]
        +      }
        +    }
        +  ],
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "expiresInSeconds": {
        +          "minimum": 1,
        +          "type": "integer"
        +        },
        +        "files": {
        +          "items": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "filename": {
        +                "type": "string"
        +              },
        +              "id": {
        +                "type": "string"
        +              },
        +              "mimeType": {
        +                "type": "string"
        +              },
        +              "requiredHeaders": {
        +                "additionalProperties": {
        +                  "type": "string"
        +                },
        +                "type": "object"
        +              },
        +              "signedUrl": {
        +                "type": "string"
        +              },
        +              "uploadRef": {
        +                "type": "string"
        +              }
        +            },
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "requiredHeaders": {
        +          "additionalProperties": {
        +            "type": "string"
        +          },
        +          "type": "object"
        +        },
        +        "reviewExpensesUrl": {
        +          "type": "string"
        +        },
        +        "signedUrl": {
        +          "type": "string"
        +        },
        +        "spreadsheetUrl": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "submissionId": {
        +          "type": "string"
        +        },
        +        "uploadRef": {
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "fileCount": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "files": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "spreadsheetUrl": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "type": "string"
        +    },
        +    "statusCode": {
        +      "type": "integer"
        +    },
        +    "submissionId": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedtrace_document1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "events": {
        +          "items": {
        +            "additionalProperties": true,
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "filters": {
        +          "additionalProperties": true,
        +          "type": "object"
        +        },
        +        "searchLabel": {
        +          "type": "string"
        +        },
        +        "summary": {
        +          "additionalProperties": true,
        +          "type": "object"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "const": "lineage_trace",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "type",
        +    "message",
        +    "data"
        +  ],
        +  "type": "object"
        +}
    • Changedupdate_expense1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "properties": {
        +        "applied": {
        +          "type": "boolean"
        +        },
        +        "diff": {
        +          "items": {
        +            "additionalProperties": true,
        +            "properties": {
        +              "column": {
        +                "type": "string"
        +              },
        +              "columnLetter": {
        +                "type": "string"
        +              },
        +              "field": {
        +                "type": "string"
        +              },
        +              "from": {},
        +              "to": {}
        +            },
        +            "required": [
        +              "field",
        +              "from",
        +              "to"
        +            ],
        +            "type": "object"
        +          },
        +          "type": "array"
        +        },
        +        "dryRun": {
        +          "type": "boolean"
        +        },
        +        "expenseId": {
        +          "type": "string"
        +        },
        +        "preview": {
        +          "type": "boolean"
        +        },
        +        "reviewExpenseUrl": {
        +          "type": "string"
        +        },
        +        "unmapped": {
        +          "items": {
        +            "type": "string"
        +          },
        +          "type": "array"
        +        }
        +      },
        +      "required": [
        +        "applied",
        +        "expenseId",
        +        "diff",
        +        "unmapped"
        +      ],
        +      "type": "object"
        +    },
        +    "finalAnswer": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "message",
        +    "data"
        +  ],
        +  "type": "object"
        +}
  2. 1 tool update
    • Changedget_scan_status5 fields changed
      • changedOutput schema / properties / gmailScanUrl / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / latestScan / type
        Previous value: -"object"New value: +[
        +  "object",
        +  "null"
        +]
      • changedOutput schema / properties / reviewExpensesUrl / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / spreadsheetUrl / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / status / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
  3. 30 tool updates
    • Changedcheck_compliance1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedcheck_feature1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedcheck_tax_deductibility1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_accounting_integration_status1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "Per-provider connection and rollout state.",
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_accounting_push_status1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_client_advance_balances1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "balances": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "homeCurrency": {
        +      "type": "string"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_client_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "invoice": {
        +      "additionalProperties": true,
        +      "description": "The invoice record. Absent only on the error branch (not-found), which never carries structuredContent.",
        +      "properties": {
        +        "advanceApplied": {
        +          "type": "number"
        +        },
        +        "balanceDue": {
        +          "type": "number"
        +        },
        +        "billClientUrl": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "clientName": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "clientTag": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "currency": {
        +          "type": "string"
        +        },
        +        "deliveryStatus": {
        +          "type": "string"
        +        },
        +        "displayStatus": {
        +          "description": "Derived: overdue is computed from status + dueDate, not stored.",
        +          "enum": [
        +            "open",
        +            "overdue",
        +            "paid",
        +            "void",
        +            "superseded",
        +            "needs_review"
        +          ],
        +          "type": "string"
        +        },
        +        "documentUrl": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "dueDate": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "grandTotal": {
        +          "type": "number"
        +        },
        +        "invoiceId": {
        +          "description": "Durable invoice identity.",
        +          "type": "string"
        +        },
        +        "invoiceNumber": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "issueDate": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "paidAmount": {
        +          "description": "null until paid.",
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "paidDate": {
        +          "description": "null until paid.",
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "pdfUrl": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "reportUrl": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "status": {
        +          "description": "Stored status, e.g. \"open\", \"paid\", \"void\".",
        +          "type": "string"
        +        },
        +        "subtotal": {
        +          "type": "number"
        +        },
        +        "taxAmount": {
        +          "type": "number"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_credits_refunds1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "credits": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "refunds": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_deep_analytics1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Two branches. Async: type='analytics_pending' with jobId — poll poll_analytics until complete. Inline: message + data with the computed analytics (data may be null when there is no spreadsheet or no data yet). success is present only on the async branch.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "Inline branch: computed analytics, or null when no spreadsheet / no data.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "estimatedTime": {
        +      "description": "Async branch only: seconds.",
        +      "type": "number"
        +    },
        +    "jobId": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "message": {
        +      "description": "Human-readable narrative (both branches).",
        +      "type": "string"
        +    },
        +    "pollEndpoint": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "pollInterval": {
        +      "description": "Async branch only: milliseconds.",
        +      "type": "number"
        +    },
        +    "response": {
        +      "description": "Chat alias of message.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Async branch only.",
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "description": "Async branch only: \"analytics_pending\" — poll pollEndpoint or call poll_analytics with jobId.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_expense_by_id1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "expense": {
        +      "additionalProperties": true,
        +      "description": "The expense record.",
        +      "type": "object"
        +    },
        +    "reviewExpenseUrl": {
        +      "type": "string"
        +    },
        +    "rowNumber": {
        +      "description": "Resolved sheet row for the expense.",
        +      "type": "integer"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_expense_splits1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "splits": {
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_income_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Two branches. Async: type='analytics_pending' with jobId — poll poll_analytics until complete. Inline: message + data with the computed analytics (data may be null when there is no spreadsheet or no data yet). success is present only on the async branch.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "Inline branch: computed analytics, or null when no spreadsheet / no data.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "estimatedTime": {
        +      "description": "Async branch only: seconds.",
        +      "type": "number"
        +    },
        +    "jobId": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "message": {
        +      "description": "Human-readable narrative (both branches).",
        +      "type": "string"
        +    },
        +    "pollEndpoint": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "pollInterval": {
        +      "description": "Async branch only: milliseconds.",
        +      "type": "number"
        +    },
        +    "response": {
        +      "description": "Chat alias of message.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Async branch only.",
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "description": "Async branch only: \"analytics_pending\" — poll pollEndpoint or call poll_analytics with jobId.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_mileage_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Success returns message + data with the computed summary; success is not emitted on the inline analytics path.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Present only on the error branch (out of scope) / async path.",
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_monthly_books_review1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_per_tag_pnl1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Two branches. Async: type='analytics_pending' with jobId — poll poll_analytics until complete. Inline: message + data with the computed analytics (data may be null when there is no spreadsheet or no data yet). success is present only on the async branch.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "Inline branch: computed analytics, or null when no spreadsheet / no data.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "estimatedTime": {
        +      "description": "Async branch only: seconds.",
        +      "type": "number"
        +    },
        +    "jobId": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "message": {
        +      "description": "Human-readable narrative (both branches).",
        +      "type": "string"
        +    },
        +    "pollEndpoint": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "pollInterval": {
        +      "description": "Async branch only: milliseconds.",
        +      "type": "number"
        +    },
        +    "response": {
        +      "description": "Chat alias of message.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Async branch only.",
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "description": "Async branch only: \"analytics_pending\" — poll pollEndpoint or call poll_analytics with jobId.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_pnl1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Two branches. Async: type='analytics_pending' with jobId — poll poll_analytics until complete. Inline: message + data with the computed analytics (data may be null when there is no spreadsheet or no data yet). success is present only on the async branch.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "Inline branch: computed analytics, or null when no spreadsheet / no data.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "estimatedTime": {
        +      "description": "Async branch only: seconds.",
        +      "type": "number"
        +    },
        +    "jobId": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "message": {
        +      "description": "Human-readable narrative (both branches).",
        +      "type": "string"
        +    },
        +    "pollEndpoint": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "pollInterval": {
        +      "description": "Async branch only: milliseconds.",
        +      "type": "number"
        +    },
        +    "response": {
        +      "description": "Chat alias of message.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Async branch only.",
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "description": "Async branch only: \"analytics_pending\" — poll pollEndpoint or call poll_analytics with jobId.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_recent_activity1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "actions": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "actionId": {
        +            "type": "string"
        +          },
        +          "durationMs": {
        +            "type": "number"
        +          },
        +          "success": {
        +            "type": "boolean"
        +          },
        +          "timestamp": {
        +            "type": "string"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "count": {
        +      "type": "integer"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "count",
        +    "actions"
        +  ],
        +  "type": "object"
        +}
    • Changedget_report_details1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "report": {
        +      "additionalProperties": true,
        +      "description": "The full stored report record.",
        +      "type": "object"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "report"
        +  ],
        +  "type": "object"
        +}
    • Changedget_scan_status1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Authoritative live scan state. Fields may sit at the top level or under data depending on the branch; nothing beyond success is guaranteed, so treat each as optional.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": "object"
        +    },
        +    "gmailScanUrl": {
        +      "type": "string"
        +    },
        +    "latestScan": {
        +      "additionalProperties": true,
        +      "description": "Most recent scan outcome (success, emailsFound, emailsTagged, timestamp).",
        +      "type": "object"
        +    },
        +    "lock": {
        +      "additionalProperties": true,
        +      "description": "Scan-lock state (active, startedAt, ageSeconds, dispatchComplete, pendingProcessingCount).",
        +      "type": "object"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "reviewExpensesUrl": {
        +      "type": "string"
        +    },
        +    "scanInProgress": {
        +      "type": "boolean"
        +    },
        +    "spreadsheetUrl": {
        +      "type": "string"
        +    },
        +    "status": {
        +      "description": "Scan lifecycle state.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedget_spending_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Two branches. Async: type='analytics_pending' with jobId — poll poll_analytics until complete. Inline: message + data with the computed analytics (data may be null when there is no spreadsheet or no data yet). success is present only on the async branch.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "Inline branch: computed analytics, or null when no spreadsheet / no data.",
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "estimatedTime": {
        +      "description": "Async branch only: seconds.",
        +      "type": "number"
        +    },
        +    "jobId": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "message": {
        +      "description": "Human-readable narrative (both branches).",
        +      "type": "string"
        +    },
        +    "pollEndpoint": {
        +      "description": "Async branch only.",
        +      "type": "string"
        +    },
        +    "pollInterval": {
        +      "description": "Async branch only: milliseconds.",
        +      "type": "number"
        +    },
        +    "response": {
        +      "description": "Chat alias of message.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Async branch only.",
        +      "type": "boolean"
        +    },
        +    "type": {
        +      "description": "Async branch only: \"analytics_pending\" — poll pollEndpoint or call poll_analytics with jobId.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_subscription_audit1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "description": "Success returns message + data with the computed summary; success is not emitted on the inline analytics path.",
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "type": [
        +        "object",
        +        "null"
        +      ]
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "description": "Present only on the error branch (out of scope) / async path.",
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [],
        +  "type": "object"
        +}
    • Changedget_trip_suggestions1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "count": {
        +      "type": "integer"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "proposals": {
        +      "description": "Read-only trip proposals; accepting one continues through group_expenses.",
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_categories1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "billingAccounts": {
        +      "description": "Billing/card accounts, when configured.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "categories": {
        +      "description": "Expense categories for the user.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "categories"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_client_invoices1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "invoices": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {
        +          "advanceApplied": {
        +            "type": "number"
        +          },
        +          "clientName": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "currency": {
        +            "type": "string"
        +          },
        +          "displayStatus": {
        +            "enum": [
        +              "open",
        +              "overdue",
        +              "paid",
        +              "void",
        +              "superseded",
        +              "needs_review"
        +            ],
        +            "type": "string"
        +          },
        +          "grandTotal": {
        +            "type": "number"
        +          },
        +          "invoiceId": {
        +            "type": "string"
        +          },
        +          "invoiceNumber": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "issueDate": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "status": {
        +            "type": "string"
        +          },
        +          "total": {
        +            "type": "number"
        +          }
        +        },
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "invoices"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_income_categories1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "categories": {
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "legacy": {
        +      "description": "Deprecated income categories still accepted on read.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "notes": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "categories"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_reports1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "creationStatus": {
        +      "description": "Provenance of the listing, e.g. \"existing_only\".",
        +      "type": "string"
        +    },
        +    "filter": {
        +      "type": "string"
        +    },
        +    "limit": {
        +      "type": "integer"
        +    },
        +    "page": {
        +      "type": "integer"
        +    },
        +    "reports": {
        +      "description": "Present when the user has reports.",
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "responseGuidance": {
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "creationStatus"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_tags1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "success": {
        +      "type": "boolean"
        +    },
        +    "tags": {
        +      "description": "Client / project / trip groups (Column K values).",
        +      "items": {
        +        "additionalProperties": true,
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "success",
        +    "tags"
        +  ],
        +  "type": "object"
        +}
    • Changedwhatif_afford1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "The full what-if scenario: assumptions, evidence, and computed outcome.",
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Scenario narrative; may be absent if the scenario carried no template or evidence.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedwhatif_client1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "The full what-if scenario: assumptions, evidence, and computed outcome.",
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Scenario narrative; may be absent if the scenario carried no template or evidence.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
    • Changedwhatif_tax_setaside1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "data": {
        +      "additionalProperties": true,
        +      "description": "The full what-if scenario: assumptions, evidence, and computed outcome.",
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Scenario narrative; may be absent if the scenario carried no template or evidence.",
        +      "type": "string"
        +    },
        +    "success": {
        +      "type": "boolean"
        +    }
        +  },
        +  "required": [
        +    "success"
        +  ],
        +  "type": "object"
        +}
  4. 2 tool updates
    • Changedcreate_report1 field changed
      • addedInput schema / properties / recipientRole
        Added value: +{
        +  "default": "reviewer",
        +  "description": "Access for every shareWith recipient. Use reviewer for one-report review, comments, approval, or change requests. Use accountant only when the user explicitly wants ongoing report management and accounting-software access.",
        +  "enum": [
        +    "reviewer",
        +    "accountant"
        +  ],
        +  "type": "string"
        +}
    • Changedshare_report1 field changed
      • addedInput schema / properties / recipientRole
        Added value: +{
        +  "default": "reviewer",
        +  "description": "Use reviewer for report-only approval. Use accountant only for explicit ongoing accountant access.",
        +  "enum": [
        +    "reviewer",
        +    "accountant"
        +  ],
        +  "type": "string"
        +}
  5. 1 tool update
    • Changedsearch_knowledge1 field changed
      • changedInput schema / properties / fullAnswer / description
        Previous value: -"Set true to return complete article answers instead of short excerpts."New value: +"Set true on the first call for complete, detailed, or step-by-step instructions. Leave false for discovery or quick-answer excerpts."
  6. 57 tool updates
    • Changedadd_cash_expense1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedadd_income1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedadd_income_from_csv1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedadd_income_from_file1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedadd_mileage_entry1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedcheck_compliance1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedcheck_feature1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedcheck_tax_deductibility1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedcorrect_expenses1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedcreate_client_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedcreate_report1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedexport_report1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedfix_compliance1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_accounting_integration_status1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_accounting_push_status1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_client_advance_balances1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_client_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_credits_refunds1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_deep_analytics1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_expense_by_id1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_expense_splits1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_income_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_last_receipt_result18 fields changed
      • addedOutput schema / allOf
        Added value: +[
        +  {
        +    "if": {
        +      "properties": {
        +        "found": {
        +          "const": true
        +        }
        +      },
        +      "required": [
        +        "found"
        +      ]
        +    },
        +    "then": {
        +      "required": [
        +        "verdict",
        +        "counts",
        +        "receipts",
        +        "submissionId",
        +        "spreadsheetUrl",
        +        "reviewExpensesUrl",
        +        "data",
        +        "timestamp"
        +      ]
        +    }
        +  }
        +]
      • changedOutput schema / description
        Previous value: -"Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple."New value: +"found:false means processing is still pending; found:true is a terminal result."
      • addedOutput schema / properties / counts
        Added value: +{
        +  "additionalProperties": true,
        +  "properties": {
        +    "added": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "duplicates": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "errors": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "skipped": {
        +      "minimum": 0,
        +      "type": "integer"
        +    },
        +    "submitted": {
        +      "minimum": 0,
        +      "type": "integer"
        +    }
        +  },
        +  "required": [
        +    "submitted",
        +    "added",
        +    "duplicates",
        +    "skipped",
        +    "errors"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / data / description
        Removed value: -"Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results."
      • removedOutput schema / properties / error
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Present only when success === false.",
        -  "properties": {
        -    "code": {
        -      "type": "string"
        -    },
        -    "hint": {
        -      "type": "string"
        -    },
        -    "message": {
        -      "type": "string"
        -    }
        -  },
        -  "type": "object"
        -}
      • addedOutput schema / properties / found
        Added value: +{
        +  "type": "boolean"
        +}
      • removedOutput schema / properties / message / description
        Removed value: -"Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning."
      • addedOutput schema / properties / receipts
        Added value: +{
        +  "items": {
        +    "additionalProperties": true,
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / reviewExpensesUrl
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / sampleMeta
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -  "properties": {
        -    "isTruncated": {
        -      "type": "boolean"
        -    },
        -    "sampleCount": {
        -      "type": "integer"
        -    },
        -    "totalCount": {
        -      "type": "integer"
        -    }
        -  },
        -  "type": "object"
        -}
      • addedOutput schema / properties / spreadsheetUrl
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / state
        Added value: +{
        +  "const": "processing",
        +  "description": "Present on pending polls for a specific submission.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / submissionId
        Added value: +{
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / success / const
        Added value: +true
      • removedOutput schema / properties / success / description
        Removed value: -"False on tool errors; check before reading `data`."
      • addedOutput schema / properties / timestamp
        Added value: +{
        +  "format": "date-time",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / verdict
        Added value: +{
        +  "description": "Terminal branch only.",
        +  "enum": [
        +    "added",
        +    "duplicate",
        +    "skipped",
        +    "errored",
        +    "mixed",
        +    "unknown"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / required
        Added value: +[
        +  "success",
        +  "found",
        +  "message"
        +]
    • Changedget_mileage_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_monthly_books_review1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_per_tag_pnl1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_pnl1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_recent_activity1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_report_details1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_scan_status1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_spending_summary1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_spreadsheet_url16 fields changed
      • removedOutput schema / description
        Removed value: -"Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple."
      • addedOutput schema / properties / dashboardUrl
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / data / description
        Removed value: -"Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results."
      • removedOutput schema / properties / error
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Present only when success === false.",
        -  "properties": {
        -    "code": {
        -      "type": "string"
        -    },
        -    "hint": {
        -      "type": "string"
        -    },
        -    "message": {
        -      "type": "string"
        -    }
        -  },
        -  "type": "object"
        -}
      • addedOutput schema / properties / gmailActionNeededUrl
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / gmailScanUrl
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / message / description
        Removed value: -"Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning."
      • addedOutput schema / properties / reportsUrl
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / reviewExpensesUrl
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / reviewIncomeUrl
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / sampleMeta
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -  "properties": {
        -    "isTruncated": {
        -      "type": "boolean"
        -    },
        -    "sampleCount": {
        -      "type": "integer"
        -    },
        -    "totalCount": {
        -      "type": "integer"
        -    }
        -  },
        -  "type": "object"
        -}
      • addedOutput schema / properties / spreadsheetId
        Added value: +{
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedOutput schema / properties / spreadsheetUrl
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / success / const
        Added value: +true
      • removedOutput schema / properties / success / description
        Removed value: -"False on tool errors; check before reading `data`."
      • addedOutput schema / required
        Added value: +[
        +  "success",
        +  "spreadsheetId",
        +  "spreadsheetUrl",
        +  "reviewExpensesUrl",
        +  "reviewIncomeUrl",
        +  "gmailScanUrl",
        +  "gmailActionNeededUrl",
        +  "reportsUrl",
        +  "dashboardUrl",
        +  "data",
        +  "message"
        +]
    • Changedget_subscription_audit1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedget_trip_suggestions1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedgroup_expenses1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedlist_categories1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedlist_client_invoices1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedlist_income_categories1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedlist_reports1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedlist_tags1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedmark_client_invoice_paid1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedparse_expense1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedprepare_client_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedprocess_gmail_receipts1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedrequest_accounting_integration1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedscan_gmail1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedscan_gmail_years1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedsearch_expenses15 fields changed
      • removedOutput schema / description
        Removed value: -"Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple."
      • addedOutput schema / properties / count
        Added value: +{
        +  "description": "Rows matched by the filters.",
        +  "type": "integer"
        +}
      • removedOutput schema / properties / data
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -  "type": "object"
        -}
      • removedOutput schema / properties / error
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Present only when success === false.",
        -  "properties": {
        -    "code": {
        -      "type": "string"
        -    },
        -    "hint": {
        -      "type": "string"
        -    },
        -    "message": {
        -      "type": "string"
        -    }
        -  },
        -  "type": "object"
        -}
      • addedOutput schema / properties / expenses
        Added value: +{
        +  "description": "Matching expense rows, newest first, paginated.",
        +  "items": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "amount": {
        +        "description": "Functional/home-currency amount.",
        +        "type": "number"
        +      },
        +      "category": {
        +        "type": "string"
        +      },
        +      "currency": {
        +        "description": "Home currency code when available.",
        +        "type": "string"
        +      },
        +      "date": {
        +        "type": "string"
        +      },
        +      "dateIso": {
        +        "description": "Canonical YYYY-MM-DD when available.",
        +        "type": "string"
        +      },
        +      "expenseId": {
        +        "description": "Durable Receipt ID (Column Q). The only identity accepted by update_expense.",
        +        "type": "string"
        +      },
        +      "location": {
        +        "type": "string"
        +      },
        +      "matchReason": {
        +        "type": "string"
        +      },
        +      "matchedFields": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "merchant": {
        +        "type": "string"
        +      },
        +      "originalAmount": {
        +        "type": "number"
        +      },
        +      "originalCurrency": {
        +        "type": "string"
        +      },
        +      "tag": {
        +        "description": "Column K group (client/project/trip).",
        +        "type": "string"
        +      },
        +      "updateEligible": {
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "expenseId",
        +      "date",
        +      "amount",
        +      "tag",
        +      "updateEligible"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / hasMore
        Added value: +{
        +  "type": "boolean"
        +}
      • removedOutput schema / properties / message / description
        Removed value: -"Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning."
      • addedOutput schema / properties / nextCursor
        Added value: +{
        +  "description": "Opaque signed continuation; reuse with identical filters.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / pageInfo
        Added value: +{
        +  "additionalProperties": true,
        +  "type": "object"
        +}
      • addedOutput schema / properties / queryApplied
        Added value: +{
        +  "type": "string"
        +}
      • removedOutput schema / properties / sampleMeta
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -  "properties": {
        -    "isTruncated": {
        -      "type": "boolean"
        -    },
        -    "sampleCount": {
        -      "type": "integer"
        -    },
        -    "totalCount": {
        -      "type": "integer"
        -    }
        -  },
        -  "type": "object"
        -}
      • removedOutput schema / properties / success
        Removed value: -{
        -  "description": "False on tool errors; check before reading `data`.",
        -  "type": "boolean"
        -}
      • addedOutput schema / properties / total
        Added value: +{
        +  "description": "Sum of the matched set in home currency.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / totalMatched
        Added value: +{
        +  "description": "Present for free-text searches.",
        +  "type": "integer"
        +}
      • addedOutput schema / required
        Added value: +[
        +  "expenses",
        +  "count",
        +  "total"
        +]
    • Changedsearch_knowledge8 fields changed
      • removedOutput schema / description
        Removed value: -"Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple."
      • removedOutput schema / properties / data
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -  "type": "object"
        -}
      • removedOutput schema / properties / error
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Present only when success === false.",
        -  "properties": {
        -    "code": {
        -      "type": "string"
        -    },
        -    "hint": {
        -      "type": "string"
        -    },
        -    "message": {
        -      "type": "string"
        -    }
        -  },
        -  "type": "object"
        -}
      • removedOutput schema / properties / message
        Removed value: -{
        -  "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -  "type": "string"
        -}
      • addedOutput schema / properties / results
        Added value: +{
        +  "items": {
        +    "additionalProperties": true,
        +    "properties": {
        +      "answer": {
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "question": {
        +        "type": "string"
        +      },
        +      "relevance": {
        +        "type": "number"
        +      },
        +      "truncated": {
        +        "type": "boolean"
        +      },
        +      "type": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "question",
        +      "answer"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • removedOutput schema / properties / sampleMeta
        Removed value: -{
        -  "additionalProperties": true,
        -  "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -  "properties": {
        -    "isTruncated": {
        -      "type": "boolean"
        -    },
        -    "sampleCount": {
        -      "type": "integer"
        -    },
        -    "totalCount": {
        -      "type": "integer"
        -    }
        -  },
        -  "type": "object"
        -}
      • removedOutput schema / properties / success / description
        Removed value: -"False on tool errors; check before reading `data`."
      • addedOutput schema / required
        Added value: +[
        +  "success",
        +  "results"
        +]
    • Changedsend_report_to_accounting1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedshare_report1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedsubmit_receipt1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedtrace_document1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedupdate_expense1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedwhatif_afford1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedwhatif_client1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
    • Changedwhatif_tax_setaside1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "additionalProperties": true,
        -  "description": "Standard ExpenseBot tool result envelope. `message` is the human-readable summary the AI cites; `data` is the structured payload (totals, breakdowns, ids, etc.). On failure, `success` is false and `error` carries a code/message/hint triple.",
        -  "properties": {
        -    "data": {
        -      "additionalProperties": true,
        -      "description": "Structured payload. Shape varies per tool — common keys: total, breakdown, comparison, sampleMeta, ids, expenseId, reportId, signupUrl, results.",
        -      "type": "object"
        -    },
        -    "error": {
        -      "additionalProperties": true,
        -      "description": "Present only when success === false.",
        -      "properties": {
        -        "code": {
        -          "type": "string"
        -        },
        -        "hint": {
        -          "type": "string"
        -        },
        -        "message": {
        -          "type": "string"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "message": {
        -      "description": "Human-readable result text. Always present on success; prefer rendering this verbatim before any further reasoning.",
        -      "type": "string"
        -    },
        -    "sampleMeta": {
        -      "additionalProperties": true,
        -      "description": "Set when the underlying dataset was truncated. isTruncated=true means the agent saw a sample of `sampleCount` of `totalCount` rows; aggregate totals are still accurate.",
        -      "properties": {
        -        "isTruncated": {
        -          "type": "boolean"
        -        },
        -        "sampleCount": {
        -          "type": "integer"
        -        },
        -        "totalCount": {
        -          "type": "integer"
        -        }
        -      },
        -      "type": "object"
        -    },
        -    "success": {
        -      "description": "False on tool errors; check before reading `data`.",
        -      "type": "boolean"
        -    }
        -  },
        -  "type": "object"
        -}New value: +null
  7. 3 tool updates
    • Changedget_accounting_integration_status2 fields changed
      • changedInput schema / properties / provider / description
        Previous value: -"Accounting destination provider."New value: +"Accounting destination provider. QuickBooks Online, Xero, Wave, FreeAgent (beta), or Zoho Books."
      • changedInput schema / properties / provider / enum
        Previous value: -[
        -  "zoho_books"
        -]New value: +[
        +  "zoho_books",
        +  "quickbooks",
        +  "xero",
        +  "wave",
        +  "freeagent"
        +]
    • Changedget_accounting_push_status1 field changed
      • changedInput schema / properties / provider / enum
        Previous value: -[
        -  "zoho_books"
        -]New value: +[
        +  "zoho_books",
        +  "quickbooks",
        +  "xero",
        +  "wave",
        +  "freeagent"
        +]
    • Changedsend_report_to_accounting2 fields changed
      • changedInput schema / properties / mode / description
        Previous value: -"Step 1 only: automatic document treatment, paid expenses, or bills."New value: +"Step 1 only (Zoho Books): automatic document treatment, paid expenses, or bills."
      • changedInput schema / properties / provider / description
        Previous value: -"Accounting destination provider."New value: +"Accounting destination provider. Agent-driven posting is currently available only for Zoho Books."
  8. 13 tool updates
    • Changedadd_income_from_csv6 fields changed
      • changedInput schema / properties / csvContent / description
        Previous value: -"Raw CSV/TSV/text content (step 1). On ChatGPT you may pass the attached file reference object directly; the server fetches and decodes the bytes."New value: +"Attached CSV/TSV/text file supplied by ChatGPT for step 1. The server downloads and decodes the attachment securely."
      • addedInput schema / properties / csvContent / properties
        Added value: +{
        +  "download_url": {
        +    "description": "Temporary HTTPS URL supplied by ChatGPT for downloading the attachment.",
        +    "format": "uri",
        +    "type": "string"
        +  },
        +  "file_id": {
        +    "description": "Attachment identifier supplied by ChatGPT.",
        +    "type": "string"
        +  },
        +  "file_name": {
        +    "description": "Original attachment filename supplied by ChatGPT.",
        +    "type": "string"
        +  },
        +  "mime_type": {
        +    "description": "Attachment MIME type supplied by ChatGPT.",
        +    "type": "string"
        +  }
        +}
      • addedInput schema / properties / csvContent / required
        Added value: +[
        +  "download_url",
        +  "file_id"
        +]
      • changedInput schema / properties / csvContent / type
        Previous value: -"string"New value: +"object"
      • addedInput schema / properties / csvText
        Added value: +{
        +  "description": "Legacy fallback for MCP clients that send raw CSV/TSV/text content inline. ChatGPT should use csvContent.",
        +  "type": "string"
        +}
      • addedInput schema / properties / rowEdits / items / properties / fields / description
        Added value: +"Only the user-approved income fields to replace on this staged row: date, source, amount, currency, category, paymentMethod, description, notes, reference, fees, taxCollected, or tag."
    • Changedadd_income_from_file6 fields changed
      • changedInput schema / properties / photo / description
        Previous value: -"Base64-encoded image/PDF bytes (step 1). On ChatGPT you may pass the attached file reference object directly; the server fetches the bytes."New value: +"Attached image or PDF supplied by ChatGPT for step 1. The server downloads and parses the attachment securely."
      • addedInput schema / properties / photo / properties
        Added value: +{
        +  "download_url": {
        +    "description": "Temporary HTTPS URL supplied by ChatGPT for downloading the attachment.",
        +    "format": "uri",
        +    "type": "string"
        +  },
        +  "file_id": {
        +    "description": "Attachment identifier supplied by ChatGPT.",
        +    "type": "string"
        +  },
        +  "file_name": {
        +    "description": "Original attachment filename supplied by ChatGPT.",
        +    "type": "string"
        +  },
        +  "mime_type": {
        +    "description": "Attachment MIME type supplied by ChatGPT.",
        +    "type": "string"
        +  }
        +}
      • addedInput schema / properties / photo / required
        Added value: +[
        +  "download_url",
        +  "file_id"
        +]
      • changedInput schema / properties / photo / type
        Previous value: -"string"New value: +"object"
      • addedInput schema / properties / photoBase64
        Added value: +{
        +  "description": "Legacy fallback for MCP clients that send complete image/PDF bytes as base64. ChatGPT should use photo.",
        +  "type": "string"
        +}
      • addedInput schema / properties / rowEdits / items / properties / fields / description
        Added value: +"Only the user-approved income fields to replace on this staged row: date, source, amount, currency, category, paymentMethod, description, notes, reference, fees, taxCollected, or tag."
    • Changedadd_mileage_entry1 field changed
      • addedInput schema / properties / notes / description
        Added value: +"Optional user-supplied context stored with the mileage entry."
    • Changedcorrect_expenses8 fields changed
      • addedInput schema / properties / change / properties / attendees / description
        Added value: +"Attendee names explicitly supplied by the user when type is attendees; never infer names."
      • addedInput schema / properties / change / properties / businessPurpose / description
        Added value: +"User-supplied business purpose to apply when type is businessPurpose."
      • addedInput schema / properties / change / properties / category / description
        Added value: +"Configured expense category to apply when type is category."
      • addedInput schema / properties / change / properties / type / description
        Added value: +"The one correction kind to apply to every exact selected expense."
      • addedInput schema / properties / selection / description
        Added value: +"Exact expenses returned by search_expenses and approved for this bounded correction."
      • addedInput schema / properties / selection / properties / items / description
        Added value: +"One exact receipt identity per selected expense; never broaden this list after preview."
      • addedInput schema / properties / selection / properties / items / items / properties / expected / properties / category / description
        Added value: +"Current category observed before preview for conflict detection."
      • addedInput schema / properties / selection / properties / items / items / properties / expected / properties / notes / description
        Added value: +"Current structured Notes value observed before preview for conflict detection."
    • Changedcreate_report1 field changed
      • addedInput schema / properties / categories / description
        Added value: +"Optional configured expense categories to include in the report."
    • Changedget_accounting_push_status2 fields changed
      • addedInput schema / properties / provider / description
        Added value: +"Accounting destination provider used for the prior posting attempt."
      • addedInput schema / properties / reportId / description
        Added value: +"Exact ExpenseBot report ID from the prior proposal or posting attempt."
    • Changedget_client_invoice2 fields changed
      • changedInput schema / properties / invoiceId / description
        Previous value: -"Stable invoice ID from list_client_invoices."New value: +"Stable invoice ID from list_client_invoices. Required unless invoiceNumber is supplied."
      • changedInput schema / properties / invoiceNumber / description
        Previous value: -"Human invoice number when invoiceId is unavailable."New value: +"Human invoice number when invoiceId is unavailable; it must identify one unique invoice."
    • Changedget_spending_summary1 field changed
      • addedInput schema / properties / categories / description
        Added value: +"Optional configured expense categories to include in the summary."
    • Changedgroup_expenses7 fields changed
      • addedInput schema / properties / group / description
        Added value: +"The user-named destination group to apply to every eligible selected expense."
      • addedInput schema / properties / group / properties / kind / description
        Added value: +"How to label the destination in user-facing confirmation text."
      • addedInput schema / properties / reportTitle / description
        Added value: +"Optional title when createReport is true; otherwise ExpenseBot derives one from the group."
      • addedInput schema / properties / selection / description
        Added value: +"Exact expenses returned by search_expenses and approved for this bounded operation."
      • addedInput schema / properties / selection / properties / items / description
        Added value: +"One exact receipt identity per selected expense; never broaden this list after preview."
      • addedInput schema / properties / selection / properties / items / items / properties / expected / description
        Added value: +"Optional current state copied from search results for conflict detection."
      • addedInput schema / properties / selection / properties / items / items / properties / expected / properties / tag / description
        Added value: +"Current group/tag value observed before preview; an empty string means ungrouped."
    • Changedlist_reports3 fields changed
      • addedInput schema / properties / filter / description
        Added value: +"Optional report-status filter; All returns every authorized status."
      • addedInput schema / properties / limit / description
        Added value: +"Maximum reports to return on this page."
      • addedInput schema / properties / page / description
        Added value: +"One-based results page to return."
    • Changedprepare_client_invoice6 fields changed
      • addedInput schema / properties / clientAddress / description
        Added value: +"Optional billing address printed in the invoice's Bill To section."
      • addedInput schema / properties / customLineItems / items / properties / amount / description
        Added value: +"Positive amount for this fee or service line in the invoice currency."
      • addedInput schema / properties / customLineItems / items / properties / description / description
        Added value: +"User-approved fee or service description shown on the invoice."
      • addedInput schema / properties / mentionSupportingReceipts / description
        Added value: +"When true, note on the invoice that supporting receipts are available."
      • addedInput schema / properties / paymentTerms / description
        Added value: +"Invoice due terms. Defaults to the client's billing profile or net30."
      • addedInput schema / properties / taxPct / description
        Added value: +"Tax percentage applied after markup and custom line items; use 0 for no tax."
    • Changedsend_report_to_accounting2 fields changed
      • addedInput schema / properties / reportingTagMappings / additionalProperties / properties / optionId / description
        Added value: +"Live option ID belonging to tagId, returned in the step-1 proposal."
      • addedInput schema / properties / reportingTagMappings / additionalProperties / properties / tagId / description
        Added value: +"Live accounting-provider reporting-tag ID returned in the step-1 proposal."
    • Changedsubmit_receipt5 fields changed
      • changedInput schema / properties / photo / description
        Previous value: -"Base64-encoded image or PDF data (JPEG, PNG, HEIC, WebP, or PDF). Max 15MB. Only for small images — large payloads get truncated or dropped in transit; use uploadRef instead."New value: +"Single attached receipt image or PDF supplied by ChatGPT. For multiple files or large files, use filesToUpload and uploadRefs instead."
      • addedInput schema / properties / photo / properties
        Added value: +{
        +  "download_url": {
        +    "description": "Temporary HTTPS URL supplied by ChatGPT for downloading the attachment.",
        +    "format": "uri",
        +    "type": "string"
        +  },
        +  "file_id": {
        +    "description": "Attachment identifier supplied by ChatGPT.",
        +    "type": "string"
        +  },
        +  "file_name": {
        +    "description": "Original attachment filename supplied by ChatGPT.",
        +    "type": "string"
        +  },
        +  "mime_type": {
        +    "description": "Attachment MIME type supplied by ChatGPT.",
        +    "type": "string"
        +  }
        +}
      • addedInput schema / properties / photo / required
        Added value: +[
        +  "download_url",
        +  "file_id"
        +]
      • changedInput schema / properties / photo / type
        Previous value: -"string"New value: +"object"
      • addedInput schema / properties / photoBase64
        Added value: +{
        +  "description": "Legacy fallback for MCP clients that send one small image as complete base64 data. ChatGPT should use photo or uploadRefs instead.",
        +  "type": "string"
        +}
  9. 5 tool updates
    • Changedcreate_client_invoice16 fields changed
      • addedInput schema / additionalProperties
        Added value: +false
      • removedInput schema / properties / advanceApplied
        Removed value: -{
        -  "minimum": 0,
        -  "type": "number"
        -}
      • removedInput schema / properties / billToEmail
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / clientAddress
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / clientName
        Removed value: -{
        -  "description": "In in-app chat, the full client name shown on the invoice.",
        -  "type": "string"
        -}
      • removedInput schema / properties / customLineItems
        Removed value: -{
        -  "items": {
        -    "properties": {
        -      "amount": {
        -        "exclusiveMinimum": 0,
        -        "type": "number"
        -      },
        -      "description": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "description",
        -      "amount"
        -    ],
        -    "type": "object"
        -  },
        -  "maxItems": 25,
        -  "type": "array"
        -}
      • removedInput schema / properties / invoiceNumber
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / issueDate
        Removed value: -{
        -  "description": "In in-app chat, a calendar-valid YYYY-MM-DD invoice date.",
        -  "type": "string"
        -}
      • removedInput schema / properties / markupPct
        Removed value: -{
        -  "maximum": 100,
        -  "minimum": 0,
        -  "type": "number"
        -}
      • removedInput schema / properties / mentionSupportingReceipts
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / paymentTerms
        Removed value: -{
        -  "enum": [
        -    "due_on_receipt",
        -    "net7",
        -    "net14",
        -    "net15",
        -    "net30",
        -    "net45",
        -    "net60"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / receiptIds
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedInput schema / properties / reportId
        Removed value: -{
        -  "description": "In in-app chat, the saved report ID to prepare and confirm.",
        -  "type": "string"
        -}
      • removedInput schema / properties / taxLabel
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / taxPct
        Removed value: -{
        -  "maximum": 100,
        -  "minimum": 0,
        -  "type": "number"
        -}
      • addedInput schema / required
        Added value: +[
        +  "preparationId"
        +]
    • Changedget_credits_refunds4 fields changed
      • addedInput schema / properties / dateRange / additionalProperties
        Added value: +false
      • changedInput schema / properties / dateRange / description
        Previous value: -"Optional window to narrow results. Both bounds inclusive, YYYY-MM-DD."New value: +"Optional open-ended or closed window to narrow results. Supply startDate, endDate, or both; supplied bounds are inclusive YYYY-MM-DD dates."
      • addedInput schema / properties / dateRange / properties / endDate / format
        Added value: +"date"
      • addedInput schema / properties / dateRange / properties / startDate / format
        Added value: +"date"
    • Changedget_expense_splits4 fields changed
      • addedInput schema / properties / dateRange / additionalProperties
        Added value: +false
      • changedInput schema / properties / dateRange / description
        Previous value: -"Optional window to search for split expenses. Both bounds inclusive, YYYY-MM-DD."New value: +"Optional open-ended or closed window to search for split expenses. Supply startDate, endDate, or both; supplied bounds are inclusive YYYY-MM-DD dates."
      • addedInput schema / properties / dateRange / properties / endDate / format
        Added value: +"date"
      • addedInput schema / properties / dateRange / properties / startDate / format
        Added value: +"date"
    • Changedmark_client_invoice_paid1 field changed
      • addedInput schema / properties / paidDate / format
        Added value: +"date"
    • Changedprepare_client_invoice1 field changed
      • addedInput schema / properties / issueDate / format
        Added value: +"date"
  10. 5 tool updates
    • Addedcreate_client_invoice
    • Addedget_client_invoice
    • Changedlist_client_invoices2 fields changed
      • changedInput schema / properties / status / description
        Previous value: -"Filter by invoice status (default open)."New value: +"Filter by invoice status (default active/outstanding)."
      • changedInput schema / properties / status / enum
        Previous value: -[
        -  "open",
        -  "paid",
        -  "all"
        -]New value: +[
        +  "active",
        +  "open",
        +  "overdue",
        +  "needs_review",
        +  "paid",
        +  "void",
        +  "superseded",
        +  "all"
        +]
    • Addedmark_client_invoice_paid
    • Addedprepare_client_invoice
  11. 2 tool updates
    • Changedget_client_advance_balances2 fields changed
      • changedInput schema / properties / clientName / description
        Previous value: -"Optional client name or canonical Client tag. Omit to list all open balances."New value: +"Optional client name or canonical Client tag. Omit to list every open balance backed by a recorded client advance."
      • removedInput schema / properties / days
        Removed value: -{
        -  "description": "Lookback window in days (default 365).",
        -  "maximum": 3650,
        -  "minimum": 30,
        -  "type": "integer"
        -}
    • Addedrequest_accounting_integration
  12. 1 tool update
    • Addedget_trip_suggestions
  13. 1 tool update
    • Changedget_accounting_integration_status1 field changed
      • addedInput schema / properties / reportId
        Added value: +{
        +  "description": "Optional existing ExpenseBot report ID. When supplied, setupUrl opens this exact report and highlights the selected accounting provider's setup control.",
        +  "type": "string"
        +}
  14. 3 tool updates
    • Addedget_accounting_integration_status
    • Addedget_accounting_push_status
    • Addedsend_report_to_accounting
  15. 1 tool update
    • Addedget_client_advance_balances
  16. 49 tool updates
    • First observedadd_cash_expense
    • First observedadd_income
    • First observedadd_income_from_csv
    • First observedadd_income_from_file
    • First observedadd_mileage_entry
    • First observedcheck_compliance
    • First observedcheck_feature
    • First observedcheck_tax_deductibility
    • First observedcorrect_expenses
    • First observedcreate_report
    • First observedexport_report
    • First observedfetch
    • First observedfix_compliance
    • First observedget_credits_refunds
    • First observedget_deep_analytics
    • First observedget_expense_by_id
    • First observedget_expense_splits
    • First observedget_income_summary
    • First observedget_last_receipt_result
    • First observedget_mileage_summary
    • First observedget_monthly_books_review
    • First observedget_per_tag_pnl
    • First observedget_pnl
    • First observedget_recent_activity
    • First observedget_report_details
    • First observedget_scan_status
    • First observedget_spending_summary
    • First observedget_spreadsheet_url
    • First observedget_subscription_audit
    • First observedgroup_expenses
    • First observedlist_categories
    • First observedlist_client_invoices
    • First observedlist_income_categories
    • First observedlist_reports
    • First observedlist_tags
    • First observedparse_expense
    • First observedprocess_gmail_receipts
    • First observedscan_gmail
    • First observedscan_gmail_years
    • First observedsearch
    • First observedsearch_expenses
    • First observedsearch_knowledge
    • First observedshare_report
    • First observedsubmit_receipt
    • First observedtrace_document
    • First observedupdate_expense
    • First observedwhatif_afford
    • First observedwhatif_client
    • First observedwhatif_tax_setaside

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to perform financial analysis, budget forecasting, compliance checks, expense categorization, and risk assessment, returning structured JSON with audit-ready governance receipts.
    5
    81 npm
    1
    Business Source 1.1
  • F
    license
    Not graded
    quality
    D
    maintenance
    Approval receipts for AI browser purchases. Enables purchase evaluation, approval recording, budget alerts, and receipt export.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Manage your finances through natural language directly in your AI assistant. Add, edit, delete, and query expenses; set monthly budgets; and generate comprehensive spending reports seamlessly.
    1
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to inspect and extract invoice metadata from PDFs, Word documents, Excel files, and images, then synchronize and enrich the extracted data into an Excel ledger.
    -
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.