mcpField
E
Ekwo OS — open source accounting: ledger, invoices and VAT on your own Supabase or Postgres

Ekwo OS — open source accounting: ledger, invoices and VAT on your own Supabase or Postgres

远程服务
ekwo.ai金融数据40今天更新

关于 Ekwo OS — open source accounting: ledger, invoices and VAT on your own Supabase or Postgres

Ekwo OS 的 MCP 服务让 AI Agent 在用户自己的 Postgres 或 Supabase 安装中处理会计记录。它使用用户权限操作,由数据库策略控制访问和过账,而非使用高权限服务密钥。

主要功能

  1. 01读取分类账及会计记录
  2. 02创建并过账发票
  3. 03匹配付款
  4. 04准备增值税申报
  5. 05遵循用户和公司访问策略
  6. 06支持托管 HTTP 与本地 stdio 模式

适用场景

  1. 01查看公司分类账分录
  2. 02准备并过账发票
  3. 03将付款与记录匹配
  4. 04准备增值税申报

MCP 相关

该服务通过本地 stdio 或 Streamable HTTP 向 MCP 客户端提供 Ekwo OS 会计操作。它支持本地安装和托管端点,并在数据库策略约束下使用用户访问权限或 Ekwo OS API 密钥。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://mcp.ekwo.ai/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
npm@ekwo-ai/mcp0.24.0

工具

详细介绍

@ekwo-ai/mcp

Ekwo OS 的 Model Context Protocol 服务。它让 AI Agent 能在你自己的 Postgres 中处理账簿:读取账本、开具发票、过账、匹配付款、准备增值税申报表——以你的身份操作,并遵守你自己的安装实例中的行级安全策略。

有两种方式可以连接到它,它们连接的是同一个服务。

托管服务,地址为 https://mcp.ekwo.ai/mcp

适用于添加远程服务而非启动服务的客户端——claude.ai,或任何支持 Streamable HTTP 的客户端。无需安装,也无需将密码或密钥写入配置文件。

https://mcp.ekwo.ai/mcp

让客户端连接到该地址,它就会发现其余信息。未经身份验证的调用会收到 401 响应,并附带一个 WWW-Authenticate 标头,其中包含该服务受保护资源的元数据(RFC 9728);客户端会根据该信息找到授权服务器(RFC 8414),自行注册(RFC 7591,因此无需提供自己的凭据),并让用户前往浏览器批准连接。请求的作用域为 books。

没有浏览器的 Agent 可以从 /.well-known/oauth-protected-resource 开始。

账簿会留在原处:托管服务不保存账簿,而是在用户批准连接时接入其选择的实例。在同一屏幕上,用户可以决定是否允许 Agent 写入;否则,Agent 只能读取。托管服务由 Ekwo Cloud 运营,登录该服务需要一个账户——免费账户可通过地址和六位数代码注册,还可访问这些账簿对应的 Web 应用,并为其关联的每家公司提供每晚备份。

本地运行,通过 stdio 连接

npx -y @ekwo-ai/mcp@latest

适用于启动自身服务的客户端——Claude Desktop、Claude Code,以及任何读取 .mcp.json 的编辑器——可连接到任意安装实例,无需账户。命令中请保留 @latest:在仓库克隆目录中运行不带其他参数的 npx @ekwo-ai/mcp,会找到尚未构建的工作区包,并报错 ekwo-mcp: command not found。

安装命令行工具后,ekwo mcp 会启动同一个服务——相同的入口点 runStdio()、相同的标志(--autopilot、--review)和相同的环境:"command": "ekwo", "args": ["mcp"]。

它是什么,以及它不是什么

该服务本身不持有任何权限。它会以使用者的身份登录,或者接收其访问令牌;此后它能执行的所有操作,完全取决于该用户本身的权限:查看者只能读取,不能写入;某家公司的成员看不到其他公司;已锁定的期间会拒绝过账。本包不会检查这些规则——由架构中的策略和触发器决定,服务只报告它们返回的结果。

