mcpField
H
hilan-mcp

hilan-mcp

本地服务
github.com/udah1金融数据612 周前更新

关于 hilan-mcp

hilan-mcp 将 Hilan 的工资单和 Form 106 税务文件提供给 AI 助手。它通过无头 Chromium 访问不同租户的账户,并将同步数据存入本地加密 SQLite,供查询和薪资趋势分析。

主要功能

  1. 01同步结构化工资单数据和 PDF
  2. 02下载年度 Form 106 PDF
  3. 03适配各租户的登录字段
  4. 04将数据存储在本地加密 SQLite
  5. 05查询同步记录并计算薪资趋势

适用场景

  1. 01获取近期工资单以供查看
  2. 02下载某年度的 Form 106
  3. 03查询某月税前或税后收入
  4. 04分析多年薪资变化

MCP 相关

作为 stdio MCP 服务运行,提供租户管理、工资单与 Form 106 同步、本地查询及薪资趋势工具。它使用 Playwright 登录 Hilan 并访问其内部端点。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"udah1-hilan": {
"command": "npx",
"args": [
"-y",
"hilan-mcp"
],
"env": {
"COMPANY_URL": "<COMPANY_URL>",
"COMPANY_TENANT": "<COMPANY_TENANT>",
"COMPANY_CODE": "<COMPANY_CODE>",
"HILAN_DB_KEY": "<HILAN_DB_KEY>",
"NODE_EXTRA_CA_CERTS": "<NODE_EXTRA_CA_CERTS>"
}
}
}
}
启动命令npx -y hilan-mcp
需要配置的环境变量
COMPANY_URLDefault tenant as a full URL, e.g. "https://amdocs.net.hilan.co.il" (optional if you always pass a `tenant` argument to tools instead). Takes priority over COMPANY_TENANT/COMPANY_CODE.
COMPANY_TENANTDefault tenant subdomain, e.g. "amdocs" (optional if COMPANY_URL is set or a `tenant` argument is always passed to tools).
COMPANY_CODEDefault tenant as a numeric org code, e.g. "5227" (optional, lowest priority of the three tenant env vars).
HILAN_DB_KEY密钥Database encryption key (only needed if you skip `npx hilan-mcp setup-key`, which stores it in your OS credential store instead).
NODE_EXTRA_CA_CERTSPath to a CA bundle, only needed on a network with a TLS-intercepting corporate proxy (e.g. "self-signed certificate in certificate chain" errors).

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmhilan-mcp0.3.2

工具

11

收录的工具列表 · 更新于 2 周前

参数类型必填说明
versionstring是要忽略的 _updateNotice 中的版本字符串,例如 "0.2.0"

详细介绍

hilan-mcp

适用于 Hilan(Hilanet / חילן, חילנט)的 MCP 服务 — 将工资单和 106 表导入任何 AI 助手,支持任意 Hilan 租户。

npm version npm downloads license node


Hilan 没有官方 API。hilan-mcp 通过 Playwright 驱动真实的(无头)Chromium 浏览器登录,随后复用同一经过身份验证的会话来调用 Hilan 的内部端点并下载 PDF — 无需脆弱的手动 Cookie 重放,也不会在任何地方以明文形式存储密钥。

目录

功能

  • 📄 工资单 — 结构化的 Bruto/Neto/薪资组成数据,以及 PDF,涵盖租户历史记录中的任意月份。
  • 🧾 106 表 — 按年份提供年度税务汇总 PDF。
  • 🔐 本地加密存储 — 使用 SQLCipher 加密的 SQLite,密钥绝不以明文写入磁盘;支持操作系统原生凭据存储(Keychain/DPAPI/Secret Service)。
  • 🏢 任意 Hilan 租户 — 登录表单字段会按租户自动检测,而不是为某个雇主硬编码。
  • 💬 直接回答,而非原始 JSON — query 等工具可直接根据本地数据回答“我 6 月赚了多少钱?”,无需网络往返。
  • 🔄 自动更新提醒 — 服务会检查是否有更新版本,并让你的 AI Agent 提供更新选项,无需自带界面。

