MCP Server
Listed on the official MCP Registry

The evidence layer for your AI accounting workflow

Your agent stays the orchestrator. ExpenseBot gathers receipts and inbox documents, turns them into reviewed, source-linked records in your own Google Sheets and Drive, then prepares the handoff to the accountant or accounting system already in your workflow.

Choose your AI assistant

Pick the app you use. We’ll show only the setup you need — no MCP knowledge required.

OR JUMP TO:ChatGPT•Claude.ai•Gemini Spark•Claude Desktop•Cursor•Claude Code•Continue / Cline / Windsurf

Already know where you're going?

Open in ChatGPT →Open in Claude →Get token for desktop →

60-day free trial · No credit card · Hosted OAuth connections skip the token entirely

See it in action — receipt to spreadsheet, P&L summary, and accountant email, all in chat.

What people use it for

Mobile snapper

"Find my receipt photos from this week and submit them"

→ Photos parsed, categorized, in your spreadsheet

Inbox forwarder

"Scan my Gmail for any receipts I missed last month"

→ Hidden receipts found and added automatically

Quarterly closer

"Show me my profit by client this year"

→ Per-client revenue, costs, and profit table

Tax-time

"Generate a Schedule C report for 2025 and email it to my accountant"

→ Report built, accountant emailed, link delivered in chat

Which AI assistant do you use?

Pick the product you use. Each link goes directly to its setup instructions.

ChatGPT
No token or configuration file
Find ExpenseBot in ChatGPT's app directory, click Connect, and sign in. No settings file, no token.ChatGPT setup →
Claude.ai
No token or configuration file
Find ExpenseBot in Claude's connector directory, click Connect, and sign in. Availability can depend on workspace controls.Claude.ai setup →
Gemini Spark
Google account eligibility applies
Add https://mcp.expensebot.ai/mcp under Custom apps for Spark, then complete ExpenseBot browser sign-in. Eligibility depends on Google's current Spark requirements.See Gemini setup →
Viktor or another remote/custom agent
Browser sign-in
If the agent supports remote HTTP MCP with OAuth, add https://mcp.expensebot.ai/mcp. ExpenseBot handles browser sign-in and consent.See remote-agent setup →
Zapier MCP Client (beta)
Beta — verify before relying on it
Add https://mcp.expensebot.ai/mcp as a custom MCP connection, then authenticate in the browser — no client ID or secret to copy. Zapier's MCP Client is in beta; verify a read-only request before wiring it into anything.See Zapier setup →
Make.com (native app in review)
Not publicly installable yet
The native ExpenseBot app is built and submitted to Make, but it is not publicly installable yet. Check the status page or ask support about early access.View Make status →
Claude Desktop, Cursor, or a local agent
Uses a revocable token
Run the authenticated npm package locally and store a revocable token as EXPENSEBOT_TOKEN in the client's environment or secret settings.See desktop setup →

Choose the row with your product's name. For Claude Desktop, Cursor, Continue, Cline, or Windsurf, use the last row.

Connect ExpenseBot to ChatGPT

ExpenseBot is available in the ChatGPT app directory. No server URL or personal access token is required.

  1. Open ChatGPT → Settings → Apps, search for ExpenseBot, or open the ExpenseBot listing.
  2. Click Connect → Google login → Allow
  3. 62 submitted tools appear in your ChatGPT tool list. Try: "Find my receipt photos from last week and submit them to ExpenseBot"

Connect ExpenseBot to Claude.ai

ExpenseBot is listed in the Claude connectors directory, so there is no server URL to paste and no personal access token to manage. Claude currently makes remote connectors available across its plans, subject to workspace controls.

  1. In Claude, open Customize → Connectors and search ExpenseBot — or go straight to the ExpenseBot listing.
  2. Click Connect → sign in with the Google account you use for ExpenseBot → Allow on the consent screen.
  3. Try it: attach a receipt photo and type "Submit this Uber receipt to ExpenseBot"

ExpenseBot is listed as a Community connector. Claude shows a note before you connect saying it hasn't been reviewed in depth by Anthropic — that describes how much reviewing Anthropic did, not whether the connector works. Authentication is OAuth 2.1 with PKCE and Dynamic Client Registration, so there is no shared secret to copy or leak, and ExpenseBot is CASA Tier 2 certified across the whole data path.

Prefer the manual route (or using Claude Desktop)? It still works identically: Customize → Connectors → Add custom connector, server URL https://mcp.expensebot.ai/mcp, leaving all OAuth fields blank — DCR handles registration automatically.

Connect ExpenseBot to Gemini Spark

Gemini Spark supports custom Connected Apps through remote MCP. This is a direct custom connection, not a curated Gemini directory listing.

  1. On a computer, open Gemini.
  2. Open Settings & help → Connected Apps. If it is not shown, open Personal Intelligence → Connected Apps.
  3. Under Custom apps for Spark, choose Add a custom app and enter https://mcp.expensebot.ai/mcp.
  4. Click Next, then complete ExpenseBot sign-in and consent. Do not enter a personal token, client ID, or client secret; ExpenseBot supports Dynamic Client Registration and PKCE.
  5. In a Spark task, type @ and choose ExpenseBot when you want to route a request explicitly. Start with: "Show my top five expense categories this month. Do not change anything."