它永远不会做以下三件事:

  • 写入账本条目。 每笔分录都通过架构自身的函数生成,这些函数会执行会计规则。直接插入仅用于用户手动填写的对象:联系人、草稿单据及其明细、付款和银行交易。
  • 删除或编辑已过账的条目。 没有任何工具会删除条目。已过账的发票只能按照其所在国家/地区允许的方式撤销——若其内容尚未产生任何影响,则退回草稿状态;否则,创建一张注明该发票的贷项通知单;手动录入的条目则通过其冲销分录撤销。
  • 使用 service_role 密钥。 它确实能用,但问题也正在于此:它会绕过所有策略,导致 Agent 能为其用户从未获准加入的公司作答。服务不会使用这种密钥启动。

配置

推荐方式:以已登录用户身份通过 PostgREST 连接
{
  "mcpServers": {
    "ekwo": {
      "command": "npx",
      "args": ["-y", "@ekwo-ai/mcp@latest"],
      "env": {
        "SUPABASE_URL": "https://YOURREF.supabase.co",
        "SUPABASE_ANON_KEY": "your anon (publishable) key",
        "EKWO_EMAIL": "[email protected]",
        "EKWO_PASSWORD": "your password"
      }
    }
  }
}

对于 Claude Desktop,请将此配置块放入 claude_desktop_config.json;对于 Claude Code,请将其放入项目根目录的 .mcp.json。如果你已经持有会话,EKWO_ACCESS_TOKEN 会替代地址和密码;使用密码登录时,会话会保存在内存中并自动续期,不会写入磁盘。

备用方案:直接连接 Postgres

适用于数据库前面没有 PostgREST 的可自托管安装,或用于测试。

{
  "env": {
    "EKWO_DB_URL": "postgresql://…",
    "EKWO_ACT_AS_USER_ID": "the auth.users id this server acts for"
  }
}

EKWO_ACT_AS_USER_ID 是必需项,这正是此模式的关键。数据库连接不代表任何用户:auth.uid() 为 null,行级安全策略会被绕过,而非得到满足;以这种方式运行的服务相当于绕过策略,而不是遵循策略的客户端。因此,每个查询都会在一个事务中运行,该事务会将 request.jwt.claims 设置为该用户,并切换到 authenticated 角色,策略的绑定方式与通过 API 时完全相同。此模式需要与服务端一同安装 postgres 包;推荐方式完全不需要驱动程序。

变量含义
SUPABASE_URLhttps://<ref>.supabase.co
SUPABASE_ANON_KEYanon(可发布)密钥。不接受 service_role 密钥。
EKWO_EMAIL / EKWO_PASSWORD此 Agent 代表其执行操作的用户
EKWO_ACCESS_TOKEN已有会话时使用此项,无需设置上述两项
EKWO_DB_URL直接连接 Postgres 的连接地址,适用于可自托管安装
EKWO_ACT_AS_USER_ID与 EKWO_DB_URL 一同使用时必需:要代表其执行操作的 auth.users ID
EKWO_NO_REGISTER_INVITE可选。设为 1 时,说明中不包含邀请注册的内容
EKWO_NO_CLOUD_OFFER可选。设为 1 时,说明中不包含免费 Ekwo Cloud 账户的邀请;设置 CI 也会如此
EKWO_AGENT_POSTING可选。autopilot 或 review:选择此会话的发帖方式,与 --autopilot 和 --review 的选择相同。未设置时,由各公司的 agent_posting 决定。参见审核或自动驾驶
EKWO_EINVOICE_DIRECTORY可选。einvoicing_issue 使用 send 时,电子发票发送到的文件夹。未设置时,发票会生成并保留,但拒绝发送,并返回 no_transport
EKWO_FISCAL_SYSTEM可选。einvoicing_fiscalise 以 JSON 格式指定其下挂接税务记录的开票系统:name、id、version、installation、producerName、producerTaxId,以及相应制度可能要求的布尔值(verifactuOnly、multipleTaxpayers、multipleTaxpayersNow)。未设置时,税务处理会被拒绝,并返回 no_fiscal_system;格式错误时,服务不会启动
未设置任何变量时启动

