关于 MCP FactorialHR
MCP FactorialHR 将 AI 助手连接到 FactorialHR,可管理员工、考勤、休假、项目、培训、招聘等人力资源数据。它以分类工具覆盖 CRUD 操作,并为高风险操作设置确认门槛、为写入记录审计日志。
主要功能
- 01员工、团队和地点管理
- 02休假与考勤操作
- 03项目、培训和招聘管理
- 04薪资、合同和文档访问
- 05确认门槛与写入审计日志
适用场景
- 01查看员工和团队记录
- 02核对考勤缺口与工时表
- 03管理休假申请和项目记录
- 04查看招聘与薪资数据
MCP 相关
这是一个 MCP 服务,通过 14 个分层分类工具提供 FactorialHR 的 124 项操作。它支持读取和写入,并对高风险操作设置确认保护。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @t4dhg/mcp-factorialFACTORIAL_API_KEY密钥API key from FactorialHR (Settings > API Keys)FACTORIAL_API_VERSIONAPI version (default: 2026-07-01)FACTORIAL_TIMEOUT_MSRequest timeout in milliseconds (default: 30000)FACTORIAL_MAX_RETRIESMaximum retry attempts (default: 3)DEBUGEnable debug logging (default: false)本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
14收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| category | string | 否 | 获取特定类别的详细信息(例如,"employees"、"time_off") |
详细介绍
MCP FactorialHR
适用于 FactorialHR 的权威模型上下文协议服务
这是一款功能全面的模型上下文协议(MCP)服务,可让 Claude 等 AI 助手全面访问 FactorialHR。管理员工、团队、休假、项目、培训、招聘等,并内置安全防护机制。
为什么选择此 MCP 服务?
- 优化上下文:提供 14 个分层工具(117 项操作),比使用单项工具减少 88% 的上下文占用
- 完整的 CRUD 操作:支持对所有主要实体进行创建、读取、更新和删除
- 安全防护机制:高风险操作需要明确确认
- 审计日志:所有写入操作都会记录时间戳和上下文,便于调试
- 面向企业:专为需要在适当管控下集成 AI 的企业打造
功能特性
分层工具发现(v8.0.0+)
MCP 服务采用分层工具结构,以优化上下文使用。你将获得 14 个按类别划分的工具,每个工具都带有一个 action 参数,而不是 124 个独立工具。
| 工具 | 描述 | 操作 |
|---|---|---|
factorial_discover | 发现可用类别 | - |
factorial_employees | 员工管理 | list、get、search、create、update、terminate |
factorial_teams | 团队管理 | list、get、create、update、delete |
factorial_locations | 地点管理 | list、get、create、update、delete |
factorial_contracts | 合同/薪资数据 | list、get_with_employee、by_job_role、by_job_level |
factorial_time_off | 休假管理 | 10 个操作 |
factorial_attendance | 班次和工时记录 | 14 个操作,包括 clock_in、audit、log_range |
factorial_documents | 文档管理 | 8 个操作(下载需要 OAuth2,见下文) |
factorial_job_catalog | 职位/级别 | list_roles、get_role、list_levels |
factorial_projects | 项目管理 | 16 个项目、任务、员工和工时相关操作 |
factorial_training | 培训管理 | 12 个培训、课程和报名相关操作 |
factorial_work_areas | 工作区域管理 | list、get、create、update、archive、unarchive |
factorial_ats | 申请人跟踪 | 17 个招聘相关操作 |
factorial_payroll | 薪资数据(只读) | 6 个操作 |
使用示例:
// List all employees
factorial_employees({ action: 'list', page: 1, limit: 50 });
// Get a specific employee
factorial_employees({ action: 'get', id: 123 });
// Search employees
factorial_employees({ action: 'search', query: 'john' });
// Create a leave request
factorial_time_off({
action: 'create',
employee_id: 123,
leave_type_id: 1,
start_on: '2026-02-01',
finish_on: '2026-02-05',
});
// Discover available actions for a category
factorial_discover({ category: 'employees' });
14 个类别中的 124 项操作
| 类别 | 操作 |
|---|---|
| 员工 | list、get、search、create、update、terminate |
| 团队 | list、get、create、update、delete |
| 地点 | list、get、create、update、delete |
| 休假 | list_leaves、get_leave、list_types、get_type、list_allowances、create、update、cancel、approve、reject |
| 考勤 | list、get、create、update、delete、clock_in、clock_out、status、gaps、audit、log_range、log_days、list_edit_requests、create_edit_request |
| 项目 | 16 项项目、任务、员工和时间记录相关操作 |
| 培训 | 12 项培训、场次和报名相关操作 |
| 工作区域 | list、get、create、update、archive、unarchive |
| ATS | 17 项职位发布、候选人、申请和招聘阶段相关操作 |
| 工资核算 | 列出/获取补贴、纳税人识别号和家庭情况(只读) |
| 文档 | 8 项文件夹、文档和下载相关操作(⚠️ 下载需要 OAuth2) |
| 职位目录 | list_roles、get_role、list_levels(只读) |
| 合同 | list、get_with_employee、by_job_role、by_job_level(只读) |
考勤和 Registro Horario
Factorial 要求员工逐日记录工作时间。factorial_attendance 允许 Claude 为 API 密钥可访问的任何员工记录一天或整个月的工时。
时间采用公司当地时间,以 HH:MM 表示,与 Factorial 中显示的时间完全一致;Factorial 会根据公司所在时区应用这些时间,服务端绝不会在不同时区之间进行转换。此服务写入的记录带有 source: "api",因此可以与 Factorial 自身活动日志中的实时打卡记录区分开来。
写入的申报工作时间(date、clock_in、clock_out)与录入元数据相互独立:Factorial 会根据记录的录入时间和方式,为 created_at、updated_at 及 in_source/out_source 添加时间戳;这些字段无法通过 API 设置或更改。每次创建、更新、clock_in、clock_out,以及每次批量预览和结果,都会说明申报工作时间,并且只说明一次。
| 操作 | 功能 |
|---|---|
status | 员工是否已打卡上班,以及从何时开始。始终打印已配置的身份。 |
clock_in、clock_out | 按当前时间实时打卡,或提供 date 和 time(公司当地时间,格式为 HH:MM),为忘记打卡的人申报一个时间。若申报的时间在未来,则在发送任何请求前拒绝。若没有尚未结束的班次,或申报的 clock_out 时间早于当前班次的开始时间,则拒绝该申报。 |
gaps | 日期范围内合同要求的工时多于已记录工时的工作日。不包括周末、银行假日和全天休假。 |
audit | 日期范围内每个日历日对应一行:日期类型、预期和已记录工时、休假覆盖情况、已记录的班次,以及状态(complete、missing、short、over、weekend、bank_holiday、on_leave、half_day_leave、no_contract_data、future)。missing 表示没有记录;short 表示已记录部分工时,但比预期少超过容差,并显示差值。已签核的日期会单独标记,且禁止写入;可通过 create_edit_request 申请更正。表头会列出 expected(银行假日和休假日按完整合同分钟数计算)以及 workday expected(已记录工时实际应达到的时数)。statuses 可将摘要限制为指定状态集合。format 可以是 summary(默认值,仅显示需要关注的日期)、table(显示每天)或 json(显示台账)。这是对照已打卡工时与应有工时进行核对的起点。 |
log_range | 将每日模式(segments)应用于日期范围内每个可工作的日期。跳过周末、银行假日、合同要求 0 分钟的日期、已批准的休假日期、未来日期、已签核日期、exclude_dates,以及与现有班次重叠的时段。 |
log_days | 写入包含各自时段的明确日期列表,用于从其他平台迁移数据。仅拒绝未来日期、已批准的休假日期、已签核日期和重叠时段,因此可以写入某人曾工作的星期六。 |
list、get、create、update、delete | 单个班次记录。list 需要提供 start_on 和 end_on(或 ids,或 updated_at);Factorial 会忽略此端点的分页,因此由客户端分页。list 中的 fields: "compact" 会返回较小的数据载荷(日期、clock_in、clock_out、分钟数、in_source);get 会返回完整记录。 |
list_edit_requests、create_edit_request | Factorial 用于更正已签核日期的途径,因为不能直接向已审核日期写入工时。提交申请会通知审批工时表的人员,因此即使是已配置的身份,create_edit_request 也需要预览并通过令牌门控。 |
// Find the missing days first
factorial_attendance({ action: 'gaps', start_on: '2026-03-01', end_on: '2026-03-31' });
// Preview a month of split days; nothing is written yet
factorial_attendance({
action: 'log_range',
start_on: '2026-03-01',
end_on: '2026-03-31',
segments: [
{ clock_in: '09:00', clock_out: '14:00' },
{ clock_in: '15:00', clock_out: '18:00' },
],
});
// -> "Plan for <name> (<id>) ... 20 days to write, 40 shift records, 160h ... confirmation_token: <token>"
// Same call plus the token writes it
factorial_attendance({ action: 'log_range', /* same arguments */ confirmation_token: '<token>' });
// Afterwards, reconcile the month
factorial_attendance({ action: 'audit', start_on: '2026-03-01', end_on: '2026-03-31' });
未来日期规则中的“今天”指运行服务的机器所在时区的日期,因此请在公司所在时区运行,或者接受边界日期可能相差一天。银行假日来自 Factorial 中公司的日历(worked_times.day_type),因此不需要假日列表。已批准的休假从 timeoff/leaves 读取;如果源系统的数据是正确的,而 Factorial 的休假记录已过时,请传入 skip_leave: false。半天休假的日期不会纳入 log_range,并会在预览中列出;要记录实际工作的半天,请使用 log_days。
没人每天都恰好在 09:00 打卡,而整个月记录都一模一样,是实际工时记录中绝不会出现的模式。向 log_range 或 log_days 传入 jitter_minutes(5 到 10 分钟较为合适),写入的每个时间就会在当天内偏离你的模式最多指定的分钟数;各时间段不会彼此重叠。传入 variation_minutes 则可实现另一种变化:它会为整天确定一个偏移量,使开始时间逐日变化;jitter_minutes 无法做到这一点,因为它只会改变一天内各时间段的时间。两者都根据员工、日期和(对于 jitter)时间段确定,因此预览会列出将要写入的确切时间,确认令牌会与这些时间绑定,重试时也能识别自己先前写入的记录。这些记录仍会带有 source: "api";这些选项让重建的工时更真实,但不会掩盖其来源。
每个 gaps、audit 和批量写入预览都会以一行 Data read 开头:显示该时间范围内有合同数据的天数,以及读取的休假和班次记录数。读取会遵循 Factorial 的分页机制直至结束,因此任何长度的时间范围都能完整读取;对于 API 没有返回数据的日期,会报告为 no_contract_data,且绝不会写入,而不会将其伪装成不可工作的日期。这些日期通常在入职日期之前。如果并非如此,则说明读取不完整,不应信任结果。
已签核的时段。 在 Factorial 中审核某日期的工时表后,该日期便会禁止写入;对该日期写入班次会被拒绝并返回 403。audit 会同时读取 attendance/reviews 和其他事实,并在任何写入前将这些日期标记为已签核;log_range 和 log_days 也会像跳过周末或已批准的休假日期那样跳过这些日期。要更正已签核的日期,请使用 create_edit_request 提交申请,由工时表审批人决定如何处理;list_edit_requests 会读取已提交的申请。即使是已配置的身份,提交申请也需要预览并通过令牌验证,因为这会通知相关人员。
对于不存在的日期(例如 2026-02-30),系统会拒绝处理,而不会静默地顺延到下一个有效日期;真实存在的闰日(例如 2024-02-29)则会正常接受。
审计一个月的工时。 首先对整个时间范围运行 audit。某日的工时总数与预期值相差不超过 tolerance_minutes(默认 15 分钟),就会计为 complete,因此符合实际情况的打卡时间和带有随机偏差的补录记录不会被误判为工时不足。将台账与本地掌握的信息(例如日历、其他工时跟踪系统、实际在假日工作的日期)进行比较,然后修正差异:用 log_range 或 log_days 补录缺失日期,用 delete 或 update 修正错误记录,再次运行 audit,确认每个工作日都显示为 complete。
这五个提示词为用户封装了这些工作流,并有一个指南资源供模型参考;请参阅 5 MCP Prompts 和 factorial://guides/registro-horario。有些客户端(包括 Claude Code)只会将提示词显示为由用户调用的斜杠命令,模型本身无法读取;因此,每个提示词的操作步骤也会作为资源发布于 factorial://prompts/<name>。
将 FACTORIAL_EMPLOYEE_ID 设置为你自己的员工 ID,这样就可以省略 employee_id。针对其他人的写入操作以及所有批量写入操作都需要确认令牌;请参阅安全与保护。
6 个 MCP 资源
| 资源 URI | 描述 |
|---|---|
factorial://org-chart | 完整的组织架构(Markdown) |
factorial://guides/registro-horario | 如何使用此服务审核、填写和维护 registro horario(Markdown) |
factorial://employees/directory | 按团队划分的员工目录(Markdown) |
factorial://locations/directory | 包含员工人数的地点目录(Markdown) |
factorial://timeoff/policies | 所有休假类型和政策(JSON) |
factorial://teams/{team_id} | 团队详情及成员列表(JSON,模板化) |
factorial://prompts/{name} | 考勤提示词的操作步骤文本,可在不调用提示词的情况下读取(Markdown) |
5 个 MCP 提示词
提示词是由用户调用的操作步骤(在 Claude Code 中,它们会以 /mcp__factorial__<name> 斜杠命令的形式显示)。考勤提示词会预先读取操作步骤所需的数据,并明确说明后续要调用的工具,因此小型模型也能完成整个工作流。提示词本身绝不会写入任何内容;写入操作会通过 factorial_attendance 及其确认关卡执行。
| 提示词 | 参数 | 功能 |
|---|---|---|
attendance_audit | start_on、end_on、employee_id(均为可选) | 运行审计(默认范围:本月至今,使用 FACTORIAL_EMPLOYEE_ID),并请求生成只读报告:预期工时与已记录工时的对比、按月统计的缺失天数和超时天数,以及数据覆盖警告。 |
attendance_fill | segments(必填)、start_on、end_on、employee_id、observations、jitter_minutes | 读取工时缺口,并传递带有已解析模式的准确 log_range 调用,然后执行预览、人工确认、令牌、重试和验证步骤。segments 的值为 "09:00-14:00, 15:00-18:00"。 |
attendance_today | segments(必填)、employee_id、observations、jitter_minutes | 读取今天的状态并作出判断:周末、节假日、休假、未结束班次或已完成的工作日均不执行任何操作;否则,为今天调用 log_days,并在同一会话中仅针对已配置的身份进行确认。 |
attendance_reconcile | known_absences(必填)、start_on、end_on、employee_id | 运行审计,并仅报告与已提供的已知缺勤列表不一致的日期(休息日、病假、出差)。只读。 |
attendance_fill_days | days(必填)、employee_id、observations、jitter_minutes | 针对一组明确指定的日期填写 registro horario,每个日期都有自己的每日模式,并将其作为一次 log_days 调用执行:预览、人工确认、令牌、重试和验证。days 的值为 [{"date":"2026-03-02","segments":"09:00-14:00, 15:00-18:00"}]。 |
summarize_team | team_id | 团队摘要,包含成员和角色。 |
time_off_report | employee_id | 员工休假报告:休假额度和近期休假。 |
按计划运行每日记录。 MCP 没有计划任务调度器,因此计划任务由客户端负责。在 Claude Code 中,/schedule 会创建一个例程,使用你的模式调用 attendance_today;/loop 会在会话保持打开时重复执行;任何 cron 都可以将提示词作为输入运行 claude -p。只有在今天是工作日且没有任何已记录工时的情况下,提示词才会写入记录,并且仅针对 FACTORIAL_EMPLOYEE_ID 中的员工;无论是否写入,都会报告一行内容。生成的记录是工作时长的法律文件,因此你设置的模式必须与你实际工作的时长一致;不工作的日期则需要休假记录或手动更正。
架构特性
- 安全护栏:高风险操作(终止、删除)需要确认
- 审计日志:所有写入操作都会在进程内记录,并包含时间戳和上下文
- 缓存:基于 TTL 的内存缓存(可按资源类型配置)
- 分页:所有列表操作均支持分页
- 重试逻辑:采用指数退避,并处理速率限制
- 验证:使用 Zod 架构进行运行时验证
快速开始
1. 添加到 MCP 配置中
{
"mcpServers": {
"factorial": {
"command": "npx",
"args": ["-y", "@t4dhg/mcp-factorial"]
}
}
}
2. 设置 API 密钥
在项目根目录中创建 .env 文件:
FACTORIAL_API_KEY=your-api-key-here
或者直接在 MCP 配置中传入:
{
"mcpServers": {
"factorial": {
"command": "npx",
"args": ["-y", "@t4dhg/mcp-factorial"],
"env": {
"FACTORIAL_API_KEY": "your-api-key-here"
}
}
}
}
3. 开始使用!
配置完成后,可以向 Claude 提问,例如:
- “工程团队里有哪些人?”
- “创建一名新员工 John Smith”
- “批准员工 42 待处理的休假申请”
- “创建一个名为 Q1 Marketing Campaign 的新项目”
- “让 Sarah 参加 Leadership Training 项目”
- “显示所有正在招聘的职位”
- “有哪些候选人申请了 Senior Developer 职位?”
获取 API 密钥
要使用此 MCP 服务,你需要 FactorialHR API 密钥。获取方法如下:
- 以管理员身份登录 FactorialHR
- 前往 设置 → API 密钥
- 点击 “New API key” 按钮
- 为密钥设置一个便于识别的名称(例如,“Claude Code”或“MCP Server”)
- 点击 Create——系统将显示你的 API 密钥
- 立即复制密钥——密钥只会显示一次,之后无法找回
- 将密钥添加到
.env文件或 MCP 配置中
重要提示:API 密钥拥有对 FactorialHR 数据的完整访问权限,且永不过期。请妥善保管,切勿提交到版本控制系统,并定期轮换。
OAuth2 设置(下载文档所必需)
文档下载操作(download_payslips、download)需要 OAuth2 身份验证。这是 Factorial API 的限制——下载端点不接受 API 密钥身份验证。
注意:创建 OAuth 应用需要 Factorial 管理员权限。
第 1 步:创建 OAuth2 应用
- 前往:https://api.factorialhr.com/oauth/applications
- 点击 “New application”
- 填写以下内容:
- Redirect URI:
http://localhost:8080/callback(或任何你能够访问的网址) - Confidentiality:是(服务端应用)
- Scopes:选择所需的范围:
- 下载所需:Documents、Employees
- 完整使用 MCP 功能的建议范围:Contracts、Payroll、Payroll supplements、Time off、Shift management、Trainings、Recruitment、Company locations、Job catalog
- Redirect URI:
- 保存并记下你的 Client ID 和 Client Secret
第 2 步:获取授权码
在浏览器中打开以下 URL(替换 YOUR_CLIENT_ID):
https://api.factorialhr.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8080/callback&response_type=code
- 登录并授权该应用
- 系统会将你重定向到回调 URL,并附带
?code=AUTHORIZATION_CODE - 从 URL 中复制该代码(代码很快就会过期,因此请立即继续第 3 步)
第 3 步:用代码换取令牌
运行以下 curl 命令(替换占位符):
curl -X POST 'https://api.factorialhr.com/oauth/token' \
-d 'client_id=YOUR_CLIENT_ID' \
-d 'client_secret=YOUR_CLIENT_SECRET' \
-d 'code=AUTHORIZATION_CODE' \
-d 'grant_type=authorization_code' \
-d 'redirect_uri=http://localhost:8080/callback'
你会收到包含 access_token 和 refresh_token 的响应。请保存 refresh_token。
第 4 步:配置 MCP 服务
将 OAuth2 凭据添加到 MCP 配置中:
{
"mcpServers": {
"factorial": {
"command": "npx",
"args": ["-y", "@t4dhg/mcp-factorial"],
"env": {
"FACTORIAL_API_KEY": "your-api-key",
"FACTORIAL_OAUTH_CLIENT_ID": "your-client-id",
"FACTORIAL_OAUTH_CLIENT_SECRET": "your-client-secret",
"FACTORIAL_OAUTH_REFRESH_TOKEN": "your-refresh-token"
}
}
}
}
或者添加到 .env 文件中:
FACTORIAL_API_KEY=your-api-key
FACTORIAL_OAUTH_CLIENT_ID=your-client-id
FACTORIAL_OAUTH_CLIENT_SECRET=your-client-secret
FACTORIAL_OAUTH_REFRESH_TOKEN=your-refresh-token
重要说明
- 刷新令牌在 1 周后过期——过期后需要重复第 2 至第 3 步
- MCP 服务会使用刷新令牌自动刷新访问令牌
- 如果文档下载突然无法使用,很可能是刷新令牌已过期
使用场景
面向经理
- 创建和管理团队架构
- 批准或拒绝休假申请
- 为员工分配项目
- 跟踪项目工时记录
- 监控培训报名情况
面向 HR
- 通过完整的数据录入为新员工办理入职
- 管理职位发布和招聘流程
- 跟踪候选人申请的招聘阶段
- 生成组织结构分析
- 管理培训计划和报名
面向开发者
- 构建需要员工上下文的 AI 工作流
- 创建自定义 Claude 集成
- 借助 AI 助手自动化 HR 流程
- 生成报告和分析
配置选项
| 环境变量 | 描述 | 默认值 |
|---|---|---|
FACTORIAL_API_KEY | 你的 FactorialHR API 密钥 | 必填 |
FACTORIAL_API_VERSION | API 版本 | 2026-07-01 |
FACTORIAL_EMPLOYEE_ID | 你的员工 ID:默认目标对象,以及考勤操作中不受限制的身份 | - |
FACTORIAL_TIMEOUT_MS | 请求超时时间(毫秒) | 30000 |
FACTORIAL_MAX_RETRIES | 最大重试次数 | 3 |
DEBUG | 启用调试日志 | false |
FACTORIAL_OAUTH_CLIENT_ID | OAuth2 客户端 ID(用于下载) | - |
FACTORIAL_OAUTH_CLIENT_SECRET | OAuth2 客户端密钥(用于下载) | - |
FACTORIAL_OAUTH_REFRESH_TOKEN | OAuth2 刷新令牌(用于下载) | - |
安全与防护
需要确认的操作
以下操作需要明确确认(confirm: true)。如果未提供此参数调用,工具会返回说明影响的警告,且不会做出任何更改。风险按操作分类,详见 src/write-safety.ts;无论风险评级为高还是中,以下所有操作都需要确认:
factorial_employees({ action: 'terminate' })- 终止一名员工的雇佣关系factorial_teams({ action: 'delete' })- 永久删除一个团队factorial_locations({ action: 'delete' })- 永久删除一个地点factorial_projects({ action: 'delete' })- 永久删除一个项目factorial_projects({ action: 'delete_task' })- 删除一个项目任务factorial_projects({ action: 'delete_time' })- 删除一条工时记录factorial_projects({ action: 'remove_worker' })- 删除一名员工在某个项目中的分配factorial_attendance({ action: 'delete' })- 删除一条班次记录factorial_time_off({ action: 'cancel' })- 取消一项休假申请factorial_time_off({ action: 'reject' })- 拒绝一项休假申请factorial_training({ action: 'delete' })- 删除一个培训计划及其报名记录factorial_training({ action: 'delete_session' })- 删除一场培训课程factorial_training({ action: 'unenroll' })- 删除一名员工的培训报名factorial_ats({ action: 'delete_posting' })- 删除一个职位发布及其申请factorial_ats({ action: 'delete_candidate' })- 永久删除一名候选人factorial_ats({ action: 'delete_application' })- 永久删除一项申请
由确认令牌控制的操作
考勤写入操作受目标对象和涉及记录数量的限制,而单个操作的策略无法表达这些条件。首次调用不会写入任何内容,而是返回一份预览,其中列出人员、日期和总数,以及一个有效期为 15 分钟且仅绑定到该计划的 confirmation_token。使用该令牌再次调用即可执行操作;如果期间计划发生变化(例如有人写入了班次),令牌将被拒绝,并会生成一份新的预览。confirm: true 无法绕过此限制,因为首次调用时没有可传入的令牌。
当目标不是配置的 FACTORIAL_EMPLOYEE_ID 时需要确认;如果未设置该变量,则始终需要确认:
factorial_attendance({ action: 'create' })- 为其他人员创建班次factorial_attendance({ action: 'update' })- 更新其他人员的班次(会先获取班次,以确定其归属人员)factorial_attendance({ action: 'delete' })- 删除其他人员的班次,且仍需confirm: truefactorial_attendance({ action: 'clock_in' })- 为其他人员打卡上班factorial_attendance({ action: 'clock_out' })- 为其他人员打卡下班
无论目标是谁,以下操作始终需要确认,因为操作量本身就存在风险:
factorial_attendance({ action: 'log_range' })- 为日期范围内每个可工作日写入一条或多条班次记录factorial_attendance({ action: 'log_days' })- 为明确列出的日期写入记录factorial_attendance({ action: 'create_edit_request' })- 提交修改工时表的请求,该请求会通知相关人员,因此即使目标是配置的身份,也需要确认
批量调用部分失败后,重新运行时不会重复写入此前已成功写入的内容:规划器会重新读取现有班次,并跳过重叠的部分。但这无法防止其他写入者在读取和写入之间进行操作。
文档下载
文档名称来自 Factorial 元数据,而非调用方,因此下载时会将其视为不可信数据:
- 名称会缩减为单个路径段,因此包含路径分隔符的名称无法将下载重定向到
output_dir之外。 - 控制字符会被移除,过长的名称会被缩短,同时保留扩展名。
- 绝不会覆盖任何文件。 如果目标名称已被占用,文件将依次保存为
name (1).ext、name (2).ext等。这样既能保护output_dir中的现有文件,也能避免两个同名文档被合并为一个文件。
下载仍会写入你指定的 output_dir,因此请将其设为专用于下载的目录,而不是源代码目录或主目录。
只读类别
出于安全考虑,以下类别有意设为只读:
- 薪资:补充信息、税务识别信息、家庭情况
- 文档:文件夹和文档元数据(可使用工资单和文档下载工具)
- 合同:历史合同数据
响应优化
文档和合同列表操作默认返回摘要格式,以防止令牌溢出:
文档(factorial_documents({ action: 'list' })):
- 返回:
id、name、folder_id、employee_id、mime_type(5 个字段) - 默认限制:每页 100 份文档
- 获取完整详情:使用
factorial_documents({ action: 'get', id: X })获取完整元数据
合同(factorial_contracts({ action: 'list' })):
- 返回:
id、employee_id、job_title、effective_on(4 个字段) - 默认限制:每页 100 份合同
所有列表操作都接受 page 和 limit 参数,用于控制分页。
审计日志
所有写入操作(创建、更新、删除、批准、拒绝)都会记录以下信息:
- 时间戳
- 操作类型
- 实体类型和 ID
- 所做的更改
- 成功或失败,以及所用时长
此日志的范围。 日志记录保存在运行中的服务器进程内存中,最多保留最近 1000 条,且不会通过任何工具或资源公开。进程退出后,日志记录会丢失。设置 DEBUG=true 后,每条记录都会写入服务器的 stderr,这是目前唯一的保留方式。此日志仅用于调试,不可作为合规记录:如果你需要持久、可查询的审计日志,请使用 FactorialHR 自带的活动日志作为权威记录。
开发
# Clone the repository
git clone https://github.com/t4dhg/mcp-factorial.git
cd mcp-factorial
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint
npm run lint
# Format
npm run format
# Run locally
FACTORIAL_API_KEY=your-key npm start
# Test with MCP Inspector
npx @modelcontextprotocol/inspector
项目结构
代码库按领域划分为多个模块,以便于维护:
src/
├── schemas/ # Zod schemas by domain
│ ├── employees.ts # Employee, Team, Location, Contract schemas
│ ├── time-off.ts # Leave, LeaveType, Allowance, Shift schemas
│ ├── projects.ts # Project, Task, Worker, TimeRecord schemas
│ ├── training.ts # Training, Session, Membership schemas
│ ├── ats.ts # JobPosting, Candidate, Application schemas
│ └── ...
├── api/ # API functions by domain
│ ├── employees.ts # listEmployees, getEmployee, createEmployee, etc.
│ ├── time-off.ts # listLeaves, createLeave, approveLeave, etc.
│ ├── projects.ts # listProjects, createProject, etc.
│ └── ...
├── tools/ # MCP tool registrations by domain
│ ├── employees.ts # factorial_employees tool registration
│ ├── time-off.ts # factorial_time_off tool registration
│ ├── index.ts # Server setup, discovery tool, resources, prompts
│ └── ...
├── index.ts # Entry point (re-exports from tools/)
├── api.ts # Re-exports from api/
└── schemas.ts # Re-exports from schemas/
添加新功能:
- 将架构添加到
src/schemas/{domain}.ts - 将 API 函数添加到
src/api/{domain}.ts - 将工具操作添加到
src/tools/{domain}.ts - 根据需要更新
src/schemas/index.ts、src/api/index.ts导出 - 运行
npm test进行验证
故障排除
API 密钥无法使用
- 确保 API 密钥具有适当的权限
- 检查密钥是否已撤销或过期
- 确认已在环境变量中正确设置密钥
速率限制
服务器会针对速率限制实施指数退避。如果你频繁触及限制:
- 降低请求频率
- 使用较小的页面大小进行分页
- 避免使用破坏缓存的参数,以启用缓存
数据缺失
hired_on字段:FactorialHR API 可能不会为所有员工填充此字段- 团队成员身份:部分员工可能未分配到团队
- 响应为空:检查该资源是否存在于你的 Factorial 账户中
文档无法下载
文档下载需要 OAuth2 身份验证。这是 Factorial API 的限制——下载端点不接受 API 密钥身份验证。
如果你看到类似以下错误:
“文档下载需要 OAuth2 身份验证”
你需要设置 OAuth2 凭据。请参阅上文的 OAuth2 设置(文档下载必需)。
注意:OAuth2 刷新令牌会在 1 周后过期。如果下载突然无法使用,请重新授权并获取新的刷新令牌。
“未找到 ID 为 X 的文档”错误
Factorial API 的单个文档端点(GET /documents/{id})在访问员工专属文档时存在限制。这是因为:
- 使用
employee_ids筛选条件调用list_documents可以正确返回所有员工文档 - 按 ID 调用
get_document无法单独访问这些相同的文档
解决方法:使用 download_payslips 操作,而不是 download 操作。download_payslips 操作会直接使用列表操作返回的文档元数据,绕过存在问题的单个 GET 端点:
// This works - uses document list internally
factorial_documents({
action: 'download_payslips',
employee_id: 123,
output_dir: '/path/to/downloads',
});
常见问题
Q:这会暴露薪资/工资数据吗? A:薪资数据(津贴、纳税人识别信息、家庭状况)可供只读访问。不支持任何薪资数据写入操作。
Q:Claude 可以修改 Factorial 中的数据吗? A:可以!员工、团队、地点、休假、项目、培训和招聘数据均支持完整的 CRUD 操作。高风险操作会明确标记。
Q:数据如何缓存? A:数据缓存在内存中,并设有 TTL:员工(5 分钟)、团队(10 分钟)、地点(15 分钟)、合同(3 分钟)。
Q:使用的是哪个版本的 FactorialHR API?
A:默认使用 2026-07-01 版本。可通过 FACTORIAL_API_VERSION 环境变量覆盖。自该版本起,所有 Factorial 标识符(id 和 *_id 字段)都是字符串,而非数字;请将其视为不透明字符串。
Q:Claude 可以帮我填写 registro horario 吗?
A:可以。设置 FACTORIAL_EMPLOYEE_ID,运行 gaps 查看缺失日期,然后使用每日时段运行 log_range。首次调用会返回预览和令牌;第二次调用才会写入数据。请参阅考勤与 Registro Horario。
Q:写入操作会记录日志吗? A:会,每次写入都会由审计模块记录,包含时间戳、实体、变更内容和结果。日志保存在运行进程的内存中(最多保留最近 1000 条),无法通过 MCP 接口检索,因此应将其视为调试辅助信息,而非合规记录。请参阅审计日志。
Factorial API 的特殊情况和限制
FactorialHR API 的某些设计模式与常见的 REST API 不同。此 MCP 服务会自动处理这些情况,但了解它们有助于调试或扩展:
数据位置的特殊情况
| 数据 | 预期位置 | 实际位置 | 影响 |
|---|---|---|---|
| 团队成员关系 | Employee 对象上(team_ids) | Team 对象上(employee_ids) | 使用 list_teams 查找员工所属的团队 |
| 职位角色分配 | Employee 对象上(job_role_id) | Contract 对象中(job_catalog_role_id) | 使用 get_employee_with_contract 获取职位角色信息 |
| 薪资信息 | Employee 对象上 | Contract 对象中(salary_amount、salary_frequency) | 使用 get_employee_with_contract 获取薪资 |
| 职位名称 | Employee 对象上 | Contract 对象中(job_title) | 如果未在 Factorial 中设置,可能为 null |
端点的特殊情况
| 端点 | 特殊情况 | 解决方法 |
|---|---|---|
GET /employees/{id} | 对有效员工也可能返回 404 | 服务会回退为列出所有员工并进行筛选 |
GET /documents/{id} | 可能对员工专属文档返回 404 | 使用 download_payslips 绕过此问题 |
GET /contracts?employee_id=X | 筛选不可靠 | 服务会获取所有记录,并在客户端进行筛选 |
| 空结果 | 返回 {"errors": null},而非 {"data": []} | 服务会同时处理两种格式 |
| 文档下载 URL | 需要 OAuth2(API 密钥无效) | 配置 OAuth2 凭据以供下载 |
字段可用性
即使您预期某些字段有数据,它们也可能为 null:
job_title:仅在员工合同中设置了该字段时才会填充manager_id:仅在配置了汇报结构时才会填充seniority_calculation_date:请使用此字段,而非不存在的hired_on字段- 文档元数据(
name、mime_type、size_bytes):某些文档的这些字段可能为 null
薪资数据
薪资信息位于 Contract 实体中,而非 Employee 实体中:
salary_amount: number (in cents, e.g., 7000000 = €70,000)
salary_frequency: 'yearly' | 'monthly' | 'weekly' | 'daily' | 'hourly'
使用 get_employee_with_contract 获取包含最新薪资信息的员工数据。
最佳实践
- 获取员工的职位:使用
get_employee_with_contract,而非get_employee - 按职位查找员工:使用
list_employees_by_job_role,并提供职位 ID - 查找员工所属的团队:查询
list_teams,并检查employee_ids数组 - 获取薪资数据:始终使用合同端点,而非员工端点
贡献
欢迎贡献!请参阅 CONTRIBUTING.md 了解指南。
许可证
MIT © Taig Mac Carthy
由 Anthropic 基于 Model Context Protocol 构建
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。