工作原理

此服务通过 Playwright 驱动真实的(无头)Chromium 浏览器登录,随后复用同一经过身份验证的浏览器上下文中的 HTTP 客户端(context.request),调用 Hilan 内部的 .asmx JSON 端点并下载 PDF — 因此它会自动继承真实页面加载所设置的 Cookie/标头,而无需脆弱的手动 Cookie 重放。

不同 Hilan 租户的登录表单字段各不相同(有些有 2 个字段,有些有 3 个),因此首次录入凭据时,会针对每个租户重新检查登录表单,而不是为某家公司硬编码。

设置

0. 如果你使用 npm 12 或更高版本

npm 12 会阻止安装依赖项时运行脚本,除非你明确允许;本包的一个依赖项(better-sqlite3-multiple-ciphers,即加密版 SQLite 引擎)需要运行安装脚本来编译原生绑定。若不允许,设置看似会成功,但之后所有访问数据库的工具都会失败。只需允许一次,此后所有 npx 和全局安装都适用:

npm config set allow-scripts=better-sqlite3-multiple-ciphers --location=user

如果不想全局设置,也可以针对每次安装单独允许:

npm install -g --allow-scripts=better-sqlite3-multiple-ciphers hilan-mcp

npm 11 及更早版本无需执行此操作 — 默认仍会运行安装脚本。使用 npm --version 检查版本。

1. 注册租户并输入凭据

请亲自在自己的终端中运行此命令,切勿将真实凭据粘贴到 AI 聊天中。它会安装 Playwright 所需的 Chromium 浏览器(仅需安装一次),启动无头浏览器,检测租户实际使用的登录字段,并逐一提示你输入(密码会隐藏)。无需在本地克隆项目或运行 npm install——npx 会即时获取软件包:

npx hilan-mcp setup --tenant amdocs        # tenant subdomain
# or
npx hilan-mcp setup --tenant 5227          # numeric org code, resolved automatically

如果你已通过其他方式安装了软件包,也可以使用等效的底层命令 npx hilan-mcp ingest-creds --tenant <...>——setup 还会先处理一次性 Chromium 安装。

首次运行时,系统会要求你设置本地数据库的加密密钥(至少 6 个字符)——该密钥不会以明文形式写入磁盘。

为了让 MCP 服务能够自行打开数据库(无需每次都有人在场响应提示),它会按以下顺序查找密钥:

  1. 操作系统凭据存储(推荐)——请亲自在自己的终端中运行一次 npx hilan-mcp setup-key。系统会要求你输入密钥(或按 Enter 生成强随机密钥),并将其存储在操作系统的原生安全存储中:macOS 钥匙串(已验证——与存储 Wi-Fi 和浏览器密码的文件相同,无提示、无对话框)、Windows(DPAPI,与 Windows 用户帐户关联)或 Linux(Secret Service / secret-tool,需要 GNOME Keyring 或 KWallet 等密钥环守护进程)。密钥不会写入任何配置文件。
  2. HILAN_DB_KEY 环境变量——在服务的 env 块中设置(参见第 2 步)。其信任模型与在 mcp.json 中为 MCP 服务配置的其他 API 密钥或机密相同(存储在本地文件中,不会提交到 git)。
  3. 桌面通知(最后手段)——服务会回退到通过系统通知请求密钥(再不行则回退到普通终端提示),但这要求有人在每次需要访问数据库的工具调用发出后约 30 秒内作出响应,因此不建议日常使用。
2. 将服务添加到 MCP 客户端配置中

不带参数运行软件包会启动 MCP 服务本身(stdio 传输)——MCP 客户端配置实际调用的就是它:

{
  "mcpServers": {
    "hilan": {
      "command": "npx",
      "args": ["-y", "hilan-mcp"]
    }
  }
}
单雇主配置——无需在每次工具调用时传入 tenant