客户端添加服务后会立即列出其工具,索引 MCP 服务的目录也会如此。因此,即使上面的变量一个都没设置——或只设置了一部分——服务仍会启动并响应工具列表请求,而每次工具调用都会返回 not_configured 错误,说明需要设置哪些变量以及设置位置。在此之前,服务不会连接到任何地方,并且只提供基础模块的工具:安装包含哪些模块,需要从其数据库中读取。

只有缺少设置可以被忽略。无论在哪个位置使用 service_role 密钥,或将非 uuid 值写入 EKWO_ACT_AS_USER_ID,都属于有人明确填写了值的情况,服务仍会拒绝启动。

npm run build -w @ekwo-ai/mcp
node packages/mcp/scripts/introspect.mjs     # starts it with no environment and lists the tools

仓库根目录下的 Dockerfile 会从检出代码构建同一个服务;docker run -i --rm <image> 通过标准输入输出使用 MCP,变量通过 -e 传入。

通过 HTTP:托管服务供他人使用

同一个服务,通过 URL 访问,而不是由客户端启动: handleHttpRequest 响应 MCP 的 Streamable HTTP 传输。它是无状态的——每个请求都会创建一个服务,以 JSON 响应后将其关闭,不需要会话 ID,也不保留任何内容——因此它可以运行在函数平台上、负载均衡器之后,或单个进程中。GET 请求会收到 405 响应:此服务不会先发起通信,因此没有流可打开。

它不会判断调用者是谁:宿主以自己的方式验证请求,然后传入该请求可以使用的连接。

import { handleHttpRequest } from '@ekwo-ai/mcp';

export default async function (request: Request): Promise<Response> {
  const who = await yourOwnAuthentication(request);      // a token you issued
  if (who === undefined) return new Response(null, { status: 401 });
  return handleHttpRequest(request, {
    supabaseUrl: who.supabaseUrl,                         // https://<ref>.supabase.co
    anonKey: who.publishableKey,                          // never the service_role key
    apiKey: who.ekwoKey,                                  // or: accessToken: who.session
  });
}

连接只能是以下两者之一,不能兼具:

  • 实例上的某个人员访问令牌。行级安全会像该人员在浏览器中操作时一样作出判断。
  • Ekwo OS 的密钥,由 create_api_key() 签发。密钥通过 X-Ekwo-Api-Key 标头传递,旁边不带 Authorization;架构的请求前钩子会提交该密钥(决策 0062),调用者属于该密钥对应的唯一公司,并具备该密钥的能力。未授予写入能力的密钥签发后,会让 Agent 只能读取。

与 stdio 一样,service_role 密钥在这三个位置都会被拒绝。对于 node:http(或基于它构建的任何内容),handleNodeRequest(req, res, connection, { origin }) 是相同的处理程序。

面向用户部署:授权

远程 MCP 客户端要求服务遵循 MCP 规范中的授权部分:采用 PKCE 的 OAuth 2.1、受保护资源元数据(RFC 9728)、授权服务器元数据(RFC 8414)和动态客户端注册(RFC 7591)。这属于宿主,而非此软件包:宿主负责让人员登录、签发自己的令牌,并将每个令牌映射到上述连接。数据库仍是唯一决定可读取或写入内容的地方。

工具

每次写入都会明确指定所属公司。

