内容
# paperless-tax-mcp
一个 **非官方** 的MCP服务器和CLI,用于 [paperless.tax](https://www.paperless.tax),一个以色列的记账/费用平台。
> ⚠️ 不隶属于、不支持、不背书Paperless。本项目与应用的私有后端通信,不使用公开的开发者API,可能会在无通知的情况下中断。<br>请仅对自己的账户使用。
本项目的价值在于 [`docs/api-surface.md`](docs/api-surface.md) 和代码本身——没有公开的API文档,因此本项目是重点。<br>
## 身份验证
使用网页应用登录后持有的 **session JWT**,作为 `Authorization: Bearer <jwt>`。<br>
UI的API/webhooks模态窗口中的自助服务API密钥 **不是** 这些端点的凭证——它在所有方案下都返回401,并且购买API插件不会改变这一点。<br>不要购买插件期望它有所帮助。<br>
好消息是,与“session”令牌的预期相反:它的 `exp` 约为 **十个月**,因此一次交互式登录涵盖了大部分年份的计划工作。<br>登录是无密码的(电子邮件→输入代码),因此新令牌需要浏览器;之后可以从浏览器配置文件中提取。<br> [`docs/api-surface.md`](docs/api-surface.md#authentication--resolved) 同时包含这两项。<br>
## 作为MCP服务器使用
使用任何MCP客户端注册——Claude Code、Claude Desktop或网关。无需安装步骤:
```json
{
"mcpServers": {
"paperless-tax": {
"command": "npx",
"args": ["-y", "paperless-tax-mcp"],
"env": { "PAPERLESS_TOKEN": "..." }
}
}
}
```
Claude Code,一行:
```bash
claude mcp add paperless-tax --env PAPERLESS_TOKEN=... -- npx -y paperless-tax-mcp
```
## 作为CLI使用
相同的客户端,用于导出和查看API。安装它一次,以便 `paperless-tax` 二进制文件在您的PATH上:
```bash
npm install -g paperless-tax-mcp
export PAPERLESS_TOKEN=...
paperless-tax whoami # 验证令牌,打印账户ID
paperless-tax probe # 访问每个读取端点,报告答案
paperless-tax list --type 1 # 仅费用
paperless-tax list --from 2025-01 --to 2025-12
paperless-tax export --out export/ # 文件和元数据边车
paperless-tax raw POST documents/get/downloadurl --json '{"sDocID":"..."}'
```
无需安装即可运行, `--package` 是 **必需** 的:
```bash
npx --package paperless-tax-mcp paperless-tax export --out export/
```
普通的 `npx paperless-tax …` 将查找名为 `paperless-tax` 的包,这不是这个包。<br>而 `npx paperless-tax-mcp paperless-tax …` 更糟糕:由于包中有两个二进制文件,npx运行与包名匹配的二进制文件——MCP服务器——将 `paperless-tax` 视为参数。<br>它等待stdio,读取EOF,并退出0,假装成功运行并导出无内容。<br>
`export` 在 `export/expenses/{YYYY}/{YYYY-MM}/` 下写入 `{docid}.pdf` 和 `{docid}.json` 边车,带有 `manifest.jsonl` 索引。<br>它是可恢复的——已经在磁盘上的文档会被跳过——并且清单每次运行都会被重写,因此它描述了整个导出,而不是仅限于该次运行获取的内容。<br>
`--from`/`--to` 接受 `YYYY-MM-DD`、`YYYY-MM` 或API的原生 `YYMM`。省略它们以获取所有内容:默认范围是应用自己的无边界 `1001..2912`。<br>
### 作为库使用
```ts
import { PaperlessClient } from "paperless-tax-mcp/client";
import { Exporter } from "paperless-tax-mcp/export";
const client = new PaperlessClient({ token });
const docs = await client.byDate(); // 整个历史,一次调用
const pdfUrl = await client.downloadUrl(docs[0].id);
```
### 配置
| 变量 | 必需 | 含义 |
|---|---|---|
| `PAPERLESS_TOKEN` | 是 | session JWT — 见上文 |
| `PAPERLESS_USER_ID` | 否 | 10字符账户ID;`whoami` 会发现它 |
| `PAPERLESS_BASE_URL` | 否 | 默认 `https://api.paperless.tax/` |
### 从源码构建
```bash
npm install && npm run build && npm test
```
## 工具
| 工具 | 端点 | 置信度 |
|---|---|---|
| `whoami` | `GET users/get/params` | 已确认有效 |
| `pending_documents` | `GET documents/get/pending/{uid}` | 已确认有效 |
| `list_documents` | `POST documents/get/bydate` | 已确认有效 |
| `get_document` | `GET documents/get/document/{id}` | 已确认有效 |
| `get_download_url` | `POST documents/get/downloadurl` | 已确认有效 |
| `raw_request` | 任意 | 映射新表面的逃生门 |
## 四个常见问题
所有问题都在 `docs/api-surface.md` 中有详细说明,并且它们都需要花费大量时间来查找:
1. **控制器前缀不是可选的。** `POST /bydate` 是 404;路由是 `POST documents/get/bydate`。对于 `downloadurl`、`searchdp`、`document/{id}` 也是如此。<br>
2. **401 不意味着路由存在。** 身份验证在路由之前运行,因此所有未经身份验证的路径都返回 401 — 包括无意义的路径。这就是之前错误的、不正确的端点映射版本。<br>永远不要仅凭 401 推断路由是否存在。<br>
3. **`bydate` 使用 `YYMM` 时间字符串,而不是 ISO 日期。** `sStart: "2506"` 是 2025 年 6 月。<br>如果您给出日期,您将获得更窄的结果集,而不是错误。<br>
4. **204 不是成功。** 如果完全不发送凭证,您也会收到相同的 204。<br>请用故意无效的凭证测试每个身份验证方案。<br>
还值得注意的是:`documents/get/bydate` 返回整个账户历史记录,仅需一次调用,其记录与每个文档的详细端点返回的记录相同——因此循环遍历每个文档是纯粹的浪费。<br>并且 `export/download` 使用 `iExportType: 8` (备份)返回 503 `NotImplementedException`;该路由上没有整个账户备份。<br>
## 贡献
对 `docs/api-surface.md` 的修正是最有价值的贡献——特别是将一行从 *推断* 移动到 *确认*。<br>请标记您验证的内容和您假设的内容,并且永远不要在问题或PR中包含账户标识符、令牌或导入地址。<br>
## 许可证
MIT。