Check eligibility first. Google currently documents custom apps as a Gemini Spark feature for eligible adults using a personal Google Account with Keep Activity enabled. Work or school accounts are not supported for this flow, and current region/language restrictions apply. If Custom apps for Spark is missing, use ChatGPT, Claude, or another MCP client instead. Review Google's current requirements before troubleshooting.

Gemini currently asks for manual confirmation before a custom app performs a write action. ExpenseBot still applies its own preview and confirmation rules for sensitive changes. Disconnect or remove ExpenseBot from the same Connected Apps screen to revoke the connection.

Connect Viktor or another remote AI agent

Use this path when the agent supports remote HTTP MCP with OAuth. Add the server URL below; ExpenseBot opens its own browser sign-in and consent flow, so there is no token to send to the agent and no OAuth client secret to invent.

https://mcp.expensebot.ai/mcp
  1. In Viktor, open Integrations → Add custom MCP and paste the URL above.
  2. Use browser OAuth when Viktor offers it. Leave manual client ID and client-secret fields blank so Dynamic Client Registration can complete setup.
  3. If Viktor asks for a static credential instead, open AI Assistant Tokens, generate a token named Viktor, and place it only in Viktor's secure credential field. Never paste it into a conversation or email.
  4. Verify with: "Show my top five expense categories this month. Do not change anything."

Building a workflow rather than chatting with an assistant? Receipt collection over MCP covers the submit, wait, and branch contract for the receipt leg.

If the agent supports only local/stdio MCP, use the desktop package in the next section instead. An AI can guide the setup only if it has access to that client's configuration; it should never ask you to paste an ExpenseBot token into the conversation.

Prompt an AI can use to help configure itself
Help me connect this AI client to ExpenseBot through MCP.

ExpenseBot is the pre-accounting evidence layer. Keep this AI client as the orchestrator; use ExpenseBot to gather and review source-linked records, then hand the result to the accountant or accounting system already in the workflow.

1. First determine whether this client supports remote HTTP MCP with OAuth, or only local stdio MCP.
2. For remote OAuth MCP, add https://mcp.expensebot.ai/mcp and let me complete ExpenseBot sign-in and consent in the browser. Do not ask for a client secret.
3. For local stdio MCP, use: npx -y @expensebot/mcp-server-auth. Tell me where this client's MCP configuration lives, then have me store a newly generated ExpenseBot token as the EXPENSEBOT_TOKEN environment secret.
4. Never ask me to paste the token into chat. Never print, log, or save it in command arguments.
5. Verify the connection by listing tools and running one read-only request: "Show my top five expense categories this month."
6. Do not run any write action unless I explicitly approve it.
Live connection: ExpenseBot + Viktor + Zoho Books

A bookkeeping firm connected ExpenseBot to Viktor successfully and described its operating model this way: ExpenseBot captures receipt evidence, Viktor applies the firm's verification and reconciliation rules, and Zoho Books remains the accounting source of truth.

“The MCP connection itself is working well, and it gives us a practical way to combine ExpenseBot's receipt capture with Viktor's access to Zoho and our accounting rules.”— John, an accounting firm using ExpenseBot with its own AI agent

No custom integration was built for this. The firm connected ExpenseBot over MCP — the open standard for giving AI assistants and agents secure access to external tools — and pointed the agent it already runs at it. That is the whole setup.

Use ExpenseBot as the receipt-capture and evidence source, and Zoho Books as the accounting source of truth.

For each new or unsubmitted ExpenseBot receipt:
1. Look for the corresponding Zoho Books or bank-feed transaction using vendor, date, amount, currency, and available reference details.
2. Classify it as exact match, ambiguous match, or no match. Never silently discard unmatched search terms or invent a match.
3. For an exact match, recommend attaching the receipt to the existing transaction rather than creating a duplicate.
4. For an ambiguous or missing match, show the evidence and ask for approval before changing Zoho Books.
5. Reuse verified vendor and account mappings when available. Do not infer a new account code from merchant name alone.
6. Keep ExpenseBot and Zoho identifiers in the result so the decision can be traced later.

Start read-only. Show me the proposed matches and exceptions; do not create, attach, recode, or post anything until I approve.

ExpenseBot now also offers its own direct Zoho Books connection — an owner-only public beta with review-before-post feed matching (see Zoho Books). The agent workflow above is independent of it: Viktor holds the firm's own Zoho access, and this prompt gives it a review-first operating contract using the connections it already has.

Setting up Claude Desktop MCP? Use the npm package below — 63 authenticated tools plus CLI-friendly token rotation. The same package covers Cursor, Claude Code, and any other stdio client.

Connect Claude Desktop, Cursor, or a local agent