工具功能
list_companies你所属的公司,以及你在每家公司的角色
get_company财政年度、锁定日期、日记账和默认科目
list_accounts公司使用的科目,可按代码前缀、类型或名称筛选。使用 include_all 查看完整科目表
search_contacts按名称、类型或 VAT 号码搜索客户和供应商
suggest_duplicate_contacts可能属于同一方的联系人,按可能性从高到低排列,每行一个待合并联系人;属于同一方的联系人行会归为一组:要保留的联系人、评分、依据(相同的 VAT 或注册号码、相同的银行账户、按使用该名称的联系人数量加权的名称词语),以及该组中最简洁的名称,建议用于保留的联系人。不会写入任何内容;用户确认后,merge_contacts 会合并一对联系人
search_products产品目录:销售和采购商品的代码、单位、价格、科目和税项
list_documents按条件筛选发票、贷项通知单和报价单
get_document单份单据及其明细行和由其生成的分录
render_invoice_pdf销售发票或贷项通知单的 PDF,作为 PDF 资源(base64)与 JSON 摘要一起返回;根据账簿内容由 @ekwo-ai/invoice-pdf 渲染。factur_x 会嵌入已入账销售单据的 CII(Factur-X、EN 16931、PDF/A-3),并返回其违反的规则;labels 会返回单据版面所用语言的文字。服务会从公司的 logo_url 获取徽标,绝不会从本地或私有地址获取。不记录任何内容
list_bank_accounts公司的银行账户,以及每个账户关联的日记账和总账科目
list_bank_transactions银行对账单行,默认仅显示待处理项
trial_balance每个科目的期初余额、发生额和期末余额
general_ledger某个科目的所有已入账行及其滚动余额
journal_book一本日记账或所有日记账的账簿:期间内所有已入账行,按账簿的阅读顺序排列,并在开头列出每本日记账的合计
suggest_line_contacts对于未指明联系人名称的未结应收或应付行,按可能性从高到低列出可能的联系人,以及每个联系人的依据和该依据匹配到的联系人数量。不会写入任何内容
suggest_item_combinations对于某个往来方的每条未结应收或应付行,列出可结清该行的另一方行:精确配对、合计到分的多行,或在公司差额容限内的行,并显示差额。不会写入任何内容
matching_difference_options可用于记账差额的原因、软件包为每种原因指定的科目,以及公司的容限
aged_balance从总账读取并按账龄区间分类的未偿金额
vat_return从总账汇总得出的某一期间的申报栏数据
instalment_plan公司 VAT 方案要求在某一期间缴纳的预缴款:到期金额、已付金额和未付金额
ec_sales_list欧盟供应交易汇总清单:每个客户 VAT 号码和每种交易性质各一行
portfolio_upcoming_filings组合 = 你有权读取的公司;对于会计师事务所,这些公司是其客户(docs/firms.md)。列出你对其持有 filings.read 权限的每家公司在两个日期之间到期的事项。每家公司至少一行:软件包未指定截止日期时,会列出该公司但不显示日期,并说明原因
portfolio_filings_touched_since在同一批公司中,列出已提交且之后期间内又录入了分录的申报,并注明公司
list_statements / financial_statement公司可使用的报表方案,以及其中一份报表
financial_analysis分析中的收入、净利润、权益、资产总额、流动资产、现金、应收款、应付款及其他汇总项,每项均列出构成该项的科目;科目由国家软件包定义,或在未定义时通过通用框架按科目类型读取——source 会说明采用哪种方式(docs/analysis.md)
list_analytic_axes公司的分析轴——例如成本中心、项目或地点——以及每个分析轴的值;这些值可以嵌套。还会列出 required_on,即过账时必须填写该分析轴的行
analytic_report从已入账总账读取某一期间内某个分析轴各值的收入、费用、结果和固定资产变动;包含完整损益表、显示其下各值小计的父级值、unassigned(该轴未覆盖的部分)以及 total(decisions/0076-an-analytic-value-is-entered-on-the-line.md)
generate_fec为采用法国账簿的公司生成法语 FEC 文本,并附带检查结果和文件名
read_audit_log谁在何时更改了什么:公司的配置以及改变状态的操作。每个客户端的日志均为只追加写入;只有数据库可以写入
get_preferences你的偏好设置,以及读取标签时使用的语言回退链
list_invitations已获邀加入公司但尚未加入的人员
list_api_keys公司的机器密钥,以及每个密钥可执行的操作
describe_pack此安装包含哪些国家软件包:其版本、任何人已阅读的内容、每个软件包所依据的原始文献登记信息——标题、官方发布方、链接和查阅日期;对于经过验证的软件包,还会列出其证据:每个范围、申报类型、年份、已复现和未测试的内容
status架构版本、实例、连接、公司
create_contact创建客户、供应商或其他第三方联系人
merge_contacts合并属于同一方的两个联系人:所有指向被合并联系人的内容(包括已入账行和已开具单据)都会改为指向保留的联系人,并填充保留联系人的空字段;被合并的联系人会被停用。如果两个联系人的 VAT 或注册号码不同、联系人曾被合并,或合并会跨越两个不同方,则会明确拒绝
create_product创建产品目录行:代码、名称、单位、价格、科目、税项
update_product修改产品,或通过 active: false 将其停用
pin_accounts将科目加入公司优先显示的工作科目表,或通过 pinned: false 将其移除
create_document创建包含明细行的发票、贷项通知单或报价单草稿。使用 client_ref 时,重复调用只会创建一次
update_document_lines替换草稿的明细行
post_document按复核或自动模式入账(见下文):在 review 模式下,只有在某人批准当前草稿后才会入账;否则返回 approval_required;在 autopilot 模式下则直接入账。两种模式下,dry_run: true 都会返回数据库将写入的分录,但不会写入任何内容
cancel_document撤销已入账的发票,并在 undone_by 中说明撤销方式:如果其所在国家的 posted_edit_policy 允许,且该发票的任何内容都未对外发送,则还原为 draft(unpost_document());否则创建一张指向该发票的贷项通知单并将其入账、与该发票核销,然后取消该发票(cancel_document()),并通过 why 说明为何不允许还原。若所属期间仍开放,贷项通知单日期与发票日期相同;否则由调用方提供日期。提供日期或设置 credit_note: true 即表示要求创建贷项通知单
reverse_entry撤销手动指定的已入账分录:创建镜像分录,按下一个编号入账,并与原分录核销。日期适用相同规则
record_payment记录收入或支出并与未结发票核销;如果提供 document_id,则只与该单据核销,且该单据会确定联系人和收支方向。使用 client_ref 时,重复记录只会记录一次
set_line_contact为此类行指定联系人,仅限从未指定联系人变更为该公司的一位联系人,并将该标签作为模式记录下来。如果该行已指定某人、已核销、不属于应收或应付科目,或联系人属于另一家公司,则会明确拒绝
leave_line_unnamed / undo_leave_line_unnamed有意将此类行保留为未指定联系人状态并记录原因,使其不再被建议;或撤销此操作
reconcile_many在同一往来方和同一科目下,将多行合并核销;其未结借方和贷方必须精确到分地相等,并使用同一个字母标记
reconcile_with_difference同样地核销,但允许存在小额差异;差异会在公司的容限内记入软件包为相应原因(rounding、exchange_difference)指定的科目,然后进行核销
reconcile / unreconcile核销两条总账行,或撤销一次核销
create_bank_account按公司所在国家使用的方案,根据银行账户标识注册账户(如 IBAN、路由号码和账户号码、排序代码和账户号码……),并将其关联到银行日记账。使用相同标识重复运行不会创建任何内容
create_bank_transaction在没有银行数据导入源的安装中,手动创建一条银行对账单行
settle_from_statement将银行对账单行作为实际付款入账,并在同一分录中与指定的单据或未结项目核销;使用 amounts 指定结清每项的金额;使用 extra_lines 记录支付服务商扣留的费用或银行手续费,并指定用户提供的科目和税项。该行必须精确到分地平衡,否则将拒绝(settlement_unbalanced);仅使用额外行即可结清银行手续费
import_bank_statement将对账单文件(camt.053、coda、cfonb120)导入为对账单及待处理行。不进行记账;同一文件重复导入不会创建任何内容;未知账户或对账单金额不平衡时会明确拒绝,并在缺少对账单时发出提示
lock_period移动会计和 VAT 锁定日期。需要 company.write 权限。
opening_balance将此前持账的账簿试算平衡表作为期初分录:记在年度第一天,或记在 opening_date(年内接手账簿的日期)。items 是该日仍未结清的发票和贷项通知单:每项都是已入账单据,包含单据编号、付款参考和到期日,银行对账单核销时会像匹配本公司开具的发票一样匹配这些项目;同一科目的各项目合计必须与其对应行金额相等
import_books导入在其他地方维护的账簿——FEC、日记账项目导出文件、日记账报告或试算平衡表——要么全部导入,要么完全不导入;试算平衡表可附带 open_items。先运行 dry_run: true:查看为每个科目和日记账提出的对应关系——只有文件未提供矛盾信息且代码完全相同才标记为 exact;否则标记为 suggested 并说明原因,或标记为 none;还会显示无法对应的内容,以及由数据库演练并回滚的导入结果。然后补全 mapping 再次运行,或由用户阅读所有建议后使用 accept_suggestions;任何对应关系尚未确认时都不会过账。所有分录均通过 post_entry();不含税项;重复导入相同文件会被拒绝,并说明时间和原因。文件以文本形式传入,最大为 256 KiB;超过此限制时,该工具会返回 ekwo import 命令,由其从磁盘读取文件。ekwo import 执行相同的功能
close_fiscal_year / reopen_fiscal_year按国家软件包规定结账,使用 final_close 指明该国家是否还要求最终结账以及截止时间;或重新打开年度以进行更正,无论之后还有哪些年度。若之后有已结账年度,必须先重新打开该年度
close_fiscal_year_finally对已结账年度进行最终结账:此后任何人都不能重新打开,包括操作员。仅在用户明确要求时使用
create_company在国家软件包上创建公司,并配置其科目表和首个财政年度。此操作针对整个实例
update_company_profile公司在其单据上展示的信息,以及单据编号格式
set_number_prefix设置某本日记账在编号中用来替代 {CODE} 的内容
set_preferences设置你自己的语言、时区、格式和默认公司
invite_member / revoke_invitation邀请某个地址加入公司,或撤回邀请。令牌仅显示一次
remove_member / set_member_role将成员移出公司——移除自己无需 members.manage 权限——或将其调整为另一个预设角色,并清除该成员的单独调整。最后一位所有者既不会被移除,也不会被降级
create_api_key / revoke_api_key为机器创建密钥,并限定其适用公司和权限列表
share_document / list_shares / revoke_share发布已入账销售单据,生成客户无需账户即可打开的链接;列出链接及每个链接的打开次数;或撤回链接(docs/sharing.md)
list_accounts 返回的是正在使用的会计科目表,而不是完整科目表。 国家/地区包会记录法规中的科目表——有时超过一千个科目——而公司实际使用的只有几十个。默认返回已有过账分录、被公司设置或已启用模块引用,以及有人通过 pin_accounts 固定的科目。include_all 会返回完整科目表,而每个写入工具仍接受其中任意科目。

