ExpenseBot
REMOTE · MCP.EXPENSEBOT.AI · 2 COMPONENTS · SCANNED SEP 20
Capture receipts, scan Gmail, analyze spending, and create reviewed reports from AI assistants.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score → Why this is hard to score →
Endpoint Security63
- The endpoint's TLS certificate is valid, in date, and uses a strong key. View diagnostics → Pass
- Authorisation check failed: no authorisation is required to call this server, and it exposes a tool marked destructive (share_report). See how to fix → View diagnostics → Fail
- HTTPS is enforced; there's no plaintext access path. View diagnostics → Pass
- The HSTS (Strict-Transport-Security) header is present. View diagnostics → Pass
- DNSSEC check failed: this domain isn't protected by DNSSEC. See how to fix → View diagnostics → Fail
Transport & Reachability100
- Verified streamable-http transport via a live MCP handshake. View diagnostics → Pass
Schema Quality & AI Usability64
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 14731 tokens (~249/item across 59 items; 59 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management96
- Stability check failed: schema churn in the 30 days we've observed: 0 tool removals, 5 breaking changes, 0 auth/transport breaks, 0 additions. See how to fix → Fail
Tool Coverage99
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 97% of tool parameters carry a description.Partial
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 1 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 60 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
How do I install the ExpenseBot MCP server?
ExpenseBot is a hosted endpoint at https://mcp.expensebot.ai/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
remote · mcp.expensebot.ai
claude mcp add --transport http totesmagotes-mcp-server-auth 'https://mcp.expensebot.ai/mcp'
{
"mcpServers": {
"totesmagotes-mcp-server-auth": {
"url": "https://mcp.expensebot.ai/mcp"
}
}
} {
"servers": {
"totesmagotes-mcp-server-auth": {
"type": "http",
"url": "https://mcp.expensebot.ai/mcp"
}
}
} [mcp_servers.totesmagotes-mcp-server-auth] url = "https://mcp.expensebot.ai/mcp"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"totesmagotes-mcp-server-auth": {
"type": "remote",
"url": "https://mcp.expensebot.ai/mcp",
"enabled": true
}
}
} openclaw mcp add totesmagotes-mcp-server-auth --url 'https://mcp.expensebot.ai/mcp' --transport streamable-http
mcp_servers:
totesmagotes-mcp-server-auth:
url: "https://mcp.expensebot.ai/mcp" {
"McpServers": {
"totesmagotes-mcp-server-auth": {
"Transport": "http",
"Url": "https://mcp.expensebot.ai/mcp"
}
}
} assistant mcp add totesmagotes-mcp-server-auth -t streamable-http -u 'https://mcp.expensebot.ai/mcp'
{
"mcpServers": {
"totesmagotes-mcp-server-auth": {
"type": "http",
"url": "https://mcp.expensebot.ai/mcp"
}
}
} The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 10 Sept 26 +2
- A breaking change shipped without a version bump: still 0.3.1-m3.6 ▼ security
- Tool “update_expense” rewrote its description, which is the text the model reads security
- Tool “fix_compliance” rewrote its description, which is the text the model reads security
- Tool “add_income” rewrote its description, which is the text the model reads security
- “fix_compliance” added a required parameter “operationId”, so existing callers break ▼ functional
- “fix_compliance” dropped the required parameter “value” ▼ functional
- “fix_compliance” dropped the required parameter “reportId” ▼ functional
- “fix_compliance” dropped the required parameter “action” ▼ functional
- Tool coverage: 61% → 100% ▲ functional
- Tool “trace_document” now declares an output schema ▲ functional
- Tool “submit_receipt” now declares an output schema ▲ functional
- Tool “update_expense” now declares an output schema ▲ functional
- Tool “fix_compliance” now declares an output schema ▲ functional
- Tool “export_report” now declares an output schema ▲ functional
- Tool “create_report” now declares an output schema ▲ functional
- Tool “create_client_invoice” now declares an output schema ▲ functional
- Tool “correct_expenses” now declares an output schema ▲ functional
- Tool “add_mileage_entry” now declares an output schema ▲ functional
- Tool “add_income_from_file” now declares an output schema ▲ functional
- Tool “add_income_from_csv” now declares an output schema ▲ functional
- Tool “add_income” now declares an output schema ▲ functional
- Tool “add_cash_expense” now declares an output schema ▲ functional
- Tool “group_expenses” now declares an output schema ▲ functional
- Tool “mark_client_invoice_paid” now declares an output schema ▲ functional
- Tool “parse_expense” now declares an output schema ▲ functional
- Tool “prepare_client_invoice” now declares an output schema ▲ functional
- Tool “process_gmail_receipts” now declares an output schema ▲ functional
- Tool “request_accounting_integration” now declares an output schema ▲ functional
- Tool “scan_gmail” now declares an output schema ▲ functional
- Tool “scan_gmail_years” now declares an output schema ▲ functional
- Tool “send_report_to_accounting” now declares an output schema ▲ functional
- Tool “share_report” now declares an output schema ▲ functional
- “fix_compliance” added an optional parameter “selection” cosmetic
- “fix_compliance” added an optional parameter “confirm” cosmetic
- “fix_compliance” added an optional parameter “change” cosmetic
- “fix_compliance” added an optional parameter “status” cosmetic
- “fix_compliance” added an optional parameter “undo” cosmetic
- 9 Sept 26 +4
- Tool coverage: 10% → 61% ▲ functional
- Tool “get_expense_splits” now declares an output schema ▲ functional
- Tool “get_expense_by_id” now declares an output schema ▲ functional
- Tool “get_deep_analytics” now declares an output schema ▲ functional
- Tool “get_credits_refunds” now declares an output schema ▲ functional
- Tool “get_client_invoice” now declares an output schema ▲ functional
- Tool “get_client_advance_balances” now declares an output schema ▲ functional
- Tool “get_accounting_push_status” now declares an output schema ▲ functional
- Tool “get_accounting_integration_status” now declares an output schema ▲ functional
- Tool “check_tax_deductibility” now declares an output schema ▲ functional
- Tool “check_feature” now declares an output schema ▲ functional
- Tool “check_compliance” now declares an output schema ▲ functional
- Tool “get_subscription_audit” now declares an output schema ▲ functional
- Tool “get_spending_summary” now declares an output schema ▲ functional
- Tool “list_categories” now declares an output schema ▲ functional
- Tool “list_client_invoices” now declares an output schema ▲ functional
- Tool “list_income_categories” now declares an output schema ▲ functional
- Tool “list_reports” now declares an output schema ▲ functional
- Tool “list_tags” now declares an output schema ▲ functional
- Tool “whatif_afford” now declares an output schema ▲ functional
- Tool “whatif_client” now declares an output schema ▲ functional
- Tool “whatif_tax_setaside” now declares an output schema ▲ functional
- Tool “get_trip_suggestions” now declares an output schema ▲ functional
- Tool “get_scan_status” now declares an output schema ▲ functional
- Tool “get_report_details” now declares an output schema ▲ functional
- Tool “get_recent_activity” now declares an output schema ▲ functional
- Tool “get_pnl” now declares an output schema ▲ functional
- Tool “get_per_tag_pnl” now declares an output schema ▲ functional
- Tool “get_monthly_books_review” now declares an output schema ▲ functional
- Tool “get_mileage_summary” now declares an output schema ▲ functional
- Tool “get_income_summary” now declares an output schema ▲ functional
- 8 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 46 to 49.
- 6 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 39 to 43.
- 4 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 33 to 36.
- 2 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 26 to 29.
- 31 Aug 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 19 to 23.
- 29 Aug 26 +1
- Tool “share_report” rewrote its description, which is the text the model reads security
- “create_report” added an optional parameter “recipientRole” cosmetic
- “share_report” added an optional parameter “recipientRole” cosmetic
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 20 Sept 2026 · Probed https://mcp.expensebot.ai/mcp
TLS valid
Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .
| Subject | Issuer | Valid from | Valid until | Key | Signature | Serial |
|---|---|---|---|---|---|---|
| CN=mcp.expensebot.ai | CN=YR2,O=Let's Encrypt,C=US | 8 Sept 2026 | 7 Dec 2026 | RSA 2048 | SHA256-RSA | 69f8cf9d11963ed221401116573c17f0a84 |
| SANs: mcp.expensebot.ai | ||||||
| CN=YR2,O=Let's Encrypt,C=US (CA) | CN=Root YR,O=ISRG,C=US | 3 Sept 2025 | 2 Sept 2028 | RSA 2048 | SHA256-RSA | 4ebd24947e24d394802d84a52fd5b319 |
| CN=Root YR,O=ISRG,C=US (CA) | CN=ISRG Root X1,O=Internet Security Research Group,C=US | 13 May 2026 | 2 Sept 2032 | RSA 4096 | SHA256-RSA | f24b6d17f9d9ad7cb1c9fea78782699f |
Background: What to check on a remote MCP endpoint →
DNSSEC insecure
Validation of mcp.expensebot.ai. — Not signed
| Zone | DS | Keys | Algorithms | Outcome |
|---|---|---|---|---|
| . | trust_anchor | 20326, 38696 | 8, 8 | Verified |
| ai. | present | 3799 | 8 | Verified |
| expensebot.ai. | absent | Unsigned (proven) parent-signed NSEC/NSEC3 proves an unsigned delegation |
Authentication No authorisation required
The endpoint answered without asking for a token. Anyone who knows the URL can reach it.
| Result | No authorisation required |
|---|---|
| HTTP status | 200 |
| Header | Value |
|---|---|
| strict-transport-security | max-age=63072000 |
Background: How OAuth 2.1 works in the 2026 MCP spec →
Transports 2 probes
| Transport | URL | Outcome | Status | Location |
|---|---|---|---|---|
| streamable-http | https://mcp.expensebot.ai/mcp | Verified | 200 | |
| http (plaintext) | http://mcp.expensebot.ai/mcp | HTTPS enforced | 308 | https://mcp.expensebot.ai/mcp |
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
add_cash_expense ~366
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.
| Name | Type | Req | Description |
|---|---|---|---|
| category | string | – | A configured Expense Account returned by list_categories. Do not invent a category. |
| city | string | – | City/location |
| clientName | string | – | Client name for a client advance, in ordinary language. ExpenseBot resolves the canonical Client – Name group. |
| currency | string | – | Currency code (default: USD) |
| date | string | yes | Expense date (YYYY-MM-DD) |
| isClientAdvance | boolean | – | True only when a client supplied money in advance for expenses. Requires clientName and does not require category. |
| merchant | string | – | Merchant/vendor name for an ordinary expense. Not needed for a client advance; ExpenseBot derives it from clientName. |
| notes | string | – | Notes or description |
| subtotal | number | – | Subtotal before tax |
| tax | number | – | Tax amount |
| tip | number | – | Tip amount |
| total | number | yes | Positive amount paid or received. ExpenseBot stores a client advance as negative. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| expense | object | – | – |
| finalAnswer | string | – | – |
| message | string | yes | – |
| recordId | string | – | – |
| responseGuidance | string | – | – |
| reviewExpensesUrl | string | – | – |
| rowNumber | integer | – | – |
| spreadsheetUrl | string|null | – | – |
| success | boolean | yes | – |
No examples provided.
add_income ~337
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.
| Name | Type | Req | Description |
|---|---|---|---|
| amount | number | yes | Income amount (>0) |
| category | string | – | A category returned by list_income_categories (optional; defaults to Service income) |
| currency | string | – | Currency code (default: home currency) |
| date | string | – | Income date (YYYY-MM-DD). Defaults to today. |
| description | string | – | What the income was for |
| fees | number | – | Processor/transfer fees deducted |
| notes | string | – | – |
| paymentMethod | string | yes | How 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. |
| reference | string | – | Invoice or transaction reference |
| source | string | yes | Who paid you (client name, customer, etc.) |
| tag | string | – | Tag for client/project attribution |
| taxCollected | number | – | Sales tax/GST/HST collected |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| deduped | boolean | – | – |
| destinations | object | – | – |
| finalAnswer | string | – | – |
| matchedRow | object | – | – |
| message | string | yes | – |
| recordId | string | – | – |
| responseGuidance | string | – | – |
| rowNumber | integer | – | – |
| success | boolean | yes | – |
| tabCreated | boolean | – | – |
No examples provided.
add_income_from_csv ~592
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.
| Name | Type | Req | Description |
|---|---|---|---|
| bulkNote | string | – | Step 2 only: one note (max 120 chars) prepended to every confirmed row's Notes, same as the app's 'Add note to all entries'. |
| confirm | boolean | – | Step 2 only: true writes the staged rows. Omit it (with previewId absent) to parse and preview without writing. |
| csvContent | object | – | Attached CSV/TSV/text file supplied by ChatGPT for step 1. The server downloads and decodes the attachment securely. |
| csvText | string | – | Legacy fallback for MCP clients that send raw CSV/TSV/text content inline. ChatGPT should use csvContent. |
| keepBothIndexes | array | – | Step 2 only: preview indexes of duplicate-flagged rows the user explicitly wants to keep anyway (the app's 'Keep Both'). |
| paymentMethod | string | – | Fallback payment rail for rows where the parser found none (Cash, Check, Bank transfer, Wallet app, Credit/Debit card, Payment processor, or Other). |
| previewId | string | – | Step 2 only: the previewId returned by the step-1 call. |
| rowEdits | array | – | Step 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. |
| selectedIndexes | array | – | Step 2 only: preview row indexes to write. Omit to write all staged rows. |
| tag | string | – | Optional client/project tag. In step 1 it pre-fills the staged rows; in step 2 it applies to the confirmed selection. |
| Name | Type | Req | Description |
|---|---|---|---|
| confirmationContract | string | – | – |
| confirmed | boolean | – | – |
| deduped | integer | – | – |
| duplicateCount | integer | – | – |
| duplicates | array | – | – |
| entries | array | – | – |
| entryCount | integer | – | – |
| expiresAt | string | – | – |
| expiresInMinutes | integer | – | – |
| failed | integer | – | – |
| finalAnswer | string | – | – |
| idempotentReplay | boolean | – | – |
| maxChatEntries | integer | – | – |
| message | string | yes | – |
| preview | boolean | – | – |
| previewId | string | – | – |
| projectionTruncated | boolean | – | – |
| refundRowCount | integer | – | – |
| rejectedRows | array | – | – |
| responseGuidance | string | – | – |
| reviewImportUrl | string | – | – |
| reviewIncomeUrl | string | – | – |
| spreadsheetUrl | string|null | – | – |
| success | boolean | yes | – |
| tooLargeForChat | boolean | – | – |
| total | integer | – | – |
| totalsByCurrency | object | – | – |
| unattempted | integer | – | – |
| warnings | array | – | – |
| written | integer | – | – |
No examples provided.
add_income_from_file ~654
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.
| Name | Type | Req | Description |
|---|---|---|---|
| bulkNote | string | – | Step 2 only: one note (max 120 chars) prepended to every confirmed row's Notes, same as the app's 'Add note to all entries'. |
| confirm | boolean | – | Step 2 only: true writes the staged rows. Omit it (with previewId absent) to parse and preview without writing. |
| keepBothIndexes | array | – | Step 2 only: preview indexes of duplicate-flagged rows the user explicitly wants to keep anyway (the app's 'Keep Both'). |
| mimeType | string | – | MIME type of the file (default: image/jpeg) |
| paymentMethod | string | – | Fallback payment rail for rows where the parser found none (Cash, Check, Bank transfer, Wallet app, Credit/Debit card, Payment processor, or Other). |
| photo | object | – | Attached image or PDF supplied by ChatGPT for step 1. The server downloads and parses the attachment securely. |
| photoBase64 | string | – | Legacy fallback for MCP clients that send complete image/PDF bytes as base64. ChatGPT should use photo. |
| previewId | string | – | Step 2 only: the previewId returned by the step-1 call. |
| rowEdits | array | – | Step 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. |
| selectedIndexes | array | – | Step 2 only: preview row indexes to write. Omit to write all staged rows. |
| tag | string | – | Optional client/project tag. In step 1 it pre-fills the staged rows; in step 2 it applies to the confirmed selection. |
| Name | Type | Req | Description |
|---|---|---|---|
| confirmationContract | string | – | – |
| confirmed | boolean | – | – |
| deduped | integer | – | – |
| duplicateCount | integer | – | – |
| duplicates | array | – | – |
| entries | array | – | – |
| entryCount | integer | – | – |
| expiresAt | string | – | – |
| expiresInMinutes | integer | – | – |
| failed | integer | – | – |
| finalAnswer | string | – | – |
| idempotentReplay | boolean | – | – |
| maxChatEntries | integer | – | – |
| message | string | yes | – |
| preview | boolean | – | – |
| previewId | string | – | – |
| projectionTruncated | boolean | – | – |
| refundRowCount | integer | – | – |
| rejectedRows | array | – | – |
| responseGuidance | string | – | – |
| reviewImportUrl | string | – | – |
| reviewIncomeUrl | string | – | – |
| spreadsheetUrl | string|null | – | – |
| success | boolean | yes | – |
| tooLargeForChat | boolean | – | – |
| total | integer | – | – |
| totalsByCurrency | object | – | – |
| unattempted | integer | – | – |
| warnings | array | – | – |
| written | integer | – | – |
No examples provided.
add_mileage_entry ~270
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.
| Name | Type | Req | Description |
|---|---|---|---|
| category | string | – | Override the user's default mileage category (optional) |
| city | string | – | City (optional) |
| date | string | – | Trip date (YYYY-MM-DD). Defaults to today. |
| destination | string | – | Destination address or location (optional) |
| distance | number | yes | Distance traveled in the user's configured unit (miles or km) |
| notes | string | – | Optional user-supplied context stored with the mileage entry. |
| purpose | string | yes | Business purpose / description of the trip (e.g., 'Client meeting at 1234 Main St') |
| roundTrip | boolean | – | If true, doubles the distance (return trip) |
| tag | string | – | Tag for client/project attribution (optional) |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| finalAnswer | string | – | – |
| message | string | yes | – |
| responseGuidance | string | – | – |
| reviewExpensesUrl | string | – | – |
| rowNumber | integer | – | – |
| settings | object | – | – |
| spreadsheetUrl | string|null | – | – |
| success | boolean | yes | – |
No examples provided.
check_compliance ~119
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.
| Name | Type | Req | Description |
|---|---|---|---|
| reportId | string | yes | Report ID to check |
| userRequest | string | yes | The user's exact request explicitly asking for compliance, policy, audit, substantiation, or business-purpose analysis. Do not paraphrase or invent intent. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
check_feature ~80
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.
| Name | Type | Req | Description |
|---|---|---|---|
| feature | string | yes | Feature or integration to check (e.g., 'Xero', 'mileage tracking', 'Plaid') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
check_tax_deductibility ~162
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).
| Name | Type | Req | Description |
|---|---|---|---|
| category | string | – | – |
| merchant | string | – | – |
| query | string | yes | Deductibility question (e.g., 'is Uber tax deductible', 'home office write-off rules') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
correct_expenses ~382
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.
| Name | Type | Req | Description |
|---|---|---|---|
| change | object | – | Exactly one correction. The selected type determines which matching value field is required. |
| confirm | boolean | – | Omit/false for preview; true only after explicit approval. |
| operationId | string | yes | Stable idempotency key generated once for preview and reused unchanged. |
| selection | object | – | Exact expenses returned by search_expenses and approved for this bounded correction. |
| status | boolean | – | Read operation status using operationId. |
| undo | boolean | – | Undo a completed correction within its Undo window. |
| Name | Type | Req | Description |
|---|---|---|---|
| change | object | – | – |
| confirmation | object | – | – |
| finalAnswer | string | – | – |
| manifest | object | – | – |
| message | string | – | – |
| operationId | string | – | – |
| preview | object | – | – |
| requiresConfirmation | boolean | – | – |
| responseGuidance | string | – | – |
| reviewExpensesUrl | string | – | – |
| status | string | yes | – |
| success | boolean | yes | – |
| undo | object | – | – |
No examples provided.
create_client_invoice ~145
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.
| Name | Type | Req | Description |
|---|---|---|---|
| confirmTax | boolean | – | True only after the user confirms the displayed tax label and rate. |
| operationId | string | – | Optional retry key. Reuse it after an uncertain response. |
| preparationId | string | yes | Short-lived ID returned by prepare_client_invoice. |
| Name | Type | Req | Description |
|---|---|---|---|
| advanceApplied | number | – | – |
| artifactWarning | string | – | – |
| clientName | string|null | – | – |
| currency | string | – | – |
| documentUrl | string|null | – | – |
| docxUrl | string|null | – | – |
| dueDate | string|null | – | – |
| grandTotal | number | – | – |
| invoiceId | string|null | – | – |
| invoiceNumber | string|null | – | – |
| issueDate | string|null | – | – |
| pdfUrl | string|null | – | – |
| recovered | boolean | – | – |
| sourceReportId | string|null | – | – |
| status | string | – | – |
| success | boolean | yes | – |
| total | number | – | – |
No examples provided.
create_report ~457
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.
| Name | Type | Req | Description |
|---|---|---|---|
| categories | array | – | Optional configured expense categories to include in the report. |
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| excludePersonal | boolean | – | Exclude expenses whose Tag is Personal or whose Expense Category is Personal. |
| excludedCategories | array | – | Expense categories to exclude from the report. |
| excludedTags | array | – | Existing ExpenseBot groups to exclude from the report. |
| recipientRole | string | – | 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 acco… |
| shareWith | array | – | Email addresses to share the report with |
| tags | array | – | Existing ExpenseBot groups to include, such as a client, project, project code, property, or trip. Use list_tags first when uncertain. |
| title | string | – | Custom report title |
| Name | Type | Req | Description |
|---|---|---|---|
| accountingHandoffUrls | object | – | – |
| accountingSetupUrl | string | – | – |
| billClientUrl | string | – | – |
| creationStatus | string | – | – |
| data | object | – | – |
| finalAnswer | string | – | – |
| nextActions | array | – | – |
| reportId | string | – | – |
| reportUrl | string | – | – |
| responseGuidance | string | – | – |
| success | boolean | yes | – |
No examples provided.
export_report ~82
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.
| Name | Type | Req | Description |
|---|---|---|---|
| reportId | string | yes | Report ID from list_reports |
| Name | Type | Req | Description |
|---|---|---|---|
| availableInReport | array | yes | – |
| expiresAt | string | yes | – |
| notes | string | yes | – |
| report | object | yes | – |
| success | boolean | yes | – |
| urls | object | yes | – |
No examples provided.
fetch ~192
Fetch full details for a specific item returned by `search`. The id encodes the item type: • 'expense:<rowNumber>' — e.g., 'expense:42' for row 42 of the user's Expenses tab • 'report:<reportId>' — 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.
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Item ID from a previous `search` or `list_reports` call. Format: 'expense:<row>' (integer row number) or 'report:<reportId>' (alphanumeric Firestore doc id, ~20 chars). |
| Name | Type | Req | Description |
|---|---|---|---|
| id | string | yes | Echoed back from the input |
| metadata | object | – | – |
| text | string | yes | Full text content for the AI to cite |
| title | string | yes | – |
| url | string | – | – |
No examples provided.
fix_compliance ~292
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.
| Name | Type | Req | Description |
|---|---|---|---|
| change | object | – | Exactly one correction. The selected type determines which matching value field is required. |
| confirm | boolean | – | Omit/false for preview; true only after explicit approval. |
| operationId | string | yes | Stable idempotency key generated once for preview and reused unchanged. |
| selection | object | – | Exact expenses returned by search_expenses and approved for this bounded correction. |
| status | boolean | – | Read operation status using operationId. |
| undo | boolean | – | Undo a completed correction within its Undo window. |
| Name | Type | Req | Description |
|---|---|---|---|
| change | object | – | – |
| confirmation | object | – | – |
| finalAnswer | string | – | – |
| manifest | object | – | – |
| message | string | – | – |
| operationId | string | – | – |
| preview | object | – | – |
| requiresConfirmation | boolean | – | – |
| responseGuidance | string | – | – |
| reviewExpensesUrl | string | – | – |
| status | string | yes | – |
| success | boolean | yes | – |
| undo | object | – | – |
No examples provided.
get_accounting_integration_status ~220
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.
| Name | Type | Req | Description |
|---|---|---|---|
| provider | string | yes | Accounting destination provider. QuickBooks Online, Xero, Wave, FreeAgent (beta), or Zoho Books. |
| reportId | string | – | Optional existing ExpenseBot report ID. When supplied, setupUrl opens this exact report and highlights the selected accounting provider's setup control. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | Per-provider connection and rollout state. |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
get_accounting_push_status ~131
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.
| Name | Type | Req | Description |
|---|---|---|---|
| provider | string | yes | Accounting destination provider used for the prior posting attempt. |
| reportId | string | yes | Exact ExpenseBot report ID from the prior proposal or posting attempt. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
get_client_advance_balances ~169
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| clientName | string | – | Optional client name or canonical Client tag. Omit to list every open balance backed by a recorded client advance. |
| Name | Type | Req | Description |
|---|---|---|---|
| balances | array | – | – |
| data | object | – | – |
| homeCurrency | string | – | – |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
get_client_invoice ~149
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| invoiceId | string | – | Stable invoice ID from list_client_invoices. Required unless invoiceNumber is supplied. |
| invoiceNumber | string | – | Human invoice number when invoiceId is unavailable; it must identify one unique invoice. |
| Name | Type | Req | Description |
|---|---|---|---|
| invoice | object | – | The invoice record. Absent only on the error branch (not-found), which never carries structuredContent. |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
get_credits_refunds ~174
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| dateRange | object | – | Optional open-ended or closed window to narrow results. Supply startDate, endDate, or both; supplied bounds are inclusive YYYY-MM-DD dates. |
| limit | number | – | Maximum results to return (default 25, max 100). |
| Name | Type | Req | Description |
|---|---|---|---|
| credits | array | – | – |
| data | object | – | – |
| message | string | – | – |
| refunds | array | – | – |
| success | boolean | yes | – |
No examples provided.
get_deep_analytics ~125
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.
| Name | Type | Req | Description |
|---|---|---|---|
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| query | string | yes | The analytics question to answer |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | Inline branch: computed analytics, or null when no spreadsheet / no data. |
| estimatedTime | number | – | Async branch only: seconds. |
| jobId | string | – | Async branch only. |
| message | string | – | Human-readable narrative (both branches). |
| pollEndpoint | string | – | Async branch only. |
| pollInterval | number | – | Async branch only: milliseconds. |
| response | string | – | Chat alias of message. |
| success | boolean | – | Async branch only. |
| type | string | – | Async branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId. |
No examples provided.
get_expense_by_id ~110
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.
| Name | Type | Req | Description |
|---|---|---|---|
| expenseId | string | – | Exact full ExpenseBot Receipt ID from Column Q |
| rowNumber | integer | – | 1-indexed sheet row (row 1 is headers, so ≥ 2) |
| Name | Type | Req | Description |
|---|---|---|---|
| expense | object | – | The expense record. |
| reviewExpenseUrl | string | – | – |
| rowNumber | integer | – | Resolved sheet row for the expense. |
| success | boolean | yes | – |
No examples provided.
get_expense_splits ~218
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| dateRange | object | – | Optional open-ended or closed window to search for split expenses. Supply startDate, endDate, or both; supplied bounds are inclusive YYYY-MM-DD dates. |
| limit | number | – | Max parent expenses to return (default 25, max 100). |
| onlySplit | boolean | – | Return only expenses with active splits (default true). Set false to inspect an unsplit Receipt ID. |
| receiptId | string | – | Optional Receipt ID for one expense. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| message | string | – | – |
| splits | array | – | – |
| success | boolean | yes | – |
No examples provided.
get_income_summary ~313
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? } }.
| Name | Type | Req | Description |
|---|---|---|---|
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| groupBy | string | – | How to group the breakdown |
| incomeTagPrefix | string | – | Optional 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. |
| query | string | – | Natural language income question (e.g., 'income YTD by source', 'rental income last month') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | Inline branch: computed analytics, or null when no spreadsheet / no data. |
| estimatedTime | number | – | Async branch only: seconds. |
| jobId | string | – | Async branch only. |
| message | string | – | Human-readable narrative (both branches). |
| pollEndpoint | string | – | Async branch only. |
| pollInterval | number | – | Async branch only: milliseconds. |
| response | string | – | Chat alias of message. |
| success | boolean | – | Async branch only. |
| type | string | – | Async branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId. |
No examples provided.
get_last_receipt_result ~222
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.
| Name | Type | Req | Description |
|---|---|---|---|
| submissionId | string | – | Exact submissionId returned by submit_receipt. Strongly preferred because it binds the result to this upload instead of an earlier receipt. |
| withinSeconds | integer | – | Fallback lookback window when submissionId is unavailable (30-3600 seconds; default 600). |
| Name | Type | Req | Description |
|---|---|---|---|
| counts | object | – | – |
| data | object | – | – |
| found | boolean | yes | – |
| message | string | yes | – |
| receipts | array | – | – |
| reviewExpensesUrl | string | – | – |
| spreadsheetUrl | string|null | – | – |
| state | string | – | Present on pending polls for a specific submission. |
| submissionId | string|null | – | – |
| success | boolean | yes | – |
| timestamp | string|null | – | – |
| verdict | string | – | Terminal branch only. |
No examples provided.
get_mileage_summary ~186
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? } }.
| Name | Type | Req | Description |
|---|---|---|---|
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| groupBy | string | – | How to group the breakdown |
| query | string | – | Natural language mileage question (e.g., 'mileage this year', 'miles driven for Acme client') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | – |
| message | string | – | – |
| success | boolean | – | Present only on the error branch (out of scope) / async path. |
No examples provided.
get_monthly_books_review ~145
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| period | string | – | Calendar month in YYYY-MM format. Defaults to the last completed month. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| message | string | – | – |
| success | boolean | yes | – |
No examples provided.
get_per_tag_pnl ~256
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.
| Name | Type | Req | Description |
|---|---|---|---|
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| query | string | – | Natural language per-tag P&L question |
| tagPrefix | string | – | Optional prefix to limit which tags are bucketed (e.g., 'Prop –' for properties only, 'Client –' for clients only). When omitted, all tags are included. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | Inline branch: computed analytics, or null when no spreadsheet / no data. |
| estimatedTime | number | – | Async branch only: seconds. |
| jobId | string | – | Async branch only. |
| message | string | – | Human-readable narrative (both branches). |
| pollEndpoint | string | – | Async branch only. |
| pollInterval | number | – | Async branch only: milliseconds. |
| response | string | – | Chat alias of message. |
| success | boolean | – | Async branch only. |
| type | string | – | Async branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId. |
No examples provided.
get_pnl ~229
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? } }.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| query | string | – | Natural language P&L question (e.g., 'P&L for Q1 2025', 'am I profitable') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | Inline branch: computed analytics, or null when no spreadsheet / no data. |
| estimatedTime | number | – | Async branch only: seconds. |
| jobId | string | – | Async branch only. |
| message | string | – | Human-readable narrative (both branches). |
| pollEndpoint | string | – | Async branch only. |
| pollInterval | number | – | Async branch only: milliseconds. |
| response | string | – | Chat alias of message. |
| success | boolean | – | Async branch only. |
| type | string | – | Async branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId. |
No examples provided.
get_recent_activity ~159
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).
| Name | Type | Req | Description |
|---|---|---|---|
| actionId | string | – | Optional: filter to a single tool/action name |
| limit | integer | – | – |
| sinceDays | integer | – | Only show actions from the last N days (default 7) |
| Name | Type | Req | Description |
|---|---|---|---|
| actions | array | yes | – |
| count | integer | yes | – |
| success | boolean | yes | – |
No examples provided.
get_report_details ~137
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| reportId | string | yes | The report/spreadsheet ID |
| userRequest | string | yes | The user's exact request asking to inspect this report. Do not paraphrase or invent diagnostic intent. |
| Name | Type | Req | Description |
|---|---|---|---|
| report | object | yes | The full stored report record. |
| success | boolean | yes | – |
No examples provided.
get_scan_status ~112
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.
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | – |
| gmailScanUrl | string|null | – | – |
| latestScan | object|null | – | Most recent scan outcome (success, emailsFound, emailsTagged, timestamp). |
| lock | object | – | Scan-lock state (active, startedAt, ageSeconds, dispatchComplete, pendingProcessingCount). |
| message | string | – | – |
| reviewExpensesUrl | string|null | – | – |
| scanInProgress | boolean | – | – |
| spreadsheetUrl | string|null | – | – |
| status | string|null | – | Scan lifecycle state. |
| success | boolean | yes | – |
No examples provided.
get_spending_summary ~183
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? } }.
| Name | Type | Req | Description |
|---|---|---|---|
| categories | array | – | Optional configured expense categories to include in the summary. |
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| groupBy | string | – | – |
| metric | string | – | – |
| query | string | – | Natural language question (e.g., 'how much did I spend in March', 'top merchants this quarter') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | Inline branch: computed analytics, or null when no spreadsheet / no data. |
| estimatedTime | number | – | Async branch only: seconds. |
| jobId | string | – | Async branch only. |
| message | string | – | Human-readable narrative (both branches). |
| pollEndpoint | string | – | Async branch only. |
| pollInterval | number | – | Async branch only: milliseconds. |
| response | string | – | Chat alias of message. |
| success | boolean | – | Async branch only. |
| type | string | – | Async branch only: "analytics_pending" — poll pollEndpoint or call poll_analytics with jobId. |
No examples provided.
get_spreadsheet_url ~622
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 i…
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| dashboardUrl | string | yes | – |
| data | object | yes | – |
| gmailActionNeededUrl | string | yes | – |
| gmailScanUrl | string | yes | – |
| message | string | yes | – |
| reportsUrl | string | yes | – |
| reviewExpensesUrl | string | yes | – |
| reviewIncomeUrl | string | yes | – |
| spreadsheetId | string | yes | – |
| spreadsheetUrl | string | yes | – |
| success | boolean | yes | – |
No examples provided.
get_subscription_audit ~160
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? } }.
| Name | Type | Req | Description |
|---|---|---|---|
| dateRange | – | – | Time period filter. Use exactly one variant — pick the shape that matches the user's phrasing. |
| focus | string | – | Narrow the audit to a single category (default: all) |
| query | string | – | Natural language subscription question (e.g., 'find duplicate subscriptions', 'price increases this year') |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|null | – | – |
| message | string | – | – |
| success | boolean | – | Present only on the error branch (out of scope) / async path. |
No examples provided.
get_trip_suggestions ~188
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.
| Name | Type | Req | Description |
|---|---|---|---|
| clientEmail | string | – | Client account email. Accountants may use this only for an accepted ExpenseBot client. |
| limit | integer | – | Maximum high-confidence proposals to return (default 3). |
| Name | Type | Req | Description |
|---|---|---|---|
| count | integer | – | – |
| message | string | – | – |
| proposals | array | – | Read-only trip proposals; accepting one continues through group_expenses. |
| success | boolean | yes | – |
No examples provided.
What is the ExpenseBot MCP server?
ExpenseBot is an MCP server listed in the public MCP registry as io.github.TotesMagotes/mcp-server-auth. Capture receipts, scan Gmail, analyze spending, and create reviewed reports from AI assistants. This page covers its hosted endpoint (https://mcp.expensebot.ai/mcp).
Is the ExpenseBot MCP server safe to use?
ExpenseBot scores 78 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the ExpenseBot MCP server expose?
ExpenseBot exposes 59 tools: search_expenses, get_spending_summary, get_deep_analytics, create_report, list_reports, and 54 more. Their descriptions and schemas cost roughly 13,521 tokens of context every time the server is loaded.
Does the ExpenseBot MCP server require authentication?
No. We connected to ExpenseBot without credentials and it answered, so anything it exposes is reachable by anyone who knows the address.
Is the ExpenseBot MCP server still maintained?
ExpenseBot is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.