Claude Desktop speaks local stdio MCP, so it runs the @expensebot/mcp-server-auth package as a subprocess and authenticates with a revocable token rather than browser OAuth. Three steps below: generate the token, paste one JSON block into the Claude Desktop config, restart. The package is published on the official MCP Registry as io.github.TotesMagotes/mcp-server-auth. The identical config works in Cursor and other stdio clients — see the full desktop and custom-agent setup answer for per-OS config paths and token rotation.

  1. Generate a token. Open the signed-in AI Assistant Tokens screen, then choose Generate. Copy the token — it's shown once. Tokens are scoped to your account and can be revoked any time.
  2. Add to Claude Desktop config. Open the config file in any text editor:
    • Mac: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows: %APPDATA%\Claude\claude_desktop_config.json

    Paste this block (replace the token):

    {
      "mcpServers": {
        "expensebot": {
          "command": "npx",
          "args": ["-y", "@expensebot/mcp-server-auth"],
          "env": {
            "EXPENSEBOT_TOKEN": "your-personal-access-token-here"
          }
        }
      }
    }

    Just want the read-only docs server? No token needed:

    {
      "mcpServers": {
        "expensebot-docs": {
          "command": "npx",
          "args": ["-y", "@expensebot/mcp-server"]
        }
      }
    }
  3. Restart Claude Desktop and test. Fully quit and reopen Claude. Try "show me my top 5 software vendors last quarter". Claude will ask permission to run the get_spending_summary tool — approve once, and the integration is live.

Other MCP clients

The same npm package works with every MCP-compatible client — only the config location changes.

Claude Code (CLI)

One command — no JSON editing:

claude mcp add expensebot -- npx -y @expensebot/mcp-server-auth

Store EXPENSEBOT_TOKEN in Claude Code's environment or secret configuration first. Do not put the token in the command or paste it into chat. Add --scope user to make the server available across every project.

Cursor

Edit ~/.cursor/mcp.json:

{
  "mcpServers": {
    "expensebot": {
      "command": "npx",
      "args": ["-y", "@expensebot/mcp-server-auth"],
      "env": {
        "EXPENSEBOT_TOKEN": "your-personal-access-token-here"
      }
    }
  }
}

In Cursor: Settings → Tools & Integrations → look for the green dot next to expensebot. In chat, switch to Agent mode and prompt as usual.

Continue, Cline, Windsurf, custom MCP clients

Use npx -y @expensebot/mcp-server-auth in the client's MCP config and store the token as the EXPENSEBOT_TOKEN environment secret. If the client supports remote OAuth MCP, prefer the remote setup so no token is copied at all.

ChatGPT, Claude.ai, and eligible Gemini Spark accounts use the remote server at mcp.expensebot.ai — see setup instructions above ( ChatGPT, Claude.ai, and Gemini Spark ).

Security & trust

🔐
OAuth 2.1 + PKCE + DCR
No token copy/paste for ChatGPT or Claude.ai
🎛️
6 fine-grained scopes
Choose exactly what to share
🚫
Revoke anytime
Settings → AI Assistant Tokens
📋
All actions audit-logged
Full history in your account
🏅
CASA Tier 2 assessed
Independent assessment completed in 2026
🔒
SHA-256 hashed tokens
Max 5 per account, staff can't read them

What is the ExpenseBot MCP server?

MCP — the Model Context Protocol — is an open standard that lets AI assistants plug into outside tools and data using one consistent interface. Instead of every product building a one-off Claude plugin or ChatGPT plugin, the product publishes an MCP server and any MCP-compatible client speaks to it. Anthropic introduced the protocol in late 2024; it now ships natively in Claude Desktop, Cursor, Continue, and a growing list of clients.

ExpenseBot publishes two MCP servers on npm. The first, @expensebot/mcp-server, is read-only and unauthenticated — it exposes the public knowledge base and feature documentation so an AI assistant can answer "what is ExpenseBot?" or "does it work with Sage 50 Canada?" without any login. Useful for evaluation and for AI agents that want to cite our capabilities. The second, @expensebot/mcp-server-auth, is the full account-scoped version: 63 tools across search, capture, Gmail scan, reports, analytics, and document tracing, all gated behind a personal access token you generate in Settings. This is the one most users want — it talks to your actual receipts, your actual Google Sheet, and your actual spending history. ChatGPT and Claude.ai users connect to the remote server at mcp.expensebot.ai, which advertises 62 submitted tools after commerce-tool exclusions plus the search/fetch shims. Both delivery methods are listed on the official MCP Registry.

What can my AI assistant do?

Once connected, you can ask in plain English. Some example prompts that all work today:

  • "Find every Uber receipt I expensed last quarter."
  • "Submit this receipt to ExpenseBot." (drag a photo into ChatGPT or Claude)
  • "Scan my Gmail for new receipts from the last 30 days."
  • "What were my top 5 software vendors in Q1?"
  • "Generate a Schedule C report for 2025 and share it with my accountant."
  • "I paid $80 cash for parking at the airport — log it."
  • "Show me my profit and loss for 2026 year to date."

Behind the scenes, those prompts route to one of 63 authenticated tools in the stdio package, or 62 submitted tools in the remote connector after commerce-tool exclusions plus search/fetch. You don't call these by name; your AI assistant picks the right one based on what you ask.