post_document、cancel_document、reverse_entry、record_payment、update_document_lines、unreconcile、settle_from_statement、lock_period、opening_balance、import_books、close_fiscal_year、reopen_fiscal_year、close_fiscal_year_finally、revoke_invitation、remove_member、set_member_role、revoke_api_key 和 revoke_share 在协议中标记为具有破坏性,因此客户端可以在调用前询问。

工具能够执行的操作取决于用户拥有的权限,而不是工具自身的权限:服务以登录用户的身份执行操作,因此会计师可以使用 post_document,而查看者则会被数据库拒绝,拒绝信息也由数据库原样返回。get_company 会返回 your_capabilities,正是出于这个原因。

模块。 此安装中的每个模块都有自己的工具,名称使用其 module.json 声明的前缀;服务会在启动时读取 public.modules,以确定可用工具:fixed_assets_list、fixed_assets_create、fixed_assets_schedule、fixed_assets_run_depreciation、fixed_assets_dispose、budgets_list、budgets_upsert_lines、budgets_variance、einvoicing_validate、einvoicing_issue、einvoicing_status、einvoicing_list、einvoicing_fiscalise、einvoicing_fiscalisation_status、einvoicing_clearance、tax_estimate、tax_parameters、tax_declare_parameter、tax_adjustments、tax_declare_adjustment、tax_losses、tax_record_computation、tax_computations、crm_search、crm_card、crm_segments、crm_board、crm_timeline、crm_upsert_card、crm_log_activity、crm_join_segment、crm_leave_segment、crm_open_deal、crm_move_deal、contracts_list、contracts_card、contracts_upsert、contracts_schedule、contracts_issue_due、contracts_deadlines、contracts_amend、contracts_from_template。模块也可以提供提示词,使用相同的前缀:tax_review_year、crm_morning_review。未安装的模块不会提供。如果项目尚未公开某个模块的架构,工具会说明需要更改哪个设置。