如果你只会将其用于一个雇主,可以在服务的 env 块中设置默认租户。以下变量中,只有最先设置的一个会生效,优先顺序为 COMPANY_URL → COMPANY_TENANT → COMPANY_CODE:

{
  "mcpServers": {
    "hilan": {
      "command": "npx",
      "args": ["-y", "hilan-mcp"],
      "env": {
        "COMPANY_TENANT": "amdocs",
        "HILAN_DB_KEY": "the-encryption-key-you-set-during-ingest-creds",
        "NODE_EXTRA_CA_CERTS": "/path/to/your-corporate-ca-bundle.pem"
      }
    }
  }
}

仅当你未运行 npx hilan-mcp setup-key(参见第 1 步)时,才需要设置 HILAN_DB_KEY——如果两者都已设置,则优先使用操作系统凭据存储。只有在使用 TLS 拦截型企业代理的网络中,才需要设置 NODE_EXTRA_CA_CERTS(参见可靠性说明:真实端到端运行中的经验);其他情况下请省略。

环境变量示例备注
COMPANY_URLhttps://amdocs.net.hilan.co.il优先级最高。
COMPANY_TENANTamdocs裸子域名。仅当未设置 COMPANY_URL 时使用。
COMPANY_CODE5227数字组织代码。仅当以上两个变量均未设置时使用——需要额外进行一次查询。

同样的回退规则也适用于 npx hilan-mcp ingest-creds——如果已设置上述任一环境变量,则 --tenant 为可选项。显式传入的 tenant 参数(或 --tenant 标志)始终会覆盖环境变量。

从本地克隆运行,而不是使用已发布的软件包

在该克隆目录中运行 npm install && npm run build 后,使用 "command": "node", "args": ["/absolute/path/to/hilan-mcp/dist/cli/index.js"],替代上文中的 npx 形式。

### 3. 使用方法

向助手提出类似“同步我最近 3 张来自 Hilan 的工资单”“下载我 2025 年的 Form 106”或“我在 2026 年 6 月的税后/税前收入是多少?”的问题(至少同步过该月一次后,query 工具会通过本地数据库即时回答,无需网络往返)——请参阅下方的完整工具列表。

供代用户完成设置的 AI Agent(例如 Claude)

如果用户要求你为他们设置 hilan-mcp:

  1. 不得通过 shell 工具自行运行 ingest-creds/setup/setup-key——这些命令会交互式提示输入密码和/或加密密钥,而 shell 工具的记录可能会捕获用户输入的内容。请告知用户打开自己的终端并自行运行 npx hilan-mcp setup --tenant <their-org-code-or-subdomain>,然后(建议)运行 npx hilan-mcp setup-key。 先检查他们的 npm --version:如果使用 npm 12 或更高版本,他们还需要完成步骤 0,否则之后数据库将无法打开,而且问题看起来不像是由安装引起的。
  2. 完成上述步骤后,你可以安全地将 MCP 服务条目添加到客户端的配置文件中(上方的 JSON 块)——只要用户使用了 setup-key(操作系统凭据存储),而不是 HILAN_DB_KEY 环境变量回退方案,这部分就不包含任何机密信息。
  3. 添加配置后,用户(或其客户端)需要重新加载/重启 MCP 连接,才能看到新工具。
  4. 除非用户明确要求使用原始 .asmx/PDF 探索工具,否则不要启用 HILAN_ENABLE_DEBUG_TOOLS——这是有意保留的应急出口(参阅安全模型),正常使用不需要它。
  5. 如果工具响应包含 _updateNotice 字段,请告知用户并询问他们是否要更新;如果他们拒绝,请使用该版本调用 dismissUpdateNotice(参阅 MCP 工具)。

MCP 工具

