关于 MCP Holded
面向使用 Holded ERP 处理财务、CRM 和项目工作的团队,提供 Holded v2 API 的 MCP 服务。它以分层工具整合操作,并提供账户资源、工作流提示词,以及破坏性操作确认机制。
主要功能
- 01覆盖 Holded API v2
- 0213 个分层工具
- 037 个 MCP 资源和 6 个提示词
- 04验证请求与响应
- 05破坏性操作需确认
适用场景
- 01查看逾期应收款并准备客户对账单
- 02核对银行流水与已记录付款
- 03汇总季度 VAT 数据
- 04检查月末结账待办事项
MCP 相关
通过 MCP 工具提供 Holded API 操作,并包含 7 个账户及 API 资源和 6 个工作流提示词。破坏性操作必须显式确认。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @t4dhg/mcp-holdedHOLDED_API_KEY密钥Holded v2 Personal Access Token (pat_<id>_<secret>), created under Settings, Developers, API. A v1 key is rejected at startup.HOLDED_BASE_URLOverride the API base URL (default: https://api.holded.com/api/v2)HOLDED_TIMEOUT_MSPer-request timeout in milliseconds (default: 30000)HOLDED_MAX_RETRIESRetry attempts for GET requests; writes are never retried (default: 3)DEBUGLog requests to stderr (default: false)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP Holded
适用于 Holded 的 Model Context Protocol 服务,使用 v2 API
这是一个社区项目,与 Holded 无关,也未获得其认可或支持。“Holded”及 Holded 徽标是其所有者的商标,在此仅用于标识本服务所连接的 API。
一个适用于 Holded API v2 的 MCP 服务:支持联系人、销售和采购单据、付款、资金管理、会计、商品目录、团队、CRM、项目、日历、收件箱和 Webhook。提供 13 个带有 action 参数的分层工具,对每个请求和响应进行 Zod 验证,在读取操作失败时重试,并为每项破坏性操作设置确认关卡。
Holded 已弃用其经典 API(/api/invoicing/v1,使用 key 标头)。新密钥采用 pat_<id>_<secret> 格式,且只能用于 v2(https://api.holded.com/api/v2,使用 Authorization: Bearer 进行身份验证)。本服务仅支持 v2。
为什么选择这个
- 仅支持仍可用的 v2 API。 Holded 已弃用其经典 API(
/api/invoicing/v1,使用key标头)。新令牌采用pat_<id>_<secret>格式,且只能通过 v2 进行身份验证。本服务只支持 v2。 - 提供 13 个带有
action参数的分层工具,而非每个端点对应一个工具,因此工具列表在模型上下文中保持精简,同时覆盖联系人、销售、采购、付款、资金管理、会计、商品目录、团队、CRM、项目、日历、收件箱和 Webhook。 - 提供 7 个 MCP 资源和 6 个 MCP 提示词。 资源包含账户自身的税务键、编号系列、付款方式和会计科目表,以及无法通过架构表达的 API 行为。提示词可执行实际工作流:逾期应收账款、增值税汇总、银行对账、报表和月末结账。
- 每项破坏性操作都设有确认关卡,并通过结构化测试确保文档中的列表与代码保持一致。删除、覆盖、批准或发送电子邮件等操作,未提供
confirm: true一律无法执行。 - 对每个请求和响应进行 Zod 验证。 如果遇到本服务未见过的数据结构,会明确报出架构错误,而不是静默成功。
- 包含 200 多项基于匿名化真实 v2 响应的测试,通过可信发布提供 npm 来源证明,并支持 Node 18 及更高版本。
对比情况
npm 上有 4 个 Holded MCP 服务。以下对比依据截至 2026-09-08 各项目已发布的代码,而非项目描述:@t4dhg/mcp-holded 2.1.1、@nubiia/mcp-holded 2.0.2、@energio/holded-mcp 1.5.1 和 holded-mcp 1.0.0。这只是一个快照,内容会随时间过时;使用前请自行核对当前版本。
@t4dhg/mcp-holded | @nubiia/mcp-holded | @energio/holded-mcp | holded-mcp | |
|---|---|---|---|---|
| API 版本 | v2 | v2 | v1(已弃用) | v1(已弃用) |
| 身份验证 | Bearer pat_ | Bearer pat_ | key 请求头 | key 请求头 |
| 覆盖的领域 | 13 | 18 个工具模块文件(不包括日历、预订、收件箱、webhook 或 CRM) | 5 个 API 部分(会计、CRM、开票、项目、团队) | 5 个 API 部分(会计、CRM、开票、项目、团队) |
| 工具形态 | 13 个分层工具,使用 action 参数(共 15 个工具) | 119 个扁平工具,每个操作对应一个工具 | 139 个扁平工具,每个操作对应一个工具 | 136 个扁平工具,每个操作对应一个工具 |
| MCP 资源 | 7 | 0 | 0 | 0 |
| MCP 提示词 | 6 | 0 | 0 | 0 |
| 破坏性操作的限制 | 每项操作均受限制,并经过结构化测试 | 没有确认限制;仅有 destructiveHint 注解和每个工具的速率限制 | 没有确认限制;仅有 destructiveHint 注解 | 没有确认限制;仅有 destructiveHint 注解 |
| 响应验证 | 使用 Zod 验证请求和响应 | 仅使用 Zod 验证请求 | 仅使用 Zod 验证请求 | 仅使用 Zod 验证请求 |
| Node 最低版本 | 18 | 22.14 | 20 | 18 |
| 测试 | 234 | 389 个,分布在 23 个文件中,随软件包一起发布且全部通过 | 未随软件包发布 | 未随软件包发布 |
| npm 来源证明 | 有 | 有 | 无 | 无 |
| 许可证 | MIT | MIT | MIT | MIT |
| 最后发布 | 2026-09-08 | 2026-07-07 | 2026-07-01 | 2026-02-25 |
差异最大的地方在于:v1 服务使用的是 Holded 已弃用的 API,而新的 pat_ 令牌完全无法通过该 API 进行身份验证,因此无法使用新签发的密钥。与当前的 @nubiia/mcp-holded 相比,差异包括功能范围(本服务涵盖日历和预订、收件箱、webhook,以及 CRM 潜在客户和销售漏斗,这些都不在 nubiia 的工具列表中)、资源和提示词界面、分层工具结构,以及受确认保护的原始请求备用通道。nubiia 要求的 Node 最低版本为 22.14,确实高于本服务和 holded-mcp 都支持的 18。 |
快速开始
无需安装任何内容。以下客户端都会通过 npx 运行服务。在 Holded 的 Settings, Developers, API 中创建令牌,并使用完整的 pat_..._... 值。
Claude Desktop
在 macOS 上编辑 ~/Library/Application Support/Claude/claude_desktop_config.json,或在 Windows 上编辑 %APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"holded": {
"command": "npx",
"args": ["-y", "@t4dhg/mcp-holded"],
"env": { "HOLDED_API_KEY": "pat_xxxxxxxx_xxxxxxxx" }
}
}
}
Claude Code
claude mcp add holded --env HOLDED_API_KEY=pat_xxxxxxxx_xxxxxxxx -- npx -y @t4dhg/mcp-holded
Cursor
为所有项目编辑 ~/.cursor/mcp.json,或为单个项目编辑 .cursor/mcp.json:
{
"mcpServers": {
"holded": {
"command": "npx",
"args": ["-y", "@t4dhg/mcp-holded"],
"env": { "HOLDED_API_KEY": "pat_xxxxxxxx_xxxxxxxx" }
}
}
}
VS Code
编辑 .vscode/mcp.json。请注意,键名是 servers,而不是 mcpServers:
{
"servers": {
"holded": {
"command": "npx",
"args": ["-y", "@t4dhg/mcp-holded"],
"env": { "HOLDED_API_KEY": "pat_xxxxxxxx_xxxxxxxx" }
}
}
}
需要 Node.js 18 或更高版本。
环境变量
| 变量 | 必需 | 默认值 | 用途 |
|---|---|---|---|
HOLDED_API_KEY | 是 | 无 | v2 个人访问令牌。v1 密钥会在启动时被拒绝。 |
HOLDED_BASE_URL | 否 | https://api.holded.com/api/v2 | 覆盖 API 基础地址,用于测试。 |
HOLDED_TIMEOUT_MS | 否 | 30000 | 每次请求的超时时间。 |
HOLDED_MAX_RETRIES | 否 | 3 | GET 请求的尝试次数。写入操作绝不会重试。 |
DEBUG | 否 | false | 将请求记录到 stderr。 |
使用场景
追收逾期发票。 运行 holded_aged_receivables 提示词。你会得到所有未结发票,按逾期时长分档并按客户分组,最严重的排在前面;对于部分付款的发票,只统计未付余额。然后使用 holded_contact_statement 为逾期最严重的客户生成对账单,可直接发送给对方。
核对一个月的银行账目。 针对相应期间运行 holded_bank_reconciliation。它会按金额和日期将银行流水与已记录的付款进行匹配,然后显示两份重要清单:未记录付款的流水,以及银行尚未显示的付款。核对操作需要确认,因此在你批准之前,不会在账簿中进行任何匹配。
准备季度增值税数据。 运行 holded_vat_summary。它会按季度的税项代码对销售和采购进行分组,并列出每项的计税基础和税额,格式符合 Modelo 303 的要求。这是一个工作辅助工具,不会代你提交申报;它也会明确说明这一点。
月末结账。 运行 holded_month_end_close。它会告诉你哪些项目仍为草稿、哪些已逾期,以及哪些仍在收件箱中,并为每项列出可将其处理完毕的确切调用。
工具
每个工具都接受一个 action。列表操作接受 limit(1 到 200)和 cursor;响应会说明如何继续。创建和更新操作通过 data 接收负载,遵循 Holded v2 请求约定,并返回从 API 重新读取的记录。受确认保护的操作接受 confirm: true。
| 工具 | 操作 |
|---|---|
holded_discover | 列出以下领域。 |
holded_contacts | list(精确筛选条件 email、code、phone、mobile、custom_id)、search(按 name 子串搜索)、get、create、update、delete、bulk_archive、bulk_delete、list_attachments、attach(file_path)、portal_link、list_groups、get_group、create_group、update_group、delete_group |
holded_sales | type 可选值:invoice、credit_note、estimate、proforma、sales_receipt、sales_order、waybill、receipt_note、recurring_invoice。list(contact_id、status、start_date、end_date、due_date_start、due_date_end、sort、approval_status)、get、find_by_number、pdf(output_path)、list_attachments、attach、schedule、create、update、delete、approve、cancel、send、set_pipeline、record_payment、convert、accept、reject、skip、bulk_approve、bulk_cancel、bulk_delete |
holded_purchases | type 可选值:purchase、purchase_refund、purchase_order、purchase_shipment。list(相同筛选条件)、get、pdf、list_attachments、attach、received_items、create、update、delete、approve、send、set_pipeline、record_payment、receive |
holded_payments | list(start_date、end_date、banking_account_id、document_id)、get、create、update、delete、list_methods、get_method |
holded_treasury | list_accounts(type、archived)、get_account、create_account、update_account、archive_account、delete_account、list_movements(start_date、end_date)、list_cash_movements、create_movements、reconcile(movement_id)、list_remittances、get_remittance、list_forecasts、get_forecast、create_forecast、update_forecast、delete_forecast |
holded_accounting | list_accounts(start_date 和 end_date 会添加借方、贷方和余额;include_empty)、create_account、list_ledger(必须提供 start_date 和 end_date、account)、create_ledger_entry、list_taxes、tax_keys、list_expenses_accounts、get_expenses_account、create_expenses_account、update_expenses_account、delete_expenses_account、list_sales_channels、get_sales_channel、create_sales_channel、update_sales_channel、delete_sales_channel、list_numbering_series(series_type)、create_numbering_series、update_numbering_series、delete_numbering_series、list_tags、create_tag、delete_tag |
holded_catalog | list_products(name)、get_product、product_stock、create_product、update_product、update_stock、delete_product、list_services、get_service、create_service、update_service、delete_service、list_warehouses、get_warehouse、warehouse_stock、create_warehouse、update_warehouse、delete_warehouse、list_price_lists、get_price_list、create_price_list、update_price_list、delete_price_list、list_production_orders、get_production_order、create_production_order、update_production_order、delete_production_order |
holded_team | list_employees(search)、get_employee、employee_contract、create_employee、list_times、list_salary_records(employee_id、start_date、end_date)、get_salary_record、salary_record_pdf、list_payslips、get_payslip、payslip_pdf、create_payslip_payment、delete_payslip_payment |
holded_crm | list_funnels、get_funnel、create_funnel、update_funnel、delete_funnel、list_leads、get_lead、create_lead、update_lead、delete_lead、move_stage、update_dates、add_note、update_note、add_task、update_task、delete_task |
holded_projects | list_projects(status)、get_project、project_summary、create_project、update_project、delete_project、list_tasks、get_task、create_task、update_task、delete_task、list_times、get_time、create_time、update_time、delete_time |
holded_calendar | list_events、get_event、create_event、update_event、delete_event、list_bookings、get_booking、create_booking、update_booking、cancel_booking、list_locations、slots |
holded_inbox | list(status、start_date、end_date、user_id)、get、upload(file_path)、download(filename、output_path)、update、attach、delete |
holded_webhooks | list、get、events、create、update、enable、disable、delete、usage |
holded_request | 任意 v2 端点:method、path、query、body。见下文。 |
示例
{
"action": "list",
"type": "invoice",
"status": "pending",
"start_date": "2026-01-01",
"sort": "-date",
"limit": 50
}
{
"action": "create",
"type": "invoice",
"data": {
"contact_id": "5ff44eb88ec0b10f326e3213",
"date": "2026-09-06",
"items": [{ "name": "Licence", "units": 1, "price": 1000, "taxes": ["s_iva_21"] }]
}
}
资源
七个 MCP 资源为模型提供正确调用所需的上下文。将它们附加到客户端,或通过 URI 读取。
| URI | 内容 |
|---|---|
holded://guide/api-behaviour | 已验证的 v2 行为:Bearer 身份验证和 403 而非 401 的特殊情况、游标分页、两种小数约定、DD/MM/YYYY 总账日期、RFC 7807 错误、被静默忽略的查询参数、每分钟 100 次请求的限制,以及写入操作为何从不重试。 |
holded://guide/document-types | 九种销售类型和四种采购类型及其西班牙语名称,以及每种类型支持的动词。定期发票、采购退款和估价单各自缺少其他类型所支持的某些动词。 |
holded://guide/irreversible-operations | 每项受限操作的风险和效果,均根据策略表生成,确保保持同步;还说明了为何在 Verifactu 下批准销售单不可逆。 |
holded://reference/taxes | 账户的税项键、名称和百分比。单据行必须逐字使用税项键,例如 s_iva_21。 |
holded://reference/numbering-series | 为每种单据类型配置的编号系列及其格式和最后使用的编号。 |
holded://reference/payment-methods | 付款方式 ID,record_payment 和单据的 payment_method_id 均需要这些 ID。 |
holded://reference/accounting-accounts | 科目表,记账分录需要使用。采用西班牙 PGC 编号,不能靠猜测。 |
三个指南是静态的。四个参考资源会读取账户自身的配置,并缓存十五分钟,因为客户端会在每次对话开始时重新读取资源。如果读取参考资源失败,它会返回说明和可作为后备的工具;不会抛出异常。
提示词
6 个 MCP 提示词负责运行此服务的核心工作流。每个提示词都会预先读取相关事实,并返回报告以及可据此采取行动的确切工具调用。**它们都不会写入数据。**需要更改时,提示词会生成一项受控调用,供你批准。
| 提示词 | 参数 | 功能 |
|---|---|---|
holded_aged_receivables | as_of、contact_id | 按逾期天数分档,并按联系人分组列出未结销售发票,最严重的排在前面。统计未付余额,而非单据总额。 |
holded_vat_summary | start_date、end_date | 按税务标识汇总某一期间的销项税和进项税,并列出计税基础和税额。可用于准备 Modelo 303,但不能用于申报,也不构成税务建议。默认期间为上一个日历季度。 |
holded_bank_reconciliation | start_date、end_date、account_id | 提议银行流水与已记录付款之间的匹配项,然后列出双方未匹配的项目。默认期间为上个月。 |
holded_contact_statement | contact_id 或 name | 按单据逐项列出一个联系人的开票金额、已付金额和未结金额,并标出最早的未付款项。如果 API 未提供某张单据的待付款金额,则按总额减去已付款金额计算,并说明哪些行是推算得出的。 |
holded_month_end_close | start_date、end_date | 列出某个期间结束时仍未处理的事项:草稿单据、逾期发票、收件箱单据,并附上处理每项事项的调用。 |
holded_draft_invoice | contact、description、date | 查找联系人,仅提供销售单据可用的税务标识,并组装一个供你审核的创建负载。不会创建任何内容,也绝不会批准。 |
安全
需要确认的操作
这些操作会删除、覆盖、锁定或发送电子邮件。未设置 confirm: true 时,工具不会发送任何内容,并会说明操作将产生的影响;将同一调用的 confirm: true 设为真后,操作才会继续。结构测试会确保此列表与代码中的受控操作保持一致。
holded_contacts({ action: 'update' })、holded_contacts({ action: 'delete' })、holded_contacts({ action: 'bulk_archive' })、holded_contacts({ action: 'bulk_delete' })、holded_contacts({ action: 'update_group' })、holded_contacts({ action: 'delete_group' })holded_sales({ action: 'update' })、holded_sales({ action: 'delete' })、holded_sales({ action: 'approve' })(分配法定编号;在 Verifactu 下不可撤销)、holded_sales({ action: 'cancel' })、holded_sales({ action: 'send' })(向客户发送电子邮件)、holded_sales({ action: 'set_pipeline' })、holded_sales({ action: 'skip' })、holded_sales({ action: 'bulk_approve' })、holded_sales({ action: 'bulk_cancel' })、holded_sales({ action: 'bulk_delete' })holded_purchases({ action: 'update' })、holded_purchases({ action: 'delete' })、holded_purchases({ action: 'approve' })、holded_purchases({ action: 'send' })、holded_purchases({ action: 'set_pipeline' })holded_payments({ action: 'update' })、holded_payments({ action: 'delete' })holded_treasury({ action: 'update_account' })、holded_treasury({ action: 'archive_account' })、holded_treasury({ action: 'delete_account' })、holded_treasury({ action: 'reconcile' })、holded_treasury({ action: 'update_forecast' })、holded_treasury({ action: 'delete_forecast' })holded_accounting({ action: 'update_expenses_account' })、holded_accounting({ action: 'delete_expenses_account' })、holded_accounting({ action: 'update_sales_channel' })、holded_accounting({ action: 'delete_sales_channel' })、holded_accounting({ action: 'update_numbering_series' })、holded_accounting({ action: 'delete_numbering_series' })、holded_accounting({ action: 'delete_tag' })holded_catalog({ action: 'update_product' })、holded_catalog({ action: 'update_stock' })、holded_catalog({ action: 'delete_product' })、holded_catalog({ action: 'update_service' })、holded_catalog({ action: 'delete_service' })、holded_catalog({ action: 'update_warehouse' })、holded_catalog({ action: 'delete_warehouse' })、holded_catalog({ action: 'update_price_list' })、holded_catalog({ action: 'delete_price_list' })、holded_catalog({ action: 'update_production_order' })、holded_catalog({ action: 'delete_production_order' })holded_team({ action: 'delete_payslip_payment' })holded_crm({ action: 'update_funnel' })、holded_crm({ action: 'delete_funnel' })、holded_crm({ action: 'update_lead' })、holded_crm({ action: 'delete_lead' })、holded_crm({ action: 'move_stage' })、holded_crm({ action: 'update_dates' })、holded_crm({ action: 'update_note' })、holded_crm({ action: 'update_task' })、holded_crm({ action: 'delete_task' })holded_projects({ action: 'update_project' })、holded_projects({ action: 'delete_project' })、holded_projects({ action: 'update_task' })、holded_projects({ action: 'delete_task' })、holded_projects({ action: 'update_time' })、holded_projects({ action: 'delete_time' })holded_calendar({ action: 'update_event' })、holded_calendar({ action: 'delete_event' })、holded_calendar({ action: 'update_booking' })、holded_calendar({ action: 'cancel_booking' })holded_inbox({ action: 'update' })、holded_inbox({ action: 'attach' })、holded_inbox({ action: 'delete' })holded_webhooks({ action: 'update' })、holded_webhooks({ action: 'disable' })、holded_webhooks({ action: 'delete' })
创建操作不受限制,包括 record_payment、create_movements 和 create_ledger_entry:这些操作会添加之后可以删除的记录。此限制可减少意外操作,但并非授权边界;令牌拥有 Holded 授予它的所有权限。
原始请求工具
holded_request 可访问所有 v2 端点,使用正确的 Bearer 身份验证,并返回未经验证的响应。DELETE、PUT 和 PATCH 需要 confirm: true;对路径中包含 bulk、cancel、archive、approve、send、reconcile、ship、skip、clock-in 或 clock-out 的路径发起 POST 也需要如此,因为 Holded 将破坏性操作隐藏在这些路径后面。被拒绝的调用会返回原本要发送的确切方法、URL 和正文。
API 的实际行为
以下内容均已根据 2026-09-06 的实时 v2 响应进行验证,也是构建这些架构的依据。
- 分页基于游标。 列表返回
{ items, cursor, has_more };cursor是最后一个项目的 ID,并通过?cursor=传回。limit默认值为 50,上限为 200;page和offset会被忽略。配置列表(税项、标签、仓库、会计科目、费用科目、销售渠道、编号系列、价格表、预订地点)返回{ items },不带游标。 - 金额为字符串,采用两种小数表示格式。 销售和采购单据、单据行以及工资记录使用逗号(“63500,00”)。付款、资金账户、银行流水、会计科目和分类账分录使用句点(“8.3”、“0.00”)。服务端会原样传递这些值,绝不进行转换,因此不会发生舍入。
- 分类账日期格式为
DD/MM/YYYY。 其他所有日期均为 ISO 8601 格式。 - 错误遵循 RFC 7807(
{ type, title, status, detail }),适用于 400、403 和 404。密钥错误或缺失会返回 403“Access denied”,而不是 401。未知路由会返回 404{ message: "No route found..." }。某些格式错误的路径会返回 Holded 的 HTML 应用外壳,状态码为 200 或 405;服务端会将其转换为错误,而不会返回 HTML。 - 未记录的查询参数会被静默忽略。
/contacts上的query、q和search不会筛选任何内容;请使用search(它会调用/contacts/search?name=)或精确匹配筛选条件。 - 按 ID 获取单据时返回的内容比列表更多,包括:
accounting_date、approved_at、notes、language、payments_detail、payments_refunds、shipping、design_id、pipeline_id等。 - 并非每种单据类型都支持所有操作。 采购退款在
/purchase-refunds下列出,但需通过/purchases/refund读取和创建,且不支持其他操作(没有更新、删除、PDF、附件或审批)。采购没有 PDF 或发送路由。定期发票仅支持更新、删除、跳过和排期。估价单、形式发票、订单和运货单不支持付款。遇到不支持的组合时,工具会在发送任何内容之前拒绝操作,并列出可用操作。 - 编号系列类型包括 invoice、purchase、estimate、creditnote、salesorder、waybill、salesreceipt 和 purchaserefund。
- 速率限制为每个密钥每分钟 100 次请求。GET 请求遇到 429(遵循
Retry-After)、5xx、超时或网络错误时,会使用指数退避和随机抖动重试。写入请求只发送一次,因为 Holded 不提供幂等键。 - 创建操作返回
{ id },状态码为 201。服务端会重新读取记录,因此工具返回的是经过验证的对象。 - CRM 潜在客户、项目、任务、事件、预订、webhook、工资单、价格表、生产订单、销售订单、销售收据、收货单、采购货运和汇款的架构来自 OpenAPI 文档,而非实时记录,因为用于验证的账户中没有这些数据。它们都是宽松对象,因此额外字段也会原样传递;如果存在任何不匹配,都会明确显示架构错误,而不会静默地报告成功。
故障排除
服务端因密钥相关消息而立即退出
HOLDED_API_KEY 必须是 v2 个人访问令牌,格式为 pat_<id>_<secret>。服务端会在启动时检查这一点,若格式不符便拒绝运行,而不是等到每次调用时才失败。经典 v1 密钥由 32 个十六进制字符组成,完全无法通过 v2 身份验证。
所有请求都返回 403“Access denied”
这通常表示 v2 中的令牌无效、已撤销或权限范围有误。Holded 返回的是 403,而不是 401,因此看起来像是权限问题,但通常其实是身份验证问题。请在 Holded 的 Settings、Developers、API 中重新生成令牌,并确认复制了完整的 pat_..._... 值,包括两个下划线。
某个工具提示该文档类型不支持某项操作
并非每种文档类型都支持所有操作。采购退款不支持更新、删除、pdf、附件或审批。采购不支持 pdf 或发送。定期发票仅支持更新、删除、跳过和安排。估价单、形式发票、销售订单和送货单不支持付款。工具会在发送任何内容前拒绝操作,并列出可用操作。完整矩阵见 holded://guide/document-types 资源。
某个筛选条件似乎没有生效
很可能确实没有生效。Holded 会静默忽略未记录的查询参数:在 /contacts 上使用 query、q 和 search 不会筛选任何内容,而是返回所有结果。请使用 search 操作,它会调用 /contacts/search?name=;或者使用精确匹配筛选条件 email、code、phone、mobile 和 custom_id。page 和 offset 在任何地方都会被忽略;分页使用 cursor。
某个资源提示无法读取
四个 holded://reference/... 资源会读取实时配置,因此需要可用的令牌。它们会返回说明,而不是抛出错误,因此服务会继续运行。三个 holded://guide/... 资源是静态的,始终可以读取。
设置 DEBUG=true
这样会将每个请求记录到 stderr。绝不会写入 stdout,因为它是 MCP 传输通道。
常见问题
它是否支持旧版 v1 API 密钥? 不支持,这是有意为之。v1 已弃用,新密钥无法通过它进行身份验证。若同时支持两者,就意味着要维护两条代码路径,其中一条已经行不通。
它会不会意外删除内容? 每项删除、覆盖、审批、取消或发送邮件的操作都需要 confirm: true。如果没有该参数,工具不会发送任何内容,而是告诉你它原本会执行什么操作。该列表由代码生成到 holded://guide/irreversible-operations 中;如果文档列表与代码不一致,测试就会失败。
写入超时时会发生什么? 不会重试。Holded 不支持幂等键,因此重试写入可能会重复扣款或重复开具。读取操作会采用退避策略重试;写入操作则只会发送一次。如果写入超时,请先读取记录,再决定是否重试。
为什么审批发票需要确认? 因为审批会分配法定发票号码。根据 Verifactu,该号码属于不可变的链式记录,无法撤销:出错时需要开具贷项通知单,而不是编辑。
金额往返传递时会保持准确吗? 会。金额以字符串形式传递,服务会原样转发,因此不会进行舍入。请注意,两种场景使用的格式不同:文档和薪资记录使用逗号;付款、资金管理和会计使用句点。
我能否访问没有专用操作的端点? 可以,holded_request 可通过正确的身份验证访问任何 v2 路径。具有破坏性的请求方法和路径在此处也受到限制。
该项目是否与 Holded 有关联? 没有。这是一个使用其公开 API 的社区项目。
开发
npm install
npm run lint && npm run typecheck && npm run format:check && npm test && npm run build
HOLDED_API_KEY=pat_..._... npm run smoke # spawns the built server over stdio and makes one read call
测试使用 src/__tests__/fixtures 中经过匿名化处理的固定数据;每份数据都来自真实的 v2 响应,其中的名称、税号、地址、银行信息和金额均已替换。添加端点时请同时添加固定数据;任何缺少架构的固定数据都会导致架构测试失败。
发布
发布由 CI 分阶段执行,并由人工批准。更新 package.json 中的版本,提交更改,创建 vX.Y.Z 标签并推送该标签。发布工作流会通过 OIDC 以受信任发布者身份向 npm 进行身份验证(全程不使用令牌),运行测试和构建,并执行 npm stage publish。在维护者于本地运行 npm stage approve <stage-id> 之前,任何内容都无法安装;这一步会验证双重身份验证。具体步骤请参阅 CONTRIBUTING.md。
Security
Report vulnerabilities through GitHub Security Advisories; see SECURITY.md.
License
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。