Full tool reference — 60 tools across 9 categories ▸
Search & analytics
  • get_deep_analyticsreads
    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.
  • get_spending_summaryreads
    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? } }.
  • get_trip_suggestionsreads
    Review trips using the overnight engine. Explicit trip queries: set includeCandidates:true for lower-confidence candidates; name a trip with destination (e.g. "Copenhagen"); use mode:area with area for every expense in a country or city. Show dates, recorded locations, count and uncertainty; locations are not travel or client proof. Copy exact selections to group_expenses with a user-chosen trip/client name and confirm:false, then request approval. Possible additions stay out unless the user includes them (includePossibleAdditions:true). Merge/deduplicate selections for one destination; separate destinations need separate confirmations. Preserve existing assignments, Personal and read-only rows. Never infer clients or countries from currency. clientEmail mode is read-only.
  • list_categoriesreads
    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.
  • list_income_categoriesreads
    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.
  • list_tagsreads
    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.
  • search_expensesreads
    Search and filter the user's expenses; returns matching 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 overlapping searches. The optional query parameter does deterministic natural-language recall over merchant, city/location, Notes (receipt items, delivery source, payer, Business purpose), Tag and category. Results include matchedFields and a short matchReason to explain the match; when several rows plausibly match, a disambiguation list is returned and each option carries the exact expenseId. Structured filters (categories, merchants, dateRange, tags, minAmount, maxAmount) combine with the query using AND. Each result includes expenseId, the exact durable Receipt ID required by update_expense. For country-based grouping or client-assignment review use groupBy:country with explicit YYYY-MM-DD start/end; this read-only mode reviews at most 100 matching expenses, so narrow the range if too large. Use exact configured categories for travel; a foreign expense is not necessarily travel. Recorded locations can resolve to derived countries, which is not proof of travel. Unknowns stay separate even with a country filter; ask about ambiguous places, never infer from currency. Country review supports categories, merchants, tags, countries and tagAssignment, not free query or pagination. Show counts and currency-separated totals, then copy the returned selectionItems (with tag/date/location expectations) into group_expenses after the user chooses destinations.
  • search_knowledgereads
    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.
Income, P&L & books
  • get_income_summaryreads
    Use this when the user asks about income already recorded in their ExpenseBot Income tab. Read totals; group by source, category, month, payment method or tag; filter by dateRange/incomeTagPrefix. Query supports period comparisons (e.g. 'income YTD by source', 'income this year vs last'). Returns message and data with total and optional breakdown, comparison, sampleMeta. No scanning, imports, mutations, tax returns or liability determination.
  • get_mileage_summaryreads
    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? } }.
  • get_monthly_books_reviewreads
    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. closeReadiness summarizes current recorded-book checks and Action Needed categories with authenticated app links. Explain unknown coverage and limitations; it does not close books or certify tax completeness.
  • get_per_tag_pnlreads
    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.
  • get_pnlreads
    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? } }.
  • get_subscription_auditreads
    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? } }.
  • list_client_close_readinessreads
    Accountant-only month-end overview of accepted client workspaces. Returns page-level readiness and affected-client category counts with an authenticated Client Reports link. Use for 'how many clients need attention before month end'. No client identities, amounts, or individual items are returned; select a client in ExpenseBot to resolve items. Unavailable sources remain unknown. Each page uses the current roster; do not combine pages into a verified total.