工具概要
listTenants列出已配置的租户——不含机密信息。
syncPayslips获取最近 N 个月的结构化工资单数据和 PDF。
resyncPayslipMonth重新获取指定月份,并覆盖已存储的内容。
syncForm106下载指定年份的 Form 106 PDF。
downloadCombinedPayslipsPdf下载一份涵盖整个月份范围的 PDF。
getSalaryTrends年均值、同比百分比、复合年增长率和显著加薪情况——在本地计算。
listTables / describeTable查看可查询的本地架构。
query对本地工资单/Form106 数据运行只读 SQL。
getPersonalDetails实时查询个人信息(不持久化)。
dismissUpdateNotice隐藏特定版本的更新通知。
debugCallAsmx / debugDownloadPdf探索原始 API——默认关闭。
完整工具参考(参数、行为、说明)
listTenants()

已配置的租户(子域名、功能、此前是否成功登录)——不含机密信息。

syncPayslips(tenant?, monthsBack?, skipPdf?)

登录(如果已保存的会话仍有效,则重用该会话),获取最近 N 个月(默认为 3 个月)的结构化 Bruto/Neto/工资组成数据,并下载每张工资单的 PDF。设置 skipPdf: true 可更快地仅同步数字(例如回答“我今年赚了多少”)。如果已设置 COMPANY_URL/COMPANY_TENANT/COMPANY_CODE,则 tenant 为可选参数。实际可查询的历史范围受租户自身的存档长度限制——无需猜测起始日期。

resyncPayslipMonth(tenant?, period, skipPdf?)

重新获取指定的一个月份(例如 "10_2019" 或 "10/2019"),并覆盖已存储的内容。遇到损坏/截断的 PDF 需要重试,或临时回答“我在 X 月赚了多少”时,请使用此工具,而不是针对整段历史重新运行 syncPayslips。

syncForm106(tenant?, year?)

登录并下载指定年份(或租户默认年份)的 Form 106 PDF。tenant 的回退方式与上文相同。

#### `downloadCombinedPayslipsPdf(tenant?, fromMonth, toMonth, destDir?)` 下载**涵盖整个月份范围的一个 PDF**(例如,2015–2024 年的所有月份),而不是每个月一个文件。如果范围会超过服务器的 URL 长度限制,则会自动拆分成多个文件(参见[可靠性说明(基于一次真实端到端运行的经验)](#reliability-notes-learned-from-a-real-end-to-end-run))——每个分段的实用上限大约是 10–15 年。
getSalaryTrends(tenant?, fromYear?, toYear?)

仅根据本地同步的工资单计算薪资增长趋势——不会实时登录,也不会发起网络请求。返回每年的 Bruto/Neto 平均值、相邻年份之间的同比变化百分比、第一个和最后一个完整(日历年有 12 个月)年份之间的 CAGR、总体增长(首次与最后一次同步的月份之间),以及“显著增长”(Bruto 同比变化 ≥10%)。可选的 fromYear/toYear 用于限定要考虑的日历年。建议优先使用此工具,而不是用 query 手动汇总——按纯文本 period 分组或排序会导致跨年时间顺序错误(例如,"01_2011" 会排在 "02_2010" 前面);此工具会在内部按实际日历月份排序。

listTables() / describeTable(table)

列出可查询的表(仅限 payslips、form106)及其列和索引。

query(sql)

针对 payslips/form106 执行仅限 SELECT 的 SQL。credentials、sessions 和 tenants 会被严格禁止访问——参见安全模型。适合快速查询,例如“我在 2026 年 6 月赚了多少净薪资/毛薪资”,完全无需访问网络。

getPersonalDetails(tenant?)

登录并返回个人信息(姓名、国家身份证号、出生日期、地址、电话、电子邮箱、入职日期、工作类型)。仅实时查询——不会保存到本地数据库。

dismissUpdateNotice(version)

如果用户拒绝了你向其提供的更新,请调用此工具(见下文),这样就不会再次提及该确切版本。

debugCallAsmx(tenant?, servicePath, body?) / debugDownloadPdf(tenant?, relativeUrl, fileName)