电子发票工具通过服务收到的传输方式发送,模型无法自行选择传输方式:可以是 EKWO_EINVOICE_DIRECTORY 指定的文件夹,也可以是宿主通过 buildServer() 传入的 einvoiceTransport。网络凭据不会传递给任何工具。请参阅 modules/einvoicing。

对于其国家/地区包声明了相关制度的公司,税务监管工具会根据服务通过 EKWO_FISCAL_SYSTEM 接入的开票系统,为每笔已过账销售串联记录;模型无法自行指定系统。

资源。 ekwo://companies/{id}/chart 是完整的会计科目表;ekwo://companies/{id}/taxes 包含所有税项,以及每项税务对应的总账科目和申报栏次。

提示词。 close_month 会逐项检查月末清单——草稿、未匹配的银行流水、余额、增值税,以及仍未结清的事项。prepare_vat_return 会提取申报栏次,并在提交任何申报前将其与总账核对。

审核或自动驾驶

与编码 Agent 的权限类似:设置中的默认模式、单次会话的标志,以及禁止使用该标志的设置。数据库记录了所有相关路径。

设置,公司的 agent_posting(get_company、update_company_profile、ekwo company agent-posting、Ekwo Cloud 的 Settings 页面)review,默认值:post_document 只有在有人按原样批准草稿后才会将其入账 — 使用 ekwo doc approve <document> 或 Web 应用;否则会以 approval_required 拒绝,如果草稿发生更改,也会再次拒绝。autopilot:在该人员的权限范围内直接入账。review_only:需要审核,并且对每个会话都拒绝自动驾驶。
会话,由启动服务的人选择--autopilot(或 EKWO_AGENT_POSTING=autopilot):只要公司允许,就无需批准而入账;这与 Claude Code 的 --dangerously-skip-permissions 对单次会话的作用相同;在 review_only 公司中,会明确以 autopilot_forbidden 拒绝。--review:即使公司处于自动驾驶模式,也需要批准。未指定:遵循各公司的设置。
机器密钥,签发时一次性选择create_api_key 的 posting_mode(ekwo key create --autopilot):review 为默认值,遵循公司的设置;autopilot 无需批准即可入账 — 仅向持有 company.write 的人员签发;在 review_only 公司中绝不签发,使用时也会被拒绝。使用密钥发出的请求会忽略 X-Ekwo-Agent,且之后无法提升密钥权限:需要另行签发一个密钥。list_api_keys 会显示模式。

