关于 Ekwo OS — open source accounting: ledger, invoices and VAT on your own Supabase or Postgres
Ekwo OS 的 MCP 服务让 AI Agent 在用户自己的 Postgres 或 Supabase 安装中处理会计记录。它使用用户权限操作,由数据库策略控制访问和过账,而非使用高权限服务密钥。
主要功能
- 01读取分类账及会计记录
- 02创建并过账发票
- 03匹配付款
- 04准备增值税申报
- 05遵循用户和公司访问策略
- 06支持托管 HTTP 与本地 stdio 模式
适用场景
- 01查看公司分类账分录
- 02准备并过账发票
- 03将付款与记录匹配
- 04准备增值税申报
MCP 相关
该服务通过本地 stdio 或 Streamable HTTP 向 MCP 客户端提供 Ekwo OS 会计操作。它支持本地安装和托管端点,并在数据库策略约束下使用用户访问权限或 Ekwo OS API 密钥。
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://mcp.ekwo.ai/mcpclaude mcp add --transport http ai-ekwo https://mcp.ekwo.ai/mcp{"mcpServers":{"ai-ekwo":{"type":"http","url":"https://mcp.ekwo.ai/mcp"}}}在 Cursor 中打开{"servers":{"ai-ekwo":{"type":"http","url":"https://mcp.ekwo.ai/mcp"}}}在 VS Code 中打开{"mcpServers":{"ai-ekwo":{"type":"http","url":"https://mcp.ekwo.ai/mcp"}}}{"mcpServers":{"ai-ekwo":{"serverUrl":"https://mcp.ekwo.ai/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
详细介绍
@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_URL | https://<ref>.supabase.co |
SUPABASE_ANON_KEY | anon(可发布)密钥。不接受 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),使用上方配置块让客户端连接该项目,然后尝试首次会话:
- “列出我的公司。” 显示你创建的公司,其中
your_role: owner。 - “创建一位客户,然后按标准费率为他们开具 1 000 的咨询服务发票。” 依次调用
create_contact和create_document;回答中的合计金额由数据库计算。 - “过账。” 调用
post_document,它会使用销售日记账的下一个编号。 - “他们在 10 日支付了 500。” 调用
record_payment;发票将变为部分付款状态。 - “给我看看本季度的试算平衡表和增值税。”
调用
trial_balance和vat_return。 - “锁定 6 月。” 调用
lock_period;此后,日期在 6 月的任何操作都会因period_locked:而被拒绝。
从国家配置包安装的公司已将银行和现金日记账关联到相应账户,因此无需其他设置即可使用
record_payment;create_bank_account 用于登记实际账户。
许可证
AGPL-3.0-only © Ekwo AI。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。