freshbooks-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| FRESHBOOKS_CLIENT_ID | Yes | The client ID of your FreshBooks app. | |
| FRESHBOOKS_TOKEN_STORE | No | File path to store rotated refresh tokens. | ~/.freshbooks-mcp/session.json |
| FRESHBOOKS_REDIRECT_URI | No | The redirect URI registered for your app. Must match exactly. | https://localhost |
| FRESHBOOKS_CLIENT_SECRET | Yes | The client secret of your FreshBooks app. | |
| FRESHBOOKS_REFRESH_TOKEN | Yes | The refresh token obtained from the one-time bootstrap. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| freshbooks_auth_urlA | Get the FreshBooks consent URL to authorize this connection. Open it, approve, and you'll land on the redirect URL — pass that whole URL to freshbooks_auth_exchange (its state parameter binds the approval to this server; valid 15 minutes, single-use). Read-only; contacts nothing. |
| freshbooks_auth_exchangeA | Complete FreshBooks authorization. Local sessions save the credentials privately and return only status; hosted sessions return the refresh token to the host's credential-capture flow. Pass the whole redirect URL: its state must match a consent URL freshbooks_auth_url issued, so a bare code is refused. The code is SINGLE-USE — if this fails, authorize again rather than retrying it. |
| freshbooks_get_identityA | Resolve the authenticated FreshBooks user and their identifiers: accountId (alphanumeric, used by accounting and payments endpoints), businessId (integer, used by projects and time tracking) and businessUuid. The three are not interchangeable — using the wrong one returns a 404 rather than a useful error. When the identity belongs to several businesses, |
| freshbooks_healthcheckA | Resolves the credential the way real tools do, then makes one authenticated request to api.freshbooks.com. Reports which source supplied the credential, whether api.freshbooks.com accepted it, the round-trip time, and a plain-English hint distinguishing 'no credential' from 'credential rejected' from 'a api.freshbooks.com-side problem'. Read-only; never returns the credential itself. Call this when a real tool fails and you want to know which hop broke. |
| freshbooks_list_invoicesA | List invoices for the authenticated FreshBooks account — what clients owe, with each invoice's due date and status. Supports pagination and raw FreshBooks filter params. Returns items plus page/pages/total; view "brief" returns one line per invoice instead. |
| freshbooks_get_invoiceA | Get a single invoice by its numeric FreshBooks id. |
| freshbooks_list_clientsA | List clients for the authenticated FreshBooks account. Supports pagination and raw FreshBooks filter params. Returns items plus page/pages/total. |
| freshbooks_get_clientB | Get a single client by its numeric FreshBooks id. |
| freshbooks_list_estimatesA | List estimates for the authenticated FreshBooks account. Supports pagination and raw FreshBooks filter params. Returns items plus page/pages/total. |
| freshbooks_get_estimateB | Get a single estimate by its numeric FreshBooks id. |
| freshbooks_list_paymentsA | List payments for the authenticated FreshBooks account. Supports pagination and raw FreshBooks filter params. Returns items plus page/pages/total. |
| freshbooks_get_paymentB | Get a single payment by its numeric FreshBooks id. |
| freshbooks_list_itemsA | List items for the authenticated FreshBooks account. Supports pagination and raw FreshBooks filter params. Returns items plus page/pages/total. |
| freshbooks_get_itemB | Get a single item by its numeric FreshBooks id. |
| freshbooks_create_clientA | Create a client (customer) in FreshBooks. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| freshbooks_create_invoiceA | Create an invoice for a client. Created invoices start as drafts. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| freshbooks_update_invoiceA | Update an existing invoice. Only the supplied fields are sent. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). Note that changing an invoice out of draft can email it to the client. email_recipients in fields must be addresses on the invoice's client record unless allow_non_client_recipients is set, which is only for addresses the user named themselves. |
| freshbooks_record_paymentA | Record a payment against an invoice. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| freshbooks_accept_estimateA | Accept an estimate on behalf of the account, by sending FreshBooks' action_accept on the estimate (PUT estimates/estimates/{id} with {"estimate": {"action_accept": true}}). Acceptance is not reversible through the API — there is no un-accept action. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). Idempotent: an estimate already accepted or invoiced is returned unchanged with changed: false and no write is sent. Returns the re-fetched estimate. |
| freshbooks_decline_estimateA | NOT SUPPORTED by the FreshBooks API — this tool always fails, and never sends a request. FreshBooks models no declined state for estimates: the status set is draft / sent / viewed / replied / accepted / invoiced, there is no action_deny or action_decline counterpart to action_accept in FreshBooks' own API collection, and there is no estimate.decline webhook event. The tool exists so this answers with the reason instead of a plausible-looking write that changes nothing. Call it to get the alternatives. |
| freshbooks_update_estimateA | Update an existing estimate. Only the supplied fields are sent; anything omitted is left alone. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). Supplying lines REPLACES the whole line set — include each existing line's lineid to keep it. Returns the re-fetched estimate. |
| freshbooks_send_estimateA | Email an estimate to the client, by sending FreshBooks' action_email on the estimate (PUT estimates/estimates/{id} with {"estimate": {"action_email": true, …}}). This puts mail in a client's inbox. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). Omitting email_recipients lets FreshBooks use the client's own address. email_recipients must be addresses on the estimate's client record unless allow_non_client_recipients is set, which is only for addresses the user named themselves. Returns the re-fetched estimate. |
| freshbooks_list_expensesA | List expenses for the account, newest-first by default. Supports pagination and raw FreshBooks filters (e.g. {"search[categoryid]": 5}). If the response reports a total with no rows, the count includes records this identity cannot read — that is reported in the |
| freshbooks_get_expenseA | Get a single expense by its numeric id. |
| freshbooks_list_expense_categoriesB | List expense categories, which supply the categoryid used when creating an expense. |
| freshbooks_create_expenseA | Record an expense. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| freshbooks_list_projectsB | List projects for the business. Uses businessId (not accountId) and works even when the business has no accounting account. |
| freshbooks_get_projectB | Get a single project by its numeric id. |
| freshbooks_create_projectA | Create a project. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| freshbooks_list_time_entriesB | List tracked time entries for the business. The response envelope also carries total_logged and total_unbilled alongside the rows. |
| freshbooks_create_time_entryA | Log a time entry. Duration is in SECONDS. Asks the user to confirm first: a confirmation prompt where the client supports one; otherwise the first call returns a preview and a confirmToken and makes no network call, and only a repeat call with that token proceeds (see MCP_CONFIRM_MODE). |
| freshbooks_list_servicesB | List services (the billable work types available to projects and time entries). |
| freshbooks_list_recordsA | List any FreshBooks accounting resource by name — the generic reader covering the long tail (taxes, credit notes, invoice profiles, tasks, staff, gateways, bills, bill vendors, bill payments, other income, expense categories) alongside the ones with dedicated tools. Returns items plus page/pages/total. Some resources are gated by plan or account role and will report that rather than returning rows. |
| freshbooks_get_recordB | Get a single record from any FreshBooks accounting resource by name and id. Ids are numeric on every resource mapped here; the schema also accepts a string so an id carried around as text still works. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 34 tools
Each dedicated tool targets a distinct resource+action, and the freshbooks_ prefix plus resource noun makes per-resource selection straightforward. The main fuzziness comes from the generic get_record/list_records overlapping with the dedicated getters/lists, and from decline_estimate being a deliberately failing tool, but the descriptions call both out explicitly.
Every tool follows the same freshbooks_verb_noun pattern (list_invoices, get_invoice, create_invoice, update_invoice, record_payment), with singular nouns for single-record operations and plural for collections. Even the odd-man-out (decline_estimate) fits the verb_noun convention.
34 tools is heavy for what is essentially one accounting domain, and some of the load is redundancy: generic get_record/list_records duplicate the per-resource readers, and decline_estimate exists solely to return an error. The breadth (invoices, estimates, clients, payments, items, expenses, projects, time, services, auth) does justify a large surface, so it is borderline rather than excessive.
Read coverage is strong and the invoice/estimate lifecycles are well served (create, update, send, accept), but there is no delete anywhere and no update for clients, expenses, projects, time entries, or line-item edits beyond update_estimate. Agents can read most things via get_record/list_records, but write workflows beyond invoices and estimates will dead-end.