mcpField
M
MCP Holded

MCP Holded

本地服务
github.com商业与营销17 周前更新

关于 MCP Holded

面向使用 Holded ERP 处理财务、CRM 和项目工作的团队,提供 Holded v2 API 的 MCP 服务。它以分层工具整合操作,并提供账户资源、工作流提示词,以及破坏性操作确认机制。

主要功能

  1. 01覆盖 Holded API v2
  2. 0213 个分层工具
  3. 037 个 MCP 资源和 6 个提示词
  4. 04验证请求与响应
  5. 05破坏性操作需确认

适用场景

  1. 01查看逾期应收款并准备客户对账单
  2. 02核对银行流水与已记录付款
  3. 03汇总季度 VAT 数据
  4. 04检查月末结账待办事项

MCP 相关

通过 MCP 工具提供 Holded API 操作,并包含 7 个账户及 API 资源和 6 个工作流提示词。破坏性操作必须显式确认。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"t4dhg-mcp-holded": {
"command": "npx",
"args": [
"-y",
"@t4dhg/mcp-holded"
],
"env": {
"HOLDED_API_KEY": "<HOLDED_API_KEY>",
"HOLDED_BASE_URL": "<HOLDED_BASE_URL>",
"HOLDED_TIMEOUT_MS": "<HOLDED_TIMEOUT_MS>",
"HOLDED_MAX_RETRIES": "<HOLDED_MAX_RETRIES>",
"DEBUG": "<DEBUG>"
}
}
}
}
启动命令npx -y @t4dhg/mcp-holded
需要配置的环境变量
HOLDED_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+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@t4dhg/mcp-holded2.1.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Holded

MCP Holded

适用于 Holded 的 Model Context Protocol 服务,使用 v2 API

License: MIT CI codecov TypeScript Node.js npm version npm downloads MCP Compatible

这是一个社区项目,与 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-mcpholded-mcp
API 版本v2v2v1(已弃用)v1(已弃用)
身份验证Bearer pat_Bearer pat_key 请求头key 请求头
覆盖的领域1318 个工具模块文件(不包括日历、预订、收件箱、webhook 或 CRM)5 个 API 部分(会计、CRM、开票、项目、团队)5 个 API 部分(会计、CRM、开票、项目、团队)
工具形态13 个分层工具,使用 action 参数(共 15 个工具)119 个扁平工具,每个操作对应一个工具139 个扁平工具,每个操作对应一个工具136 个扁平工具,每个操作对应一个工具
MCP 资源7000
MCP 提示词6000
破坏性操作的限制每项操作均受限制,并经过结构化测试没有确认限制;仅有 destructiveHint 注解和每个工具的速率限制没有确认限制;仅有 destructiveHint 注解没有确认限制;仅有 destructiveHint 注解
响应验证使用 Zod 验证请求和响应仅使用 Zod 验证请求仅使用 Zod 验证请求仅使用 Zod 验证请求
Node 最低版本1822.142018
测试234389 个,分布在 23 个文件中,随软件包一起发布且全部通过未随软件包发布未随软件包发布
npm 来源证明有有无无
许可证MITMITMITMIT
最后发布2026-09-082026-07-072026-07-012026-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否3GET 请求的尝试次数。写入操作绝不会重试。
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_contactslist(精确筛选条件 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_salestype 可选值: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_purchasestype 可选值: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_paymentslist(start_date、end_date、banking_account_id、document_id)、get、create、update、delete、list_methods、get_method
holded_treasurylist_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_accountinglist_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_cataloglist_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_teamlist_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_crmlist_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_projectslist_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_calendarlist_events、get_event、create_event、update_event、delete_event、list_bookings、get_booking、create_booking、update_booking、cancel_booking、list_locations、slots
holded_inboxlist(status、start_date、end_date、user_id)、get、upload(file_path)、download(filename、output_path)、update、attach、delete
holded_webhookslist、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_receivablesas_of、contact_id按逾期天数分档,并按联系人分组列出未结销售发票,最严重的排在前面。统计未付余额,而非单据总额。
holded_vat_summarystart_date、end_date按税务标识汇总某一期间的销项税和进项税,并列出计税基础和税额。可用于准备 Modelo 303,但不能用于申报,也不构成税务建议。默认期间为上一个日历季度。
holded_bank_reconciliationstart_date、end_date、account_id提议银行流水与已记录付款之间的匹配项,然后列出双方未匹配的项目。默认期间为上个月。
holded_contact_statementcontact_id 或 name按单据逐项列出一个联系人的开票金额、已付金额和未结金额,并标出最早的未付款项。如果 API 未提供某张单据的待付款金额,则按总额减去已付款金额计算,并说明哪些行是推算得出的。
holded_month_end_closestart_date、end_date列出某个期间结束时仍未处理的事项:草稿单据、逾期发票、收件箱单据,并附上处理每项事项的调用。
holded_draft_invoicecontact、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

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。