服务会将其开启的每笔事务都标记为 Agent 的事务 — 直接连接时使用 ekwo.agent,通过 PostgREST 时使用 X-Ekwo-Agent,携带会话所选模式;并以签发时的模式将机器密钥视为 Agent。HTTP 传输的宿主会将该人员的选择作为连接的 agent 传递。Agent 的每笔入账都会在审计跟踪中记录为 document_posted_by_agent,并包含模式、设置、会话和密钥。Agent 不能批准,也可以让设置更严格,但不能放宽。服务会在启动时、status 中以及 post_document 的说明中告知其会话采用何种入账方式。自动驾驶是人员为自己的会话所作的选择,绝不是 Agent 的选择。参见决策 0089。

Agent 首先读取的内容

握手说明是一个包含五个步骤的首次会话:先调用 list_companies,再调用 get_company 获取财年和锁定日期,然后调用 list_accounts 并读取税务资源,以获取行项目中提及的代码;接着调用 search_contacts 和 create_document,用户同意后再调用 post_document。说明中还介绍了如何读取 vat_return、如何更正已过账的单据或分录(cancel_document、reverse_entry),以及拒绝请求时会附带下一步操作。每个工具的说明都会指出接下来应调用哪个工具。docs/agents.md 面向配置 Agent 的人员,介绍相同的会话流程,并附有命令行说明。