仅用于调试/探索,默认禁用——在已登录的会话中,将任意 .asmx 端点原样转发,或下载任意相对 PDF URL。必须在服务的 env 块中设置 HILAN_ENABLE_DEBUG_TOOLS=1;否则不会注册这些工具。文件名会经过清理(禁止路径遍历),URL 也会被限制在租户自己的源站内(防止 SSRF)。

更新通知:此服务没有自己的 UI,因此更新检查会借助 Agent 接下来调用的工具进行。每天最多一次,成功的工具响应可能会包含额外的 _updateNotice 字段,其中会显示类似 "A new hilan-mcp version is available: 0.1.0 -> 0.2.0..." 的消息——如果你是正在阅读此内容的 AI Agent,请告知用户并询问是否要更新;如果用户拒绝,请调用 dismissUpdateNotice 并传入该版本,这样就不会再次提示(后续仍会通知有更新的版本)。检查本身会向 npm 注册表发起请求,超时时间为 3s;如果无法连接(例如处于离线状态或使用企业代理),则会静默跳过——绝不会导致工具调用失败。

并发说明:针对同一租户的每次工具调用都会自动排队,并在内部依次运行(参见 TenantService.runExclusive)——Hilan 的网站(和/或到该网站的网络连接)无法很好地处理来自同一会话的并发请求,否则所有请求都会超时。你无需自行串行化调用;不同租户的请求仍会完全并行运行。

范围(v1)

  • ✅ 工资单(列表、结构化 Bruto/Neto/明细、PDF)
  • ✅ Form 106(PDF,按年)
  • ⛔ 通用文件档案、Form 101——尚未构建(v1.1+)
  • ⛔ 一次性验证码 / 2FA 登录——需要此类验证的租户会返回明确的“不支持”错误,而不会一直挂起

内部 API 响应与参考租户(Amdocs)所见的结构化格式不匹配的租户会被标记为 pdf_only:工资单仍可同步,也仍会保存 PDF,只是不解析 Bruto/Neto 数值。

可靠性说明(来自一次真实端到端运行的经验)

企业 TLS 拦截代理、PDF URL 特性、截断重试、URL 长度限制和 OTP 误报
  • 企业 TLS 拦截代理(例如 Amdocs 的网络)会导致 Playwright 的 Node 端 context.request 在调用内部 API/PDF 时出现 self-signed certificate in certificate chain 错误。遇到这种情况时,请在服务的 env 块中将 NODE_EXTRA_CA_CERTS 设置为贵组织导出的 CA 证书包。
  • 直接下载 PDF 的 URL 是相对于 /Hilannetv2 的,而不是相对于域名根目录——JSON API 返回的 URL(例如 PersonalFile/PdfPaySlip.aspx/...)实际位于 <tenant>/Hilannetv2/PersonalFile/PdfPaySlip.aspx/...。已通过实时浏览器网络捕获确认。
  • PDF 下载通过页面内的 fetch()(同源、原始 URL)进行,而不是使用 context.request;后者会静默地将查询字符串中的字面 / 重新编码为 %2F,导致某些端点返回 404。
  • 同一个企业代理偶尔会在传输过程中截断 PDF 响应(观察到可疑的整 32768 字节截断),但 fetch 本身不会报错。downloadPdf 会检查整个缓冲区是否包含标准的 %%EOF PDF 结尾标记(而不只是检查末尾——一些正常的 Hilan PDF 在有效的 %%EOF 之后还会有数十或数百 KB 的尾随空字节填充),最多重试 3 次后才放弃。
  • 合并多月 PDF(PaySlipApiapi.asmx/GetMultiplePaySlipData,一个文件覆盖一段日期范围,而非每月一个文件)会在 URL 超过约 2048 个字符后触发硬性HTTP 404——这是 IIS 默认的 requestFiltering maxQueryString 限制,并非 Hilan 特有的限制(每增加一个月,URL 会增长约 11 个字符)。已验证 120 个月(10 年,URL 约 1.4KB)可正常运行;已验证 194 个月(约 16 年,URL 2.2KB)会失败——因此,实际情况下,每个合并 PDF 的请求上限约为 15 年。逐月同步(syncPayslips)不受影响,因为它不会构造一个超长 URL。
  • 租户的常规登录页面可能会无条件显示“使用一次性验证码登录”按钮或链接,即使普通的用户名+密码登录完全受支持且运行正常——不要仅凭这段文字就认定必须使用 OTP。只有登录失败后确实出现新的 OTP 输入字段(或跳转到 OTP 专用路由),才表示必须使用 OTP。