Capture & edit
  • add_cash_expensewrites
    Add an expense without a receipt, or record money a client provided in advance. 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 that only for money a client supplied before related spending, never for vendor refunds, reimbursements, earned fees, retainers or generic deposits. For multiple entries, credits/refunds, tax or tip breakdowns, per diem or incomplete details, use the Manual expense link from get_spreadsheet_url instead.
  • add_incomewrites
    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.
  • add_income_from_csvwrites
    Use this to import the user's CSV/TSV/text income export (max 500 KB). Step 1 stages a duplicate-checked previewId without writing Income rows. Show it and obtain approval. Step 2 uses confirm:true and that previewId to write the approved rows/edits; duplicates require explicit keep approval. Unknown or expired previews never write (15-minute expiry). Return spreadsheetUrl and reviewIncomeUrl after success. Accepts user-provided attachments or inline text, not arbitrary web URLs.
  • add_income_from_filewrites
    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). Two steps. STEP 1: call with the file and WITHOUT confirm. ExpenseBot parses it with the same importer as the app's Add Income screen, checks every row against the Income tab for duplicates, and returns a preview with previewId, exact row count, totals by currency, per-row details, duplicate flags and rejected rows. NOTHING is saved in step 1; the attachment is consent to parse, not to write. Show the parsed rows and duplicates, then STEP 2: call again with confirm: true and the previewId to write exactly those rows, including only user-approved changes (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 visually complex reviews (mixed income/expense rows, many edits), send the user to the Add Income app link from get_spreadsheet_url.
  • add_mileage_entrywrites
    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.
  • correct_expenseswrites
    Safely correct the category, business purpose or explicit attendees on an exact bounded set of recorded expenses, e.g. 'categorize these as Travel', 'add Client kickoff dinner as the business purpose for these meals', '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 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; replace substitutes only the attendee segment. Business purpose and attendees preserve the structured Notes field (card, description, inbox and other typed segments). Formula Notes and changes exceeding 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 over-100-row cleanup, send the user to https://www.expensebot.ai/review-expenses?source=mcp.
  • create_tagwrites
    Create a standalone group/tag without selecting or changing any expenses. The first call prepares a preview; after the user explicitly chooses to create it, send confirm:true with the returned operationId (fresh duplicate checks run). A first call with confirm:true still returns a preview. An exact canonical duplicate is a no-op; archived tags are not reactivated. Similar names are returned as choices; set allowSimilar:true only when the user explicitly chooses a distinct new group despite them. Use list_tags to inspect all groups.
  • get_expense_by_idreads
    Read one existing expense from the authenticated user's ExpenseBot spreadsheet. Supply the exact expenseId returned by search_expenses (Receipt ID in Column Q), or the user's specified rowNumber. Never invent an identifier. Returns sheetName, rowNumber, headers, values, labeled fields and, when available, reviewExpenseUrl. This tool does not edit, submit, delete, share, or scan anything.
  • get_last_receipt_resultreads
    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 longer). A pending result is normal and must not trigger a duplicate resubmission. Returns added, duplicate, skipped, held_for_review or errored verdicts with exact counts and up to 10 receipt summaries. A held_for_review file (withheld for missing details or a possible duplicate) was not added; relay the next step in its message. found:false is pending with no terminal verdict; found:true is terminal. On completion report the authoritative per-file outcomes. Show spreadsheetUrl and reviewExpensesUrl for rows actually added, not for held files. For a held file relay only its message's next step (such as Files to review on Add Expenses); do not invent a missing card or send held uploads to Gmail Action Needed. Unknown outcomes stay unknown; do not blindly resubmit. For uploaded receipts only; use get_scan_status for Gmail scans. Read-only.
  • get_statement_import_statusreads
    Check 'Did my statement finish importing?' for at most five jobs. Returns status and authenticated review link. Extraction isn't saved; read/save jobs may overlap, so counts aren't statement totals. No job found doesn't prove no import; older non-job imports are excluded. Read-only: never uploads, parses, saves, retries, or recovers.
  • group_expenseswrites
    Group an exact set of recorded expenses for a client, project, trip, job, or other user-named purpose, e.g. 'group my Mexico meals for client Rob' or 'group these for client Rob and create a report'. The user need not know about tags: ExpenseBot resolves the name against existing groups and proposes creating one only when needed. Use exact expenseId values from search_expenses. Existing assignments are preserved by default; set replaceExistingTags:true only for an explicit replacement request. A grounded preview is automatic for every bulk request. First call with confirm omitted/false, show the 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). If the request includes a report, set createReport:true on that confirmed call and use its report result; do not run a separate broader create_report query. For 'without personal expenses' set excludePersonal:true; Personal-tagged and Personal-category rows are removed before preview so their marker is never overwritten. The confirmed operation returns exact report and Bill Client links. Expenses already on another ordinary report are excluded; if none remain, no duplicate report is created and the result links to Reports. Keep the response concise, with no unsolicited tax or substantiation advice; do not call check_compliance, get_report_details or tax/deductibility tools around this workflow unless the user asks. 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 to the preview. A Bill Client URL opens the reviewed billing handoff; it does not mean an invoice was created, sent, or confirmed. Sharing remains a separate share_report action with recipient confirmation.
  • parse_expensereads
    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, ...}
  • submit_receiptwrites
    Submit a photo or PDF of a receipt for processing. Covers 'log this', 'save this receipt', 'expense this', 'add this to my expenses', including when the user simply shares a photo of a receipt or invoice. The file is validated, uploaded and processed by AI to extract vendor, amount, date, tax and category. The expense appears in the spreadsheet in about 1-3 minutes, longer for PDFs or large batches. Handles images and PDFs mixed 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 to process the whole set as a single batch. Do not call this tool once per file. Use the photo parameter for one image or PDF attached in ChatGPT. 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 use the same metadata path as ExpenseBot's camera, uploader and forwarded-email intake: note goes to Notes (column L), tag to Tag (column K). Batch defaults apply to every file; each uploadRefs item may override either value.
  • update_expensewrites
    Update a single existing expense row's category, tag, merchant or business purpose (e.g. 'recategorize expense X to Meals', 'tag it Client – Acme'). Identify it only by the exact expenseId from search_expenses (the full Receipt ID from Column Q); never a date, displayed number or sheet row number. Two-phase: calls with confirm omitted/false return a current→proposed preview and change nothing; after user confirmation, confirm:true applies it. 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. Only category/tag/merchant/businessPurpose are editable; amounts, dates and notes are not. Does not create or delete rows.
Gmail
  • get_scan_statusreads
    Check authoritative Gmail receipt scan status. Returns the active lock and live phase/progress shown in-app, queued or attention-needed periods, completed calendar years, and tax-period statuses with their returned labels and inclusive ISO bounds, plus exclusions and recent outcomes. Use when asked if a scan is running, finished, stuck, or what it is doing. On completion show spreadsheetUrl or reviewExpensesUrl; for setup/reconnection show gmailScanUrl. Read-only.
  • process_gmail_receiptswrites
    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.
  • scan_gmailwrites
    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.
  • scan_gmail_yearswrites
    Scan completed Gmail periods for receipts. In eligible split-tax-year accounts, a number is the period's ending year (2025 = 2024–25 tax year); otherwise it is a calendar year. Use returned tax-period labels and inclusive ISO bounds. Long-running: the first eligible period starts immediately; the rest queue one at a time (each full period typically takes hours; the app may close). Preview without confirmStart (no scan starts), ask the user to confirm, then start with confirmStart:true. For recent receipts (~60 days), use scan_gmail. The in-progress period cannot be year-scanned; use get_scan_status for progress.
