内容
<p align="right"><b>🇫🇷 法语</b> · <a href="README-EN.md">🇬🇧 英语</a></p>
<div align="center">
# mcp-pennylane
**从 Claude 驾驶您的 Pennylane 账户 — 发票、日记、银行、FEC**
<br/>
<img src="assets/banner.svg" alt="Claude → mcp-pennylane → Pennylane Company API v2" width="700"/>
<br/>
<br/>
[](https://crates.io/crates/mcp-pennylane)
[](https://crates.io/crates/mcp-pennylane)
[](LICENSE)
[](https://github.com/FGRibreau/mcp-pennylane/actions/workflows/ci.yml)
[](https://rust-lang.org)
[](https://modelcontextprotocol.io)
</div>
---
## 赞助商
<table>
<tr>
<td align="center" width="175">
<a href="https://france-nuage.fr/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=france-nuage&mtm_content=mcp-pennylane">
<img src="assets/sponsors/france-nuage.svg" height="60" alt="France-Nuage"/><br/>
<b>France-Nuage</b>
</a><br/>
<sub>法国主权云,用于托管您的会计导出和FEC存档。</sub>
</td>
<td align="center" width="175">
<a href="https://hook0.com/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=hook0&mtm_content=mcp-pennylane">
<img src="assets/sponsors/hook0.png" height="60" alt="Hook0"/><br/>
<b>Hook0</b>
</a><br/>
<sub>将Pennylane Webhooks作为签名事件分发到您的后台。</sub>
</td>
<td align="center" width="175">
<a href="https://getnatalia.com/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=natalia&mtm_content=mcp-pennylane">
<img src="assets/sponsors/natalia.svg" height="60" alt="Natalia"/><br/>
<b>Natalia</b>
</a><br/>
<sub>语音AI代理,响应供应商和客户发票查询。</sub>
</td>
<td align="center" width="175">
<a href="https://www.netir.fr/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=netir&mtm_content=mcp-pennylane">
<img src="assets/sponsors/netir.svg" height="60" alt="Netir"/><br/>
<b>Netir</b>
</a><br/>
<sub>招聘通过验证的法国会计和财务运营自由职业者。</sub>
</td>
</tr>
<tr>
<td align="center" width="233">
<a href="https://nobullshitconseil.com/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=nbc&mtm_content=mcp-pennylane">
<img src="assets/sponsors/nobullshitconseil.svg" height="60" alt="NoBullshitConseil"/><br/>
<b>NoBullshitConseil</b>
</a><br/>
<sub>财务运营和ERP咨询,无废话。 Pennylane集成专家。</sub>
</td>
<td align="center" width="233">
<a href="https://qualneo.fr/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=qualneo&mtm_content=mcp-pennylane">
<img src="assets/sponsors/qualneo.svg" height="60" alt="Qualneo"/><br/>
<b>Qualneo</b>
</a><br/>
<sub>Qualiopi LMS,适用于法国培训师,附带为Pennylane准备的发票导出。</sub>
</td>
<td align="center" width="233">
<a href="https://www.recapro.ai/?mtm_source=github&mtm_medium=sponsor&mtm_campaign=recapro&mtm_content=mcp-pennylane">
<img src="assets/sponsors/recapro.png" height="60" alt="Recapro"/><br/>
<b>Recapro</b>
</a><br/>
<sub>私人AI,用于转录您的会计会议并编写会议纪要。</sub>
</td>
</tr>
</table>
> **想成为赞助商吗?** [联系我们](mailto:rust@fgribreau.com)
---
## 什么是?
`mcp-pennylane` 将 Claude(或任何 MCP 主机)连接到 [Pennylane Company API v2](https://pennylane.readme.io)。大约 73 个基本操作直接暴露给主机,两个元工具(`pennylane_search_tools`,`pennylane_execute`) 覆盖了长尾 — 因此总共 163 个操作仍然可用,而不会使 MCP 工具预算超支。
从聊天中驾驶您的会计:列出和创建客户发票,匹配银行交易,查询总账,生成 FEC 导出给您的会计师,管理 GoCardless 和 SEPA 授权 — 所有这些都使用自然语言。
## 功能
- ✨ **所有 163 个 Pennylane 操作** — 73 个基本操作 + `pennylane_search_tools` + `pennylane_execute` 用于长尾
- 🔒 **自动只读模式检测** — 在启动时查询 `GET /me`,如果每个范围以 `:readonly` 结尾,则强制只读
- ⚡ **两种传输方式** — stdio 用于 Claude Desktop,HTTP 流式用于远程 (`/mcp` + `/health`)
- ⚙️ **通过 OpenAPI 进行代码生成** — `build.rs` 解析供应商规范,如果白名单发生变化则失败
- 🤖 **每周自动 PR** — GitHub Action 在每个星期一将上游与之分开,如果规范发生变化则打开 PR
- 🛡️ **红线标记令牌** — 在所有日志路径上 `Bearer abcd***wxyz`,会计主体从不记录在 INFO 中
- 💡 **结构化错误** — `UNAUTHORIZED`,`VALIDATION_FAILED`,`RATE_LIMITED`,… 带有截断的上游正文和可操作提示
- 📦 **唯一静态二进制文件** — `cargo install`,GitHub Releases(linux/macOS/windows × x86_64/aarch64),Homebrew Tap
## 快速入门
```bash
# 1. 安装
cargo install mcp-pennylane
# 2. 在设置 → 连接性 → 开发者中生成 Pennylane 令牌
# 推荐的作用域: “只读 - 检索数据”
export PENNYLANE_API_KEY="您的 Pennylane 令牌"
# 3. 连接到 Claude Desktop,然后重启 Claude
cat <<'EOF' >> ~/Library/Application\ Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"pennylane": {
"command": "/usr/local/bin/mcp-pennylane",
"env": { "PENNYLANE_API_KEY": "您的 Pennylane 令牌" }
}
}
}
EOF
```
就这样 — Claude 现在可以看到 `getMe`,`getCustomers`,`pennylane_search_tools` 和 70 多个其他工具。
> 💡 服务器在启动时查询 `GET /me`。如果您的令牌是只读的,它会自动激活只读模式(横幅显示 `mode=readonly (auto)`)。定义 `PENNYLANE_READONLY=true` 以忽略探测并确定性地强制只读(推荐在 CI 中)。
## 配置
### 环境变量
| 变量 | 默认值 | 角色 |
|---|---|---|
| `PENNYLANE_API_KEY` | *必填* | Bearer 令牌(设置 → 连接性 → 开发者) |
| `PENNYLANE_BASE_URL` | `https://app.pennylane.com` | 代理或可能区域 URL 的覆盖 |
| `PENNYLANE_READONLY` | *自动检测* | `true` / `false` 以绕过 `/me` 探测 |
| `PENNYLANE_ENV` | `production` | `production` / `sandbox` — 横幅和 `getMe` 中的视觉指示 |
| `PENNYLANE_API_2026` | `false` | 发送头部 `X-Use-2026-API-Changes: true`(预览阶段) |
| `MCP_PENNYLANE_TRANSPORT` | `stdio` | `stdio` 或 `http` |
| `RUST_LOG` | `info` | 标准 `tracing-subscriber` 过滤器 |
### CLI 标志
每个环境变量都有一个等效的标志 (`--token`, `--base-url`, `--readonly`, `--env`, `--api-2026`, `--transport`, `--host`, `--port`, `--log-level`)。运行 `mcp-pennylane --help` 以获取完整列表。
## 安装
| 渠道 | 命令 |
|---|---|
| crates.io | `cargo install mcp-pennylane` |
| Homebrew | `brew install fgribreau/tap/mcp-pennylane` |
| GitHub Releases | [下载存档](https://github.com/FGRibreau/mcp-pennylane/releases/latest)(linux/macOS/windows × x86_64/aarch64) |
## 用法
您可以从 Claude 控制的三个端到端工作流:
**1. 列出最近的未付发票。** *“给我看过去 30 天的未付客户发票。”* → Claude 调用 `getCustomerInvoices` 并使用过滤器 `[{"field":"status","operator":"eq","value":"unpaid"},{"field":"date","operator":"gteq","value":"2026-04-06"}]`,必要时遍历分页。
**2. 匹配银行交易。** *“查找本周未匹配的 1250 欧元交易并将其链接到正确的发票。”* → Claude 调用 `getTransactions`,然后调用 `pennylane_search_tools(query="match")` 以发现对账操作,然后调用 `pennylane_execute(tool_name="postCustomerInvoiceMatchedTransactions", params={"id": <invoice_id>, "transaction_id": <transaction_id>})`。
**3. 为 2026 年第一季度生成 FEC。** *“生成 2026 年 1 月至 3 月的 FEC 并在我准备好时通知我。”* → Claude 调用 `exportFec` 并使用 `{"start_date":"2026-01-01","end_date":"2026-03-31"}`,轮询 `getFecExport` 直到状态变为 `done`,然后发送下载 URL。
## 只读模式
`mcp-pennylane` 通过两步解决只读姿态:
1. **自动检测** (默认)- 当未设置 `PENNYLANE_READONLY` 时,服务器在启动时查询 `GET /me`,读取令牌的 `scopes` 表,仅当每个作用域以 `:readonly` 结尾时强制只读。横幅显示 `mode=readonly (auto)` 或 `mode=read+write (auto)`。
2. **显式覆盖** - `PENNYLANE_READONLY=true` (或 `false`)完全绕过探测。横幅:`mode=… (explicit)`。在 CI 中用于确定性启动很有用。
无论来源如何,当只读激活时,写入操作在记录时被过滤,并且 `pennylane_execute` 在任何 HTTP 调用到 Pennylane 之前返回结构化错误 `READONLY_MODE`。
```bash
# Defense-in-depth: 显式 + Pennylane 令牌范围只读
export PENNYLANE_API_KEY=… # 使用“只读”创建令牌
export PENNYLANE_READONLY=true # 显式服务器过滤
mcp-pennylane
```
Pennylane 令牌范围是 **设置 → 连接性 → 开发者** 中的单选按钮。 一层保护免受配置错误的服务器,另一层保护免受配置错误的令牌。
## 日志和机密
- 日志**仅输出到 stderr** - 绝不会输出到 stdout,否则会破坏 stdio 传输的 MCP 分帧。
- Pennylane Bearer 令牌**始终被删节** via `redact_bearer()` (`Bearer abcd***wxyz`),即使在 TRACE 级别也是如此。
- INFO / WARN / ERROR 级别**从不包含响应正文** - 会计数据是敏感的(GDPR,商业秘密)。
- TRACE 暴露完整的请求 URL 和响应正文。仅在本地调试时在沙盒账户上激活。
- 没有遥测,没有电话回家,没有选择加入的仪表盘。
## 流式 HTTP 传输
```bash
mcp-pennylane --transport http --host 127.0.0.1 --port 8000
# MCP 端点: http://127.0.0.1:8000/mcp
# 健康检查: http://127.0.0.1:8000/health
```
Pennylane 令牌保留在服务器端的 `PENNYLANE_API_KEY` 中 - 实例按进程是单租户的。 **客户端 MCP 和此服务器之间的身份验证故意缺失**。在本地绑定到 `127.0.0.1` 并在任何非本地公开(Cloudflare Access,Authelia,Caddy basic-auth 等)之前放置反向代理。开源独立服务器不应对外部意见进行排序。
## 沙盒
`PENNYLANE_ENV=sandbox` 是一个**仅视觉指示** - Pennylane 对沙盒和生产使用相同的基准 URL。仅在三个地方提供此值以避免经典的“哦豁,我修改了生产环境”:
1. stderr 上的启动横幅:`mcp-pennylane v0.1.0 — Pennylane Company API v2.0 — env=sandbox — mode=readonly (auto)`。
2. 增强的 `getMe` 响应: `_mcp_pennylane = { env, server_version, spec_version, readonly, readonly_source, api_2026 }`。
3. MCP 协议的 `serverInfo.instructions` 字段。
## 2026 年 API 变更
Pennylane 在 **2026 年 4 月 8 日** 在其 Company API 上部署了突破性变更。从 2026 年 1 月 14 日到 4 月 8 日,新行为通过 `X-Use-2026-API-Changes: true` 是可选项。设置 `PENNYLANE_API_2026=true` (或 `--api-2026`)以发送此标头。
| 阶段 | 何时 | 行为 |
|---|---|---|
| 预览 | 2026 年 1 月 14 日 → 2026 年 4 月 8 日 | 通过环境变量进行选择加入 |
| 切换 | 2026 年 4 月 8 日 | 新行为成为上游默认值。 **v1.0** 在那天标记,变量成为选择退出 / 旧版 |
| 清理 | 2026 年 7 月 1 日 | 旧行为在上游删除 - 变量成为无操作 |
## 工具目录
大约 73 个基本工具直接暴露:客户,供应商,客户 + 供应商发票,产品,报价,银行,日记,总账,试算平衡表,税务练习,分析类别,FEC 导出,附件,变更日志,GoCardless 和 SEPA 授权,`getMe`。所有 ~163 个操作仍然可以通过元工具访问。
工具名称与 Pennylane 的 `operationId` 相同(例如 `getCustomerInvoices`,`postLedgerEntries`),以便正确 grep 对官方 OpenAPI 规范进行 grep。精选列表位于 [const `ESSENTIALS` in `server/build.rs`](./server/build.rs)。
## 路线图
- 像 `mcp-pennylane-firm` 这样的 Firm Pennylane API 二进制文件
- 当 HTTP 传输的使用证明其合理性时,使用 Docker 镜像
## 开发
```bash
# 构建
cargo build --release
# 刷新供应商的 Pennylane OpenAPI 规范
cargo run -p refresh-openapi
cargo run -p refresh-openapi -- --diff # 干运行
cargo run -p refresh-openapi -- --check # 如果漂移则退出非零
# 套件测试(单元 + 不变)
cargo test --workspace
# 对 Pennylane 沙盒(只读)进行集成测试
PENNYLANE_API_KEY=… PENNYLANE_READONLY=true cargo test --workspace --features integration-tests
```
每周的 GitHub Action 在 UTC 06:00 运行 `cargo run -p refresh-openapi` 并且如果上游规范有变化则打开 PR。CI 在 PR 上检查所有基本操作是否仍然存在(`build.rs` 在重命名/删除的操作上恐慌);当绿色时合并。