Every change Wellknown observed on this MCP server, newest first, with what it was before and what it became. Tool-surface changes carry the definition diff. Nothing here is edited after the fact.
Added "get_statement_import_status"; changed the definition of "get_report_details" (60 tools before, 61 now)
⟨20 unchanged words⟩ 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 ⟨5 unchanged words⟩ from a report; those tools already return therequiredrequested result and links.
⟨36 unchanged words⟩ ":[true],"type":"boolean"},"checkFreshness":{"description":"Set true only when the user explicitly asks whether this existing Year End report is current. Requires analysisRequested:true and performs a bounded Google Sheets source check; may return unknown if full tax-year replay is unavailable. Never use after report creation, sharing, or billing.","enum":[true],"type":"boolean"},"clientEmail":{"description":"Client account email. Accountants ⟨25 unchanged words⟩
{"additionalProperties":true,"properties":{"freshness":{"additionalProperties":false,"properties":{"checkedAt":{"format":"date-time","type":"string"},"message":{"type":"string"},"reportUrl":{"format":"uri","type":"string"},"status":{"enum":["current","outdated","unknown","not_applicable"],"type":"string"}},"required":["status","checkedAt","message","reportUrl"],"type":"object"},"report":{"additionalProperties":true,"description":"The ⟨14 unchanged words⟩
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":true,"title":"Get report details"}
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.
Changed the definition of "get_scan_status" and "scan_gmail_years"
Checktheauthoritativestatus of the user'sGmail receiptscans.scan status. Returns the activescanlock,the same live phaseanditemliveprogressphase/progress shownby ExpenseBot'sin-appstatus pill, queued or attention-neededyearsperiods, completed calendar years,current
Changed the definition of "trace_document"
⟨38 unchanged words⟩ 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.
Changed the definition of "add_income_from_csv", "check_tax_deductibility", "get_expense_by_id" and 1 more
Import income from a CSV/TSV/text export (Stripe, PayPal, Square, Cash App, Venmo, OnlyFans, Patreon, Clips4Sale, Ko-fi, Gumroad,UseEtsy,thisUber/Lyft/DoorDashtodriverimportexports,thebankuser'sstatements,CSV/TSV/textandincomesimilar;export
Added "list_client_close_readiness"; changed the definition of "add_cash_expense", "add_income", "add_income_from_csv" and 17 more (59 tools before, 60 now)
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Log cash expense"}
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Log income entry"}
Changed the definition of "get_monthly_books_review"
{"additionalProperties":true,"properties":{"closeReadiness":{"additionalProperties":true,"properties":{"actionNeeded":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"checks":{"additionalProperties":{"enum":["ready","needs_action","blocked","unknown","not_applicable"],"type":"string"},"type":"object"},"status":{"enum":["ready","needs_action","blocked","unknown"],"type":"string"}},"type":"object"},"data":{"additionalProperties":true,"type":"object ⟨10 unchanged words⟩
Changed the definition of "add_income", "add_mileage_entry", "fetch" and 2 more
⟨32 unchanged words⟩ :{"description":"Income date (YYYY-MM-DD).DefaultsRequired.toUsetoday.the date the user gives; for \"today\" send today's calendar date in their timezone. If no date was given, ask.","format":"date","type":"string"}, ⟨85 unchanged words⟩ ,"required":["amount","source","paymentMethod","date"],"type":"object"}
Certificate recorded, valid to 2026-12-07
Authorization not required
First tool surface recorded: 59 tools (server version 0.3.1-m3.6)
Showing the latest 10 events. The API returns up to 500 and filters by kind: ?kind=tool_surface_changed
ScanonecompletedorGmailmoreperiodsCOMPLETEDforPRIORreceipts.yearsInofeligiblethesplit-tax-yearuser'saccounts,Gmailafornumberreceiptsis the period's ending year (e.g.2025years:[2023]=or2024–25years:[2020,2021,2022]tax year).;Long-runningotherwisebackgrounditjobis a calendar year. Use returned tax-period labels and inclusive ISO bounds. Long-running: the first eligibleyearperiod startsimmediately andimmediately; the rest queue,runningone at a time (each fullyearperiod typically takesa couple ofhours; theuserappcanmay closethe app).ALWAYS call firstPreviewWITHOUTwithout confirmStartto preview which years(noarescaneligiblestarts),thenask the user to confirm, thencall againstart with confirmStart:true. Forreceipts from therecentlastreceipts (~60 daysuse scan_gmail instead. To check how a scan is going), useget_scan_status.scan_gmail. Thecurrentin-progressyearperiod cannot beyear-scanned.year-scanned; use get_scan_status for progress.
⟨39 unchanged words⟩ boolean"},"years":{"description":"Completedpriorperiods;yearsendingtoyearscan,fore.g.eligible[2020tax-year accounts (2025 = 2024–25),2021].calendar year otherwise. Max 10.","items":{"type":" ⟨7 unchanged words⟩
{"properties":{"bulkNote":{"description":"Step 2only: onenote(max 120 chars)prepended toeveryconfirmedrow's Notes, same as the app's 'Add noterowsto(maxall120entries'.characters).","type":"string"},"confirm":{"description":"Step 2only: true writes the stagedrows. Omit it (with previewId absent) to parseselectionandonlypreviewafterwithoutuserwriting.approval.","type":"boolean"},"csvContent":{"description":"Attached CSV/TSV/text file suppliedStepby1 ChatGPTfor step 1. Theattachment;serversecurelydownloadsdownloaded anddecodes the attachment securely.decoded.","properties":{"download_url":{"description": ⟨47 unchanged words⟩ :"object"},"csvText":{"description":"Legacy fallback for MCP clients thatStepsend1rawinline CSV/TSV/textcontent inline.fallback; ChatGPT should use csvContent.","type":"string"},"keepBothIndexes":{"description":"Step 2only: previewduplicate indexesof duplicate-flagged rowsthe user explicitlywants to keep anyway (the app's 'KeepapprovedBoth').keeping.","items":{"type":"integer"}, ⟨2 unchanged words⟩ "paymentMethod":{"description":"Fallback payment railfor rows where the parser found none (Cash, Check, Bank transfer, Wallet app,onlyCredit/Debitwhencard,absentPaymentfromprocessor,theorparsedOther).row.","type":"string"},"previewId":{"description":"Step 2only: the previewIdID returned by thestep-1unexpiredcall.preview.","type":"string"},"rowEdits":{"description":"Step 2only: user-approvedapprovedcorrections,edits; at most 50rows. Fields: date (ISO YYYY-MM-DD), source, amount, currency, category, paymentMethod, description, notes, reference, fees,selectedtaxCollected,previewtag.rows.","items":{"properties":{"fields":{"additionalProperties":truefalse,"description":"Onlythe user-approved income fields toapprovedreplacereplacements on this stagedrowrow.","properties":{"amount":{"description":"Non-zerodate,incomesourceamount.",amount"type":["number",currency"string","boolean"]},"category":{"description":"Income category.","type":["string","number","boolean","null"]},"currency":{"description":"CurrencypaymentMethodcode.","type":["string","number","boolean","null"]},"date":{"description":"ISO YYYY-MM-DD calendar date.","type":"string"},"description":{"description":"Income description.","type":["string","number","boolean","null"]},"fees":{"description":"Non-negative platform fees.","type":["number","string","boolean","null"]},"notes":{"description":"Income notes.","type":["string","number","boolean","null"]},"paymentMethod":{"description":"Payment rail.","type":["string","number","boolean","null"]},"reference":{"description":"Income reference.","type":["string","number","boolean","null"]},"source":{"description":"Incomefeessource label.","type":["string","number","boolean"]},"tag":{"description":"Client/projecttaxCollectedtag.","type":["string","number","boolean","null"]},"taxCollected":{"description":"Non-negativeorcollectedtag.tax.","type":["number","string","boolean","null"]}},"type":"object"},"index":{"description":"Preview row index","minimum":0,"type":"integer"}},"required":["index","fields"],"type":"object"},"maxItems":50,"type":"array"},"selectedIndexes":{"description":"Step 2only:preview row indexes towrite. Omitwrite;toomitwritefor all staged rows.","items":{"type" ⟨3 unchanged words⟩ },"tag":{"description":"Optional client/projecttag. In step 1 it pre-fillstagthefor stagedrows; in step 2 it applies to theor confirmedselection.rows.","type":"string"}},"required": ⟨2 unchanged words⟩
LookUseupthiswhetherwhenathespecificuser asks for general deduction guidance for an expense type, such as business meals orpurchasehome-officeisexpenses.tax-DEDUCTIBLELooks(businessupwrite-offreference rules)based onusing theuser'saccount'scountry/jurisdiction.tax-country/homeThissettingsisandacurrentdeductibilityyear.*advice*Atoolverified—ruleusemayitreturnforaquestionspercentagelikeand'isreference;Uberunverifieddeductible',rules'canreturnIunknown/reviewRequiredwritewithoutoffahomepercentage.office',Read-only:'areitclientdoesdinnersnot50%classifyorsaved100%'.expenses,DoprepareNOTausereturn,itorfordeterminequestionstheaboutuser'staxactualREFUNDStaxreceivedliability.asDoincomenot(useget_spending_summary withforatax'taxrefundsrefunds'receivedqueryasforincome;thoseuse—get_income_summarythey'reforroutedrecordedtorefunds.theGeneralIncomeguidancetab,is notdeductionarules).tax professional's determination.
{"properties":{"category":{"description":"Optional expense category to match the reference rule.","type":"string"},"merchant":{"description":"Optional merchant name only when relevant to the expense type.","type":"string"},"query":{"description":"DeductibilityBrief expense-type deduction question,(e.g.,'is'areUberbusinesstaxmealsdeductible',deductible?';'homenoofficeaccountwrite-offnumbersrules')or unrelated personal context.","type":"string"}},"required": ⟨3 unchanged words⟩
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":true,"title":"Get expense by ID"}
ReadUsetotalsthisandwhenbreakdownstheofuser asks about income already recorded inthe user'stheir ExpenseBot Income tab.Filter by period or tagReadprefix;totals; group by source, category, month, payment method,ortag. Query examples: 'incometag;YTDfilter bysource', 'rental incomedateRange/incomeTagPrefix.byQueryproperty',supports'interestperiodincomecomparisonsthis(e.g.year','income'taxYTDrefundsby2024'source',or'income this year vslast'. Supportslast').year,Returnsmonthmessage andquarter comparisons. Uses the existing recorded-income category rules; itdatadoeswithnottotaldetermineandfilingoptionaleligibilitybreakdown,prepare a tax returncomparison,scan email,sampleMeta.importNorecordsscanning,or change financial data. Returns message and data containingimports,totalmutations,optionaltaxbreakdown,returnscomparisonorandliabilitysampleMeta.determination.
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Import income ⟨4 unchanged words⟩
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Import income ⟨5 unchanged words⟩
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Log mileage trip"}
{"properties":{"reportIdanalysisRequested":{"description":"Report IDSettotruecheck","type":"string"},"userRequest":{"description":"Theonlyuser'swhenexacttherequestuser explicitlyaskingasked for this report's compliance,policy,analysis.audit,Dosubstantiation,not ask for orbusiness-purposecopyanalysis.theirDofull message, and do notparaphraseinfer consent from report creation, sharing, orinventbilling.","enum":[true],"type":"boolean"},"reportId":{"description":"Reportintent.ID to check","type":"string"}},"required":["reportId","userRequestanalysisRequested"],"type":"object"}
{"additionalProperties":true,"properties":{"data":{"additionalProperties":true,"properties":{"availability":{"enum":["unknown"],"type":"string"},"category":{"type":"string"},"country":{"type":"string"},"deductiblePercent":{"maximum":100,"minimum":0,"type":"number"},"reviewRequired":{"type":"boolean"}},"type":"object"},"message":{"type" ⟨8 unchanged words⟩
{"destructiveHint":true,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Correct selected expenses"}
{"destructiveHint":falsetrue,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Create expense report"}
{"destructiveHint":true,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Fix compliance issues"}
FetchReadaonesingleexisting expenserow byfromitsthesheetauthenticatedrowuser'snumberExpenseBotorspreadsheet.bySupplyitstheExpenseBotexact expenseId(thereturnedexactby search_expenses (Receipt ID in Column Q).,Returnsor therow'suser'sheadersspecified+rowNumber.valuesNever+inventaan identifier. Returns sheetName, rowNumber, headers, values, labeled{headerfields→and,value}whenmapavailable,soreviewExpenseUrl.youThiscantoolreferdoestonotaedit,specificsubmit,expensedelete,theshare,userormentioned.scanRead-only.anything.
{"additionalProperties":true,"properties":{"expenseheaders":{"additionalPropertiesitems":true{},"descriptiontype":"The expense record.array"},"labeled":{"additionalProperties":true,"type":"object"},"reviewExpenseUrl":{"type" ⟨7 unchanged words⟩ the expense.","type":"integer"},"sheetName":{"type":"string"},"success":{"type":"boolean"},"values":{"items":{},"type":"array"}},"required":["success"],"type":"object"}
Get incomeRead totals,breakdowns,andanalytics from the Income tab. Covers Schedule C /breakdownsT2125of income,Schedule B drill-in (interest, dividends, tax refunds,alreadysecurityrecordeddeposits),inrentaltheincome,user'sandExpenseBotper-sourceIncome/tab.per-payment-methodFilter/byper-categoryperiod/orper-monthtag/prefix;per-taggroupbreakdowns.bySchedule-C-stylesource, categoryexclusions match year-end T6 routing (security,depositsmonth,refundspaymentexcludedmethod,fromortaxabletag.totals).QueryExamplesexamples: 'incomeYTD', 'incomeYTD by source', 'rental income by property', 'interest income this year','dividends YTD','tax refunds 2024', or 'income this year vslast' (YoY).last'. Supportsperiodyear,comparisonmonthphrasingand—quarterYoYcomparisons.('vsUseslasttheyear')existing recorded-income category rules; it does not determine filing eligibility,MoMprepare('vsalasttaxmonth')return,QoQscan('Q1email,vsimportQ2')records,same-month-prev-year.orReturns:change{financial data. Returns message,and data:{containing total,breakdown?,optionalcomparison?breakdown,sampleMeta?comparison}and}.sampleMeta.
⟨62 unchanged words⟩ 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.
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":true,"title":"Get profit & loss"}
{"properties":{"clientEmailanalysisRequested":{"description":"ClientSetaccounttrueemail.onlyAccountantswhenmaytheuseuser explicitly asked to inspect thisonlyreport. Do not ask foranoracceptedcopyExpenseBottheirclient.full message, and do not infer consent from report creation, sharing, or billing.","formatenum":"email"[true],"type":"stringboolean"},"reportIdclientEmail":{"description":"TheClientreport/spreadsheetaccountIDemail. Accountants may use this only for an accepted ExpenseBot client.","format":"email","type":"string"},"userRequestreportId":{"description":"Theuser's exact request asking to inspect this report. Do not paraphrase or invent diagnosticreport/spreadsheetintent.ID","type":"string"}},"required":["reportId","userRequestanalysisRequested"],"type":"object"}
{"destructiveHint":true,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Group selected expenses"}
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":true,"title":"List expense categories"}
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":true,"title":"Search expenses"}
{"destructiveHint":false,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Submit receipt photo or PDF"}
{"destructiveHint":true,"openWorldHint":falsetrue,"readOnlyHint":false,"title":"Edit an expense's category/tag/merchant"}
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.
⟨19 unchanged words⟩ :{"description":"Trip date (YYYY-MM-DD).DefaultsRequired.toUsetoday.the date the user gives; for \"today\" send today's calendar date in their timezone. If no date was given, ask.","format":"date","type":"string"}, ⟨74 unchanged words⟩ string"}},"required":["distance","purpose","date"],"type":"object"}
⟨11 unchanged words⟩ id encodes the item type: • 'expense:<rowNumber>'<expenseId>' —e.g.the durable Column-Q Receipt ID returned by `search`, URL-encoded, e.g. 'expense:42'RR-123%3A%3Adrive%2Ffile%209'.forNever a sheet row42number:ofrows move when theuser'ssheetExpensesistabprepended. • 'report:<reportId>' — the alphanumeric Firestore document id from `search` or `list_reports`, e.g., 'report:FQqDglExofsyyQv7aYy4' • 'kb:<entryId>' — the knowledge-base entry id from `search` Always use the id exactly as returned by ⟨24 unchanged words⟩
⟨7 unchanged words⟩ previous `search` or `list_reports` call. Format: 'expense:<row>' (integer row<URL-encodednumber)Column-QorexpenseId>', 'report:<reportId>' (alphanumeric Firestore doc id, ~20 chars), or 'kb:<entryId>' (knowledge-base entry id).","pattern":"^(expense:\\d+|report.+|report:[A-Za-z0-9_-]++|kb:.+)$","type":"string"}},"required ⟨3 unchanged words⟩
⟨57 unchanged words⟩ duplicate resubmission. Returns added, duplicate, skipped, held_for_review, or errored verdicts with exact counts and up to 10 processed receipt summaries. A held_for_review file (withheld for missing details or a possible duplicate) was not added; relay the next step in the message. found:false is pending and has no terminal verdict; found:true is terminal. On completion,tellreport theuserauthoritativewhatper-filehappenedoutcomes. Show spreadsheetUrl andshowreviewExpensesUrlspreadsheetUrlforplusrowsreviewExpensesUrl.actually added, not as the destination 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 direct held uploads to Gmail Action Needed. Unknown outcomes stay unknown; do not blindly resubmit. This is for uploaded receipts; use get_scan_status for Gmail scans. Read-only.
⟨50 unchanged words⟩ "minimum":0,"type":"integer"},"heldForReview":{"description":"Files held for review and not added. Present only when at least one.","minimum":0,"type":"integer"},"skipped":{"minimum":0,"type":"integer ⟨22 unchanged words⟩ {"type":"string"},"receipts":{"description":"Processed receipt summaries. Held files are not listed here; see data.outcomes.","items":{"additionalProperties":true,"type":"object ⟨38 unchanged words⟩ ,"verdict":{"description":"Terminal branch only. held_for_review: every file was held for review, so none was added. mixed also covers any batch that includes held files.","enum":["added","duplicate","skipped","errored","mixed","unknown","held_for_review"],"type":"string"}},"required" ⟨5 unchanged words⟩
⟨449 unchanged words⟩ , while existing team owners and co-admins openLicenseTeamManager.Management. If the handoff says owner access is required ⟨30 unchanged words⟩