Reports & receivables
  • create_client_invoicewrites
    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.
  • create_reportwrites
    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 intended group is unclear. For 'all expenses in August except personal' set excludePersonal=true (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 needing visual review. Reports scoped to an existing client/project/trip group include matching expenses not already on another ordinary report. Can optionally share with recipients. If no unreported matches remain, no duplicate report is created; explain the expenses are already in Reports. Terminal results also include role-appropriate accountingHandoffUrls; use only the exact destination the user requested, since 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 analysis.
  • export_reportreads
    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.
  • get_client_advance_balancesreads
    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.
  • get_client_invoicereads
    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.
  • get_credits_refundsreads
    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.
  • get_expense_splitsreads
    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.
  • get_report_detailsreads
    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. Without checkFreshness:true, returns the stored report only. When explicitly requested together with analysisRequested:true, freshness reads canonical Google Sheets sources with a 5-second bound; if full tax-year replay is unavailable, status is unknown, not current. Never call this as a preflight or follow-up to creating, sharing, or billing from a report; those tools already return the requested result and links.
  • list_client_invoicesreads
    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.
  • list_reportsreads
    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.
  • mark_client_invoice_paidwrites
    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.
  • prepare_client_invoicewrites
    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.
  • share_reportwrites
    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.
Accounting destinations
  • get_accounting_integration_statusreads
    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.
  • get_accounting_push_statusreads
    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.
  • request_accounting_integrationwrites
    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.
  • send_report_to_accountingwrites
    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 not accepted yet because their previews cannot freeze/revalidate the plan shareReport executes. Use those providers' web flows.
Compliance & tax
  • check_compliancereads
    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.
  • check_tax_deductibilityreads
    Use this when the user asks for general deduction guidance for an expense type, such as business meals or home-office expenses. Looks up reference rules using the account's tax-country/home settings and current year. A verified rule may return a percentage and reference; unverified rules return unknown/reviewRequired without a percentage. Read-only: it does not classify saved expenses, prepare a return, or determine the user's actual tax liability. Do not use for tax refunds received as income; use get_income_summary for recorded refunds. General guidance is not a tax professional's determination.
  • fix_compliancewrites
    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 get each full expenseId and pass those exact identities; never select every report row or infer a business purpose, category or attendee. Same reviewed workflow as correct_expenses: the first call always prepares a grounded preview and changes nothing, 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 over-100-row cleanup open https://www.expensebot.ai/review-expenses?source=mcp.
Cash-flow what-if
  • whatif_affordreads
    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.
  • whatif_clientreads
    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.
  • whatif_tax_setasidereads
    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'.
Account & utility
  • check_featurereads
    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.
  • get_recent_activityreads
    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).
  • get_spreadsheet_urlreads
    Return the user's master ExpenseBot Google Sheet plus authenticated workspace links, each with a label and when-to-use description. Use when the user asks to open, view or edit their spreadsheet; review expenses or income; scan Gmail; reconcile; connect or manage a bank/card; open Automation Hub or General Settings; create or open reports; or asks where a submitted receipt went. Show only the one or two relevant links, not the catalog. After a receipt submission prefer Review expenses plus the Sheet; after an income write, Review income plus the Sheet. Gmail scan or connection: Scan Gmail. Bank/card: Reconcile. Configuration: Automation Hub or General Settings. Category, G/L and account codes: Category management. Client, project and trip groups: Group management. What counts as Personal: Personal rules. Client billing setup: use the returned clientBillingHandoffs, not a generic tour: manageClients manages the client list, tagReadyExpenses opens Review Expenses filtered to blank or default-Business rows, createClientReport opens report creation by group once expenses are assigned; pick the one step matching the user's state. If the user names a client and an exact expense scope and wants the assistant to do the work, use search_expenses and group_expenses instead (grounded preview, explicit confirmation before changing rows). Google Photos receipt picking: Google Photos link (existing authenticated picker, handles Google consent). Receipt file storage: the Drive folder link only when available; never invent or request a folder ID. A complete, unambiguous cash expense or mileage trip: use the direct write tool. Manual expense link: multiple entries, credits/refunds, detailed tax/tip, per diem, incomplete details, visual review. Mileage and travel link: route calculation, mileage settings, repeated trips, calendar/rideshare imports, per diem, visual review. Income import from a screenshot, PDF or CSV with no attachment in chat (or a visually complex review): Import income links; the importer shows every row for review before saving. Team setup: the role-aware Team setup handoff (solo business owners open Add teammates; team owners and co-admins open Team Management); if it says owner access is required, explain that instead of presenting a broken link. Complex or visually reviewed report requests: Create report link. Read-only; modifies no spreadsheet rows.
  • trace_documentreads
    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. NOT for the status, progress, or completion of a Gmail scan job (running, queued, finished, or stuck) — a scan is not a document; use get_scan_status for that. Returns a read-only timeline from the user's lineage audit trail.
ChatGPT Deep Research shims
search, fetch

Remote connector only (mcp.expensebot.ai). Not counted in the 60 above.

You don't call these tools by name — Claude picks the right one based on what you ask. The list is here so you know what's possible. Power users link the MCP from their freelancer workflow so their AI assistant becomes the front-end for bookkeeping.