## 安全模型
  • 整个 SQLite 数据库(在 macOS 上位于 ~/Library/Application Support/HilanMcp/hilan.db,其他系统则位于对应的 XDG/AppData 路径)通过 SQLCipher(better-sqlite3-multiple-ciphers)进行静态加密,密钥是你自行选择、绝不会写入磁盘的密码短语。PDF 文件存放在同级的 .../HilanMcp/pdfs/<tenant>/ 目录下,滚动日志文件存放在 .../HilanMcp/logs/ 目录下(已脱敏,见下文)。应用数据、PDF 和日志目录均以 0700 权限创建;数据库和 PDF 文件本身则以 0600 权限创建。
  • credentials(你的登录字段)和 sessions(已保存的浏览器 Cookie)是加密数据库中的普通表,但无法通过 query/listTables/describeTable 工具访问——这些工具的允许列表仅包含 payslips 和 form106,并通过完整的 SQL AST 解析进行验证(而非正则表达式),因此无法利用 JOIN、子查询和带引号的标识符绕过允许列表(见 src/utils/sqlValidation.ts 和 src/tests/sqlValidation.test.ts)。
  • Cookie 和身份验证标头会从日志文件以及工具调用返回的任何错误消息中脱敏,因此 Playwright 错误不会将你的会话泄露到聊天记录中(见 src/utils/redact.ts)。
  • 必须由你在自己的终端中直接运行凭据录入命令(ingest-creds),绝不能通过助手的 shell 工具运行,因为其记录可能会捕获你输入的内容。
  • debugCallAsmx 是一个有意提供的逃生通道:它允许已登录的会话使用任意请求正文调用任何 .asmx 端点,绕过上述精心筛选的工具。它是在开发期间为探索 API 而添加的,作用范围限于单个员工(使用相同的会话,并且权限与网站上已有权限相同)——无法访问其他员工的数据或其他租户的数据——但理论上它可能调用写入端点(Hilan 通常会通过审批流程限制写入,但尚未对此进行审计)。此功能默认关闭(HILAN_ENABLE_DEBUG_TOOLS);请像对待 query 的 SQL 逃生通道一样对待它——适合交给你信任其探索能力的 AI 助手使用,不适合暴露给不可信输入。

开发

克隆此仓库以修改代码本身(仅使用服务则无需克隆——请参阅上文的设置):

npm install
npm run typecheck
npm test                 # unit tests (SQL allowlist, path-traversal, redaction, update checks, ...)
npm run build            # compile TypeScript -> dist/
npm run start:mcp        # run the server directly from source (stdio transport)
npm run setup            # local equivalent of `npx hilan-mcp setup`
npm run ingest-creds     # register a tenant + credentials (interactive, run yourself)
npm run setup-key        # store the DB encryption key in your OS credential store (interactive, run yourself)

npm publish 只会发布 dist/、README.md 和 LICENSE(见 package.json 中的 files 字段),不会包含源代码、测试和本地研究资料。prepublishOnly 会先运行类型检查、测试和构建,因此无法发布构建失败的版本。已发布的 bin 条目(dist/cli/index.js)是 npx hilan-mcp 和 npx hilan-mcp <subcommand> 调用的入口。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

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

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