关于 freshbooks-mcp
这是一个 MCP 服务,让 Claude 通过类型化工具访问 FreshBooks 记录并执行操作,涵盖发票、客户、费用和工时。写入操作需确认,本地 OAuth 令牌会私密保存。
主要功能
- 01浏览发票、客户、报价和付款
- 02创建并更新会计记录
- 03记录费用和项目工时
- 04发送前确认写入操作
- 05在本地保存轮换后的 OAuth 令牌
适用场景
- 01查看发票和付款详情
- 02确认后创建发票
- 03记录费用和项目工时
MCP 相关
它将 FreshBooks 数据和操作作为类型化工具提供给 MCP 客户端。写入工具根据客户端支持情况使用确认提示,或先返回预览和令牌。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @chrischall/freshbooks-mcpFRESHBOOKS_CLIENT_IDOAuth client ID from my.freshbooks.com/#/developerFRESHBOOKS_CLIENT_SECRET密钥OAuth client secretFRESHBOOKS_REFRESH_TOKEN密钥Optional for local sign-in, which saves tokens privately. Required for hosted or legacy environment-token setup.FRESHBOOKS_REDIRECT_URIRegistered redirect URI; required on refresh calls too (default https://localhost)FRESHBOOKS_TOKEN_STORE密钥Path for the rotating-refresh-token store (default ~/.freshbooks-mcp/session.json)FRESHBOOKS_BUSINESS_IDThe integer businessId to work in when the authenticated identity belongs to several businesses. Without it, reads use the first business FreshBooks lists and writes are refused rather than landing in the wrong books.FRESHBOOKS_ACCOUNT_IDOverrides the account id normally resolved from /auth/api/v1/users/me. Set it explicitly when the authenticated identity belongs to no business membership and resolution fails, or, together with FRESHBOOKS_BUSINESS_ID, when FreshBooks reports no account_id for the chosen business (accounting writes are refused until the pairing is confirmed this way).FRESHBOOKS_REQUEST_TIMEOUT_MSPer-request deadline for API calls, in milliseconds (default 30000)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
34收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
freshbooks-mcp
用于 FreshBooks 的 MCP 服务,可将发票、客户、报价和付款作为类型化工具提供给 Claude。
此项目由 AI(Claude Code)开发并维护。请自行决定是否使用。
安装
npm install -g @chrischall/freshbooks-mcp
设置
FreshBooks 仅支持 OAuth2——没有 API 密钥或个人访问令牌,因此需要一次性通过浏览器进行授权。
- 在 https://my.freshbooks.com/#/developer 注册应用。重定向 URI 必须是不带查询字符串的 HTTPS 地址;
https://localhost可用,且无需解析到任何地址。 - 记下客户端 ID和客户端密钥。
- 完成一次性授权:
- 直接从服务端操作(无需脚本):设置
FRESHBOOKS_CLIENT_ID和FRESHBOOKS_CLIENT_SECRET,启动服务,然后调用freshbooks_auth_url,打开 它返回的 URL 并批准授权,再将最终跳转到的完整 URL 传给freshbooks_auth_exchange。其中的state必须与服务端签发的授权 URL 相匹配(有效期 15 分钟,且只能使用一次),因此,裸代码或来自他人授权流程的重定向 URL 会在其代码被使用前遭到拒绝。本地会话会将令牌直接保存到FRESHBOOKS_TOKEN_STORE,并且只返回成功消息。收到该消息后,重启本地 MCP 服务。 无需将令牌复制到聊天或配置中。重启后继续使用相同的应用凭据和存储路径。 - 托管连接:mcp-host 的
authFlow仍会从交换响应中捕获刷新令牌,并通过其密钥存储提供该令牌。MCP_DATA_DIR用于标识此托管环境。请勿在本地编码 Agent 连接中设置此变量: 托管模式会有意返回令牌。签发的状态值会以摘要形式存储在MCP_DATA_DIR下,因此,即使用户批准授权时子进程被重新启动,也能完成登录。 注册配置中的流程必须向用户展示freshbooks_auth_url返回的authorize_url。 该 URL 包含一次性state,交换流程会拒绝不带该参数的任何重定向 URL。 在步骤说明中填写静态授权链接并不能提供state,因此每次新的登录或修复都会失败。 请从freshbooks_auth_url步骤传递authorize_url,并在提示用户的步骤中使用步骤链接展示它 (link: {from: 'authorize_url', hosts: ['auth.freshbooks.com']},需使用 mcp-host 2.30.0 或更高版本)。该提示必须收集完整的重定向 URL,而不只是其中的代码。 在包含状态检查的版本固定配置发布前,必须完成此更改。现有连接仍可刷新;只有新的登录和修复依赖此设置。 - 旧版/手动设置:
skills/freshbooks-curl中的脚本会打印令牌。 仅在私密终端中运行这些脚本,切勿在会被 Agent 捕获的终端中运行。
- 直接从服务端操作(无需脚本):设置
- 配置:
FRESHBOOKS_CLIENT_ID=...
FRESHBOOKS_CLIENT_SECRET=...
FRESHBOOKS_REFRESH_TOKEN=... # optional locally; if set during reauth, keep it set
FRESHBOOKS_REDIRECT_URI=https://localhost # optional; must match what you registered
FRESHBOOKS_TOKEN_STORE=~/.freshbooks-mcp/session.json # optional
FRESHBOOKS_BUSINESS_ID=... # optional; required for writes if you belong to several businesses
FRESHBOOKS_ACCOUNT_ID=... # optional; with FRESHBOOKS_BUSINESS_ID, confirms its accountId when FreshBooks omits it
FRESHBOOKS_REQUEST_TIMEOUT_MS=30000 # optional; per-request deadline for API calls
在 Claude Desktop 中,这两项都是扩展设置中的可选字段。如果 FreshBooks 未为所选企业返回
account_id,则会拒绝发票/支出的写入操作(项目和工时记录仍可正常使用),直到你手动设置这两个 ID。
⚠️ 刷新令牌会轮换
FreshBooks 每次刷新都会签发一个新的刷新令牌,并立即使旧令牌失效。此服务会在刷新完成前,将每次轮换后的令牌保存到 FRESHBOOKS_TOKEN_STORE(权限模式为 0600),并优先使用已保存的令牌,而非环境变量中的值——因为已保存的令牌比环境变量中的令牌更新。
登录流程还会写入一个小文件,其中保存待处理的授权 state 摘要(权限模式为 0600,条目在 15 分钟后过期)。在本地,该文件位于令牌存储文件旁,路径为 <FRESHBOOKS_TOKEN_STORE>.oauth-state.json(默认路径为 ~/.freshbooks-mcp/session.json.oauth-state.json)。在托管环境中,路径为 $MCP_DATA_DIR/freshbooks-oauth-state.json。首次调用 freshbooks_auth_url 时便会创建此文件,即使登录流程从未完成也是如此;文件中不包含任何令牌。
需要了解的两个后果:
- 不要让两个工具指向同一个存储文件。 MCP 服务和
freshbooks-curl技能会有意使用单独的状态文件;共用一个文件会导致它们消耗彼此的令牌,并使双方都无法登录。 - 如果存储文件丢失,请重新运行引导流程。 已失效的刷新令牌无法恢复。
不使用环境令牌在本地登录时,私有存储会绑定到应用的客户端 ID、密钥和重定向 URI。更改这些信息需要重新登录。对于现有的环境令牌配置,已保存的轮换令牌仍优先使用;将 FRESHBOOKS_REFRESH_TOKEN 更改为新值会开始一条新的令牌链。如果在设置了 FRESHBOOKS_REFRESH_TOKEN 的情况下重新进行本地授权,请保持该变量的值不变:已保存的登录信息与它绑定。若要移除该变量,请先取消设置,然后重新完成本地登录,使存储改为绑定到应用。授权码交换和本地保存使用与刷新相同的锁。刷新操作只有在持有该锁时才会写入,因此释放锁后不会覆盖更新的登录信息。
重新授权后,请重启所有使用该存储文件的本地服务。
工具
| 工具 | 用途 |
|---|---|
freshbooks_get_identity | 解析 accountId / businessId / businessUuid |
freshbooks_auth_url | 获取用于授权此连接的同意 URL |
freshbooks_auth_exchange | 完成授权;在本地会话中私密保存令牌,或将刷新令牌返回给托管式身份验证流程 |
freshbooks_healthcheck | 验证 OAuth 凭据和 FreshBooks 的可访问性;区分“没有凭据”“凭据被拒绝”和“FreshBooks 已停止运行” |
freshbooks_list_invoices / freshbooks_get_invoice | 浏览和获取发票 |
freshbooks_list_clients / freshbooks_get_client | 浏览和获取客户 |
freshbooks_list_estimates / freshbooks_get_estimate | 浏览和获取报价 |
freshbooks_list_payments / freshbooks_get_payment | 浏览和获取付款 |
freshbooks_list_items / freshbooks_get_item | 浏览和获取目录项目 |
freshbooks_create_client | 创建客户 — 需确认 |
freshbooks_create_invoice | 创建发票 — 需确认 |
freshbooks_update_invoice | 更新发票 — 需确认 |
freshbooks_record_payment | 记录发票付款 — 需确认 |
freshbooks_accept_estimate | 接受报价(action_accept)— 需确认,且具备幂等性 |
freshbooks_update_estimate | 更新报价的明细行、备注、条款和呈现方式 — 需确认 |
freshbooks_send_estimate | 向客户发送报价邮件(action_email)— 需确认 |
freshbooks_decline_estimate | 始终失败:FreshBooks 不支持拒绝报价。会提供替代方案 |
freshbooks_list_expenses / freshbooks_get_expense | 浏览和获取支出 |
freshbooks_list_expense_categories | 提供新建支出所需 categoryid 的类别 |
freshbooks_create_expense | 记录支出 — 需确认 |
freshbooks_list_projects / freshbooks_get_project | 项目(以 businessId 为键) |
freshbooks_create_project | 创建项目 — 需确认 |
freshbooks_list_time_entries | 已记录时间,包含 total_logged / total_unbilled |
freshbooks_create_time_entry | 以秒为单位记录时间 — 需确认 |
freshbooks_list_services | 项目和时间条目的可计费工作类型 |
freshbooks_list_records / freshbooks_get_record | 用于处理会计长尾数据的通用访问器(税费、贷项通知单、发票配置文件、任务、员工、支付网关、账单、账单供应商、账单付款、其他收入) |
需确认表示工具在写入前会征求你的确认。能够显示确认提示的客户端(Claude Code)会显示具体将要发送的内容。在其他环境(claude.ai、Claude Desktop)中,首次调用不会发起网络请求,而是返回将要发送的方法、路径和请求正文的预览,以及一个一次性 confirmToken;只有使用该令牌和相同参数再次调用,才会执行写入。如果预览后任何参数发生变化(DRAFT_CHANGED)、令牌已使用(TOKEN_REUSED)或令牌过期,则会拒绝该令牌。
确认
| 变量 | 默认值 | |
|---|---|---|
MCP_CONFIRM_MODE | ask-user | 在无法显示确认提示词的客户端(claude.ai、Claude Desktop)上,写入操作的处理方式。ask-user:分两步执行——首次调用不执行任何操作,只返回预览和令牌;模型必须先在聊天中获得你的批准,然后才能再次调用并使用该令牌。auto:同样分两步执行,但模型查看预览后可以自行使用令牌。refuse:此类客户端上的写入操作会被拒绝。能够显示提示词的客户端(Claude Code)始终会显示实际提示词,除非 MCP_CONFIRM_ELICITATION=off。无法识别的值会按 refuse 处理。 |
MCP_CONFIRM_ELICITATION | on | off 表示永不显示确认提示词,因此所有客户端都会采用 MCP_CONFIRM_MODE 的行为。如果客户端声称能够显示提示词但实际上从不显示(写入操作会挂起——opencode 2.0.x),请为该客户端设置此项。其他任何值都会按 on 处理,并在 stderr 上发出警告。 |
MCP_CONFIRM_TTL_SECONDS | 600 | 令牌的有效时长。 |
MCP_CONFIRM_SECRET | 每个进程随机生成 | 签名密钥;只有在令牌必须跨服务器重启继续有效时才设置。 |
估价单写入操作
接受是对估价单执行的操作,而不是状态字段:status(int)、
display_status 和 ui_status 都是计算得出的只读字段,而且它们有意不一致
(已查看的估价单显示为 status: 3、display_status: "viewed"、
ui_status: "open")。接受操作为 PUT estimates/estimates/{id},并使用
{"estimate": {"action_accept": true}}——该结构的来源请参阅
docs/FRESHBOOKS-API.md。
- 接受操作具有幂等性。 已接受(或已开具发票)的估价单会返回
changed: false,且不会发送写入请求——接受操作无法通过 API 撤销,因此 重复调用不得再次触发该操作。 - 没有拒绝操作。 FreshBooks 的估价单状态为 draft / sent / viewed /
replied / accepted / invoiced;没有 declined 状态,没有
action_deny,也没有estimate.declinewebhook。freshbooks_decline_estimate仅用于说明这一点 并指出替代方案,以免 Agent 自行编造一个不会改变任何内容的写入操作。 - 每次写入都会返回重新获取的估价单,以及
before/after状态和changed/changedFields,因此成功与否会根据记录验证,而不是根据200推断。changed涵盖状态字段以及写入操作实际设置的字段,因此成功 编辑备注时,即使状态没有变化,也会报告changed: true。对于freshbooks_send_estimate,该字段仅描述记录——向客户发送已发送过的估价单不会 改变任何内容,因此在changed: false时重试会向客户发送第二份副本。
写入操作需要所有者/管理员会计账户
FreshBooks 会分别记录你在某个企业和某个会计账户中的角色。你可以拥有一个
没有会计账户(account_id: null)的企业,同时在你实际能看到的账户中只是
客户——这种情况下,读取操作会成功,但每次写入都会返回 403 Permission Denied,
即使你的 OAuth 令牌包含所有 :write 作用域也是如此。
freshbooks_get_identity 会报告 accountRole 和 businessRole,因此可以提前
看出这一情况。如果 accountRole 是 client,开票写入工具就无法用于该账户——
这是账户权限问题,而不是配置问题。
API 报告的两个误导性信息
total会统计你可能无法读取的记录。 费用报告显示total: 16, 但返回的行数为零。如果发生这种情况,列表结果会附带note,从而表明这是 权限边界,而不是账户为空。- 项目和时间跟踪使用
businessId而非accountId作为键,并通过meta块进行分页,而不是使用扁平的page/pages/total。即使企业完全没有 会计账户,这些功能也能正常使用。
三种标识符
FreshBooks 会提供三种不可互换的 ID,用错时会返回一个简单的 404,看起来像是记录不存在:
| 标识符 | 用途 |
|---|---|
accountId(字母数字) | /accounting/account/…、/payments/account/… |
businessId(整数) | /projects/business/…、/timetracking/business/… |
businessUuid(UUID) | /accounting/businesses/… |
请先调用 freshbooks_get_identity。完整的 API 说明(包括四种不同的错误响应格式)见 docs/FRESHBOOKS-API.md。
无需服务即可使用 Shell
skills/freshbooks-curl 介绍了如何通过 Shell 使用 curl + jq 调用同一 API,包括 OAuth 引导流程和可安全轮换的令牌处理。
开发
npm install
npm run build
npm test
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。