Why use AI Assistant access?

  • Faster than the dashboard for ad-hoc questions. "What did I spend at Costco last month?" is one sentence in Claude versus four clicks in the UI.
  • No app switching. If you live in Claude or Cursor for writing and code, your expense answers come to you.
  • Conversational receipt submission. Drag a photo into chat, say what it was for, and it lands as a row in your sheet — categorized, with vendor and total extracted.
  • Complex analytics in natural language. get_deep_analytics surfaces top vendors, anomalies, month-over-month deltas and unusual spend without you writing a single SQL query or pivot table.
  • Cash entry by description. "$80 cash for airport parking yesterday" becomes a properly tagged cash expense with date, amount, category, and notes.

Security & token model

Hosted and remote connections use OAuth; local stdio connections use personal access tokens (PATs). Both credentials are scoped to your account only — they cannot read another user's data, even if leaked. A token stays valid for as long as you keep using it (one unused for a year lapses), and you can revoke any token from Settings → AI Assistant Tokens with immediate effect (the next request fails 401). Token issuance, use, and revocation are audit-logged in Firestore against your account so you can review what was used when. Tokens themselves are stored hashed (SHA-256) — even ExpenseBot staff can't read the original string out of the database.

Your underlying expense data never moves. Receipts stay in your Google Drive, your sheet stays in your Drive, and each MCP tool call reads or writes those files using your existing OAuth grants. The only data that flows through your AI provider is the specific tool result your assistant asked for — same trust model as any LLM tool-use call. If you're inviting an accountant later, the share happens through Google Drive sharing, not through the MCP token.

Compatible AI assistants

MCP support is growing quickly. Today the ExpenseBot MCP works out of the box with:

  • ChatGPT — connect from Settings → Apps; availability can depend on plan, region, and workspace settings. (setup ↑)
  • Claude.ai — connect from Customize → Connectors; remote connectors are available across plans, subject to workspace controls. (setup ↑)
  • Claude Desktop — Mac, Windows, Linux. Native MCP support via npm package. (setup ↑)
  • Cursor IDE — Mac, Windows, Linux. Add via Settings → Tools & Integrations. (setup ↑)
  • Claude Code (CLI) — one command. (setup ↑)
  • Continue, Cline, Windsurf — same npm package, different config path. (setup ↑)
  • Custom agents built on the Anthropic, OpenAI, or open-source MCP SDKs.

Building your own client? Build an integration with self-service OAuth setup.

If your client follows the MCP wire format (JSON-RPC over stdio), ExpenseBot works. The official and constantly-updated client list lives at modelcontextprotocol.io/clients.

Why this matters

Most expense apps see receipts. The ExpenseBot MCP lets your AI act on them — search, submit, scan Gmail, generate a tax report, share it with your accountant — using your actual Google Sheet as the source of truth. There's no separate mirror database to drift, no proprietary ledger to escape from, no "export to CSV" step. Your AI assistant reads the same sheet you read, writes the same rows you'd write, and triggers the same Gmail scanner you'd trigger from the dashboard.

That's the Gmail-Sheets-native angle. ExpenseBot was built from day one around the data your life already runs on — receipts in Gmail, ledger in Google Sheets, files in Drive — instead of on a closed app database. The MCP server inherits that. When you ask Claude to scan Gmail for new receipts, it triggers the same scanner that runs nightly. When it submits a receipt, the row lands in the sheet you already own. We're listed on the official MCP Registry at io.github.TotesMagotes/mcp-server-auth so registry-aware clients can find us automatically.

See pricing plans for full feature breakdown. The MCP servers are public on npm; account-scoped tools require an active ExpenseBot account.

New to the AI-first workflow? The tutorial walkthrough Manage Expenses from Inside ChatGPT or Claude shows real prompts, the 5-minute connector setup for ChatGPT and 3-minute setup for Claude.ai, the 5 workflows that replace separate apps, and the OAuth security model.

Coming from ChatGPT rather than a developer client? The ChatGPT expense tracker page covers the one-click app-directory connect — no server URL, no token — and what the 62 connector tools do in a conversation.

Frequently asked questions

What is MCP (Model Context Protocol)?

Model Context Protocol (MCP) is an open standard introduced by Anthropic that lets AI assistants connect to external tools and data sources through a uniform interface. Instead of every app building a one-off ChatGPT plugin or Claude integration, an app publishes one MCP server and any MCP-compatible client (Claude Desktop, Cursor, Continue, custom agents) can talk to it. Think of it as USB-C for AI — one cable, many devices. ExpenseBot publishes two MCP servers on npm so your AI assistant can search your receipts, submit new ones, and analyze your spending using the same data you see in your dashboard. Learn more at modelcontextprotocol.io.

Do I need to be a developer to use the ExpenseBot MCP?

No for ChatGPT, Claude.ai, and remote OAuth-capable agents: choose ExpenseBot from the directory or add the remote MCP URL, then complete browser sign-in. Local clients such as Claude Desktop and Cursor need a small config block and a revocable token stored as EXPENSEBOT_TOKEN. The connection chooser on this page shows the right path before asking you to edit anything. If you hit trouble, support@expensebot.ai will walk you through it.

What's the difference between the two ExpenseBot MCP servers?