对于尚未向 Ekwo 注册的安装,说明还会多出一行:邀请 Agent 在合适的停顿时机向用户转达一次,说明注册的好处以及注册命令。status 工具会在 registration 字段中提供这条信息。注册是可选的,不会改变此服务的任何行为;在服务环境中设置 EKWO_NO_REGISTER_INVITE=1 即可隐藏这条信息,托管服务则绝不会添加这条信息。

说明中还会附带一次免费 Ekwo Cloud 账户的邀请,供 Agent 在完成首项任务后转达给尚未拥有账户的用户:同一套账簿上的 Web 应用、每晚备份所有关联公司的数据,以及通过上方的 URL 使用连接器,而无需在文件中保存密钥和密码。这条信息不会出现在任何工具结果中,也不会成为任何操作的前提;服务不会向 Ekwo 发送任何信息来提供此邀请。在服务环境中设置 EKWO_NO_CLOUD_OFFER=1 即可隐藏此邀请,设置 CI 也会隐藏;托管服务则绝不会添加此邀请。

约定

  • 金额使用十进制字符串。 "1210.00",绝不使用浮点数。传入和返回的金额都采用这种格式,因为 numeric 是精确的,而浮点数不是。
  • 日期采用 ISO 格式: 2026-06-15。标识符为 uuid。
  • 总额由数据库计算。 create_document 返回的草稿包含架构计算出的总额,而非调用方提供的总额。
  • 拒绝结果原样返回。 period_locked:、entry_unbalanced:、document_total_mismatch: 等错误会连同数据库抛出的消息一起返回,并附上一句说明其含义。这些是需要处理的答复,而不是可以绕过的障碍。
  • 产品会填充行项目,但不会限制行项目。 行项目指定 product_code 时,会采用目录中的文本、说明、单位、价格、科目和税务信息;行项目自身携带的任何内容都会优先。目录变更不会影响已过账的内容;被行项目引用的产品会通过设置 active: false 停用,而不会删除。
  • 缺少税务信息就是缺少税务信息。 未指定税务的行项目会记入不对应 VAT 栏目的基数,这与 0 % 并不相同。缺少科目则有所不同:这只能表示“解析科目”,因为没有科目的产品行项目会被检查约束拒绝。因此,行项目可以省略 account_code,由数据库填入——先采用公司默认科目,再采用国家模型。

手动测试

自动化测试会针对编译为 WebAssembly 的 Postgres 真实架构运行每个工具 (tests/mcp/),包括拒绝操作。若还想测试 PostgREST 和 Supabase Auth,请在一个可以随时丢弃的项目中安装 (npx -y ekwo-os@latest init),使用上方配置块让客户端连接该项目,然后尝试首次会话:

  1. “列出我的公司。” 显示你创建的公司,其中 your_role: owner。
  2. “创建一位客户,然后按标准费率为他们开具 1 000 的咨询服务发票。” 依次调用 create_contact 和 create_document;回答中的合计金额由数据库计算。
  3. “过账。” 调用 post_document,它会使用销售日记账的下一个编号。
  4. “他们在 10 日支付了 500。” 调用 record_payment;发票将变为部分付款状态。
  5. “给我看看本季度的试算平衡表和增值税。” 调用 trial_balance 和 vat_return。
  6. “锁定 6 月。” 调用 lock_period;此后,日期在 6 月的任何操作都会因 period_locked: 而被拒绝。

从国家配置包安装的公司已将银行和现金日记账关联到相应账户,因此无需其他设置即可使用 record_payment;create_bank_account 用于登记实际账户。

许可证

AGPL-3.0-only © Ekwo AI。

评论

支持 Markdown

第一次接触 MCP?

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

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