@expensebot/mcp-server is read-only and unauthenticated — it exposes the public ExpenseBot knowledge base and documentation so an AI assistant can answer questions about features, pricing, and tax-form mapping without any login. Useful for prospects evaluating the product or for AI agents that need to cite ExpenseBot capabilities. @expensebot/mcp-server-auth is the full version: 63 tools across search, capture, Gmail scan, reports, analytics, and document tracing, all scoped to your personal account via a personal access token. This is what most users want — it's the one that searches your actual receipts and submits new ones. ChatGPT and Claude.ai users connect to the remote server at mcp.expensebot.ai, which advertises 62 submitted tools after commerce-tool exclusions plus the search/fetch shims.

Does the MCP server work with ChatGPT?

Yes — ExpenseBot is listed in the ChatGPT app directory: open Settings → Apps, search for ExpenseBot, and click Connect. OpenAI's Agents SDK also supports MCP servers. You can use the ExpenseBot MCP from any custom agent built on the Anthropic, OpenAI, or other LLM SDKs — the protocol is open. Claude Desktop and Cursor also support MCP. For other clients, see the up-to-date list at modelcontextprotocol.io/clients.

Does ExpenseBot work with Gemini?

Yes, for eligible Gemini Spark users. In Gemini on the web, open Settings & help → Connected Apps → Custom apps for Spark, add https://mcp.expensebot.ai/mcp, and complete ExpenseBot browser sign-in. Google currently documents personal-account, age, Keep Activity, region, and language eligibility requirements. This is a custom MCP connection, not a curated Gemini directory listing.

Is my expense data sent to Anthropic / OpenAI when I use the MCP?

Only the parts your AI assistant explicitly reads. When you ask Claude 'how much did I spend on software last quarter,' Claude calls the ExpenseBot MCP server's get_spending_summary tool, the server fetches that summary from your Google Sheet, and the result text becomes part of the conversation Claude sees — and is therefore sent to Anthropic as context like any other Claude message. ExpenseBot doesn't send data to Anthropic itself. Your full ledger never leaves your Google Drive; only the specific tool results requested in each conversation flow through the AI provider. This is the same trust model as any LLM tool-use call.

How do I revoke access if my token leaks?

Open ExpenseBot → Settings → AI Assistant Tokens, find the token row, and click Revoke. The token is invalidated immediately on the server side; the next MCP request from any local client using it will fail with 401 Unauthorized. Generate a new token, replace the EXPENSEBOT_TOKEN value in that client's secret or environment configuration, restart the client, and you're back. Hosted OAuth connections are revoked or reconnected from the assistant's connector settings. All token issuance, use, and revocation events are audit-logged against your account, and stored tokens are one-way protected.

Can I use the MCP server with my own AI agent / custom client?

Yes. If the agent supports remote HTTP MCP with OAuth, add https://mcp.expensebot.ai/mcp and complete browser sign-in; no personal token or hand-written client secret is needed. If it only supports local stdio MCP, run @expensebot/mcp-server-auth as a subprocess and pass EXPENSEBOT_TOKEN in the environment. The stdio server advertises 63 tools through tools/list, and the package is listed on the official MCP Registry at io.github.TotesMagotes/mcp-server-auth.

Does this work on Windows or only Mac?

Both, plus Linux. The MCP servers ship as Node.js packages on npm and run anywhere Node 18+ runs. Claude Desktop has native installers for Mac and Windows; the config file lives at ~/Library/Application Support/Claude/claude_desktop_config.json on Mac and %APPDATA%\Claude\claude_desktop_config.json on Windows. Cursor IDE's MCP config works identically across all three operating systems. The only platform-specific step is finding the right config path — once it's edited, the integration behaves the same everywhere.

Do I need ChatGPT Plus or Claude Pro to use this?

Not necessarily. ChatGPT app availability can depend on plan, region, and workspace settings; the listing's Connect button is authoritative. Claude currently makes remote connectors available across Free, Pro, Max, Team, and Enterprise plans, with workspace controls and a one-custom-connector limit on Free. ExpenseBot itself starts with a 60-day trial regardless of which client you connect from.

What if ExpenseBot is not in my assistant's connector directory?

Use the custom remote connection when the client supports HTTP MCP: add https://mcp.expensebot.ai/mcp and complete ExpenseBot's browser OAuth flow. If the client supports only local stdio MCP, use the npm package and store EXPENSEBOT_TOKEN in the client's secret or environment settings. The connection chooser on this page keeps these paths separate.

Will my existing Claude Desktop or Cursor setup keep working?

Yes. Existing stdio installations keep working. Remote OAuth and local stdio share the same core ExpenseBot workflows, while their advertised catalogs can differ intentionally (62 remote and 63 stdio in this release). Use tools/list rather than assuming exact parity.

What data does ChatGPT or Claude.ai see?

Only what you explicitly authorize on the consent screen. ExpenseBot uses six fine-grained OAuth scopes: expenses.read, expenses.write, gmail.scan, reports.read, reports.write, and compliance. Deny any scope at sign-in and the corresponding tools simply don't appear in the AI's tool list. Your full spreadsheet never leaves Google Drive — each tool call fetches only the specific result requested, exactly like any other LLM tool-use call.

Ready to connect ExpenseBot to your AI assistant?

Pick the path that matches your AI client. ChatGPT and Claude.ai are one-click connector adds; desktop clients use a token.

Open in ChatGPT →Open in Claude →Sign in for desktop token →

60-day free trial · No credit card · Cancel any time

Not sure which one fits? Compare the setup options ↑

ExpenseBot