@t4dhg/mcp-factorial 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2025 Taig Mac Carthy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
6
  [![MCP Compatible](https://img.shields.io/badge/MCP-Compatible-green.svg)](https://modelcontextprotocol.io/)
7
7
  [![Node.js](https://img.shields.io/badge/Node.js-18%2B-brightgreen.svg)](https://nodejs.org/)
8
+ [![npm version](https://img.shields.io/npm/v/@t4dhg/mcp-factorial.svg)](https://www.npmjs.com/package/@t4dhg/mcp-factorial)
8
9
 
9
10
  A Model Context Protocol (MCP) server that provides AI assistants like Claude with secure, read-only access to your FactorialHR employee and organizational data. Built with privacy and security as core principles.
10
11
 
@@ -18,6 +19,7 @@ A Model Context Protocol (MCP) server that provides AI assistants like Claude wi
18
19
  ## Security by Design
19
20
 
20
21
  This MCP server intentionally **does NOT expose**:
22
+
21
23
  - Payroll and salary information
22
24
  - Bank account details
23
25
  - Tax documents
@@ -27,18 +29,59 @@ This MCP server intentionally **does NOT expose**:
27
29
 
28
30
  We believe AI assistants should help with organizational tasks without having access to your most sensitive HR data.
29
31
 
30
- ## Available Tools
31
-
32
- | Tool | Description |
33
- |------|-------------|
34
- | `list_employees` | Get all employees with optional team/location filters |
35
- | `get_employee` | Get employee details (name, role, contact, team assignments) |
36
- | `search_employees` | Search employees by name or email |
37
- | `list_teams` | View organizational team structure |
38
- | `get_team` | Get team details and member list |
39
- | `list_locations` | Get company office locations |
40
- | `get_location` | Get location details (address, contact info) |
41
- | `get_employee_contracts` | View job titles and employment dates |
32
+ ## Features
33
+
34
+ ### 22 Tools
35
+
36
+ | Category | Tool | Description |
37
+ | --------------- | ------------------------ | ---------------------------------------------------------------- |
38
+ | **Employees** | `list_employees` | Get employees with optional team/location filters and pagination |
39
+ | | `get_employee` | Get detailed information about a specific employee |
40
+ | | `search_employees` | Search employees by name or email |
41
+ | **Teams** | `list_teams` | View organizational team structure |
42
+ | | `get_team` | Get team details and member list |
43
+ | **Locations** | `list_locations` | Get company office locations |
44
+ | | `get_location` | Get location details (address, contact info) |
45
+ | **Contracts** | `get_employee_contracts` | View job titles and contract effective dates |
46
+ | **Time Off** | `list_leaves` | List time off requests with filters |
47
+ | | `get_leave` | Get leave request details |
48
+ | | `list_leave_types` | Get all leave types (vacation, sick, etc.) |
49
+ | | `get_leave_type` | Get leave type details |
50
+ | | `list_allowances` | Get time off balances |
51
+ | **Attendance** | `list_shifts` | List employee shifts |
52
+ | | `get_shift` | Get shift details |
53
+ | **Documents** | `list_folders` | List document folders |
54
+ | | `get_folder` | Get folder details |
55
+ | | `list_documents` | List documents |
56
+ | | `get_document` | Get document metadata |
57
+ | **Job Catalog** | `list_job_roles` | List job roles |
58
+ | | `get_job_role` | Get job role details |
59
+ | | `list_job_levels` | List job levels |
60
+
61
+ ### 5 MCP Resources
62
+
63
+ | Resource URI | Description |
64
+ | --------------------------------- | -------------------------------------------------- |
65
+ | `factorial://org-chart` | Complete organizational hierarchy (Markdown) |
66
+ | `factorial://employees/directory` | Employee directory by team (Markdown) |
67
+ | `factorial://locations/directory` | Location directory with employee counts (Markdown) |
68
+ | `factorial://timeoff/policies` | All leave types and policies (JSON) |
69
+ | `factorial://teams/{team_id}` | Team details with member list (JSON, templated) |
70
+
71
+ ### 3 MCP Prompts
72
+
73
+ | Prompt | Description |
74
+ | ----------------------- | ----------------------------------------------------------------- |
75
+ | `onboard-employee` | Generate personalized onboarding checklists |
76
+ | `analyze-org-structure` | Analyze org structure (reporting lines, team sizes, distribution) |
77
+ | `timeoff-report` | Generate time off reports by team or date range |
78
+
79
+ ### Architecture Features
80
+
81
+ - **Caching**: In-memory TTL-based caching (configurable by resource type)
82
+ - **Pagination**: All list operations support pagination
83
+ - **Retry Logic**: Exponential backoff with rate limit handling
84
+ - **Validation**: Runtime validation with Zod schemas
42
85
 
43
86
  ## Quick Start
44
87
 
@@ -83,10 +126,12 @@ Or pass it directly in the MCP config:
83
126
 
84
127
  Once configured, ask Claude things like:
85
128
 
86
- - *"Who's on the Engineering team?"*
87
- - *"Find the email for John Smith"*
88
- - *"What offices do we have?"*
89
- - *"Show me the org structure"*
129
+ - _"Who's on the Engineering team?"_
130
+ - _"Find the email for John Smith"_
131
+ - _"What offices do we have?"_
132
+ - _"Show me the org structure"_
133
+ - _"How much PTO does employee 42 have left?"_
134
+ - _"Generate an onboarding checklist for the new hire"_
90
135
 
91
136
  ## Getting an API Key
92
137
 
@@ -100,20 +145,33 @@ Once configured, ask Claude things like:
100
145
  ## Use Cases
101
146
 
102
147
  ### For Managers
148
+
103
149
  - Quickly look up team member contact information
104
150
  - Understand org chart and reporting structures
105
- - Find employees by skill or department
151
+ - Monitor time off schedules for coverage planning
106
152
 
107
153
  ### For HR
154
+
108
155
  - Power AI-assisted employee directory searches
109
156
  - Streamline onboarding information lookups
110
- - Support with organizational queries
157
+ - Generate time off reports and analyze patterns
111
158
 
112
159
  ### For Developers
160
+
113
161
  - Build AI workflows that need employee context
114
162
  - Create custom Claude integrations
115
163
  - Automate org-chart-aware processes
116
164
 
165
+ ## Configuration Options
166
+
167
+ | Environment Variable | Description | Default |
168
+ | ----------------------- | ------------------------ | ------------ |
169
+ | `FACTORIAL_API_KEY` | Your FactorialHR API key | Required |
170
+ | `FACTORIAL_API_VERSION` | API version | `2025-10-01` |
171
+ | `FACTORIAL_TIMEOUT` | Request timeout (ms) | `30000` |
172
+ | `FACTORIAL_MAX_RETRIES` | Max retry attempts | `3` |
173
+ | `DEBUG` | Enable debug logging | `false` |
174
+
117
175
  ## Development
118
176
 
119
177
  ```bash
@@ -127,6 +185,18 @@ npm install
127
185
  # Build
128
186
  npm run build
129
187
 
188
+ # Run tests
189
+ npm test
190
+
191
+ # Run tests with coverage
192
+ npm run test:coverage
193
+
194
+ # Lint
195
+ npm run lint
196
+
197
+ # Format
198
+ npm run format
199
+
130
200
  # Run locally
131
201
  FACTORIAL_API_KEY=your-key npm start
132
202
 
@@ -134,21 +204,50 @@ FACTORIAL_API_KEY=your-key npm start
134
204
  npx @modelcontextprotocol/inspector
135
205
  ```
136
206
 
137
- ## Configuration Options
207
+ ## Troubleshooting
208
+
209
+ ### API Key Not Working
210
+
211
+ - Ensure the API key has appropriate permissions
212
+ - Check if the key has been revoked or expired
213
+ - Verify the key is set correctly in environment variables
214
+
215
+ ### Rate Limiting
216
+
217
+ The server implements exponential backoff for rate limits. If you're hitting limits frequently:
218
+
219
+ - Reduce request frequency
220
+ - Use pagination with smaller page sizes
221
+ - Enable caching by avoiding cache-busting parameters
222
+
223
+ ### Missing Data
224
+
225
+ - **`hired_on` field**: The FactorialHR API may not populate this for all employees
226
+ - **Team membership**: Some employees may not be assigned to teams
227
+ - **Empty responses**: Check if the resource exists in your Factorial account
228
+
229
+ ## FAQ
230
+
231
+ **Q: Does this expose salary/payroll data?**
232
+ A: No. This MCP server deliberately excludes all payroll, compensation, and financial data.
233
+
234
+ **Q: Can Claude modify data in Factorial?**
235
+ A: No. This is a read-only integration. No write operations are supported.
236
+
237
+ **Q: How is data cached?**
238
+ A: Data is cached in-memory with TTLs: employees (5 min), teams (10 min), locations (15 min), contracts (3 min).
138
239
 
139
- | Environment Variable | Description | Required |
140
- |---------------------|-------------|----------|
141
- | `FACTORIAL_API_KEY` | Your FactorialHR API key | Yes |
142
- | `DEBUG` | Enable debug logging (`true`/`false`) | No |
240
+ **Q: What FactorialHR API version is used?**
241
+ A: Version `2025-10-01` by default. Override with `FACTORIAL_API_VERSION` environment variable.
143
242
 
144
243
  ## Contributing
145
244
 
146
- Contributions are welcome! Please feel free to submit a Pull Request.
245
+ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
147
246
 
148
247
  ## License
149
248
 
150
- MIT © [t4dhg](https://github.com/t4dhg)
249
+ MIT © [Taig Mac Carthy](https://taigmaccarthy.com/)
151
250
 
152
251
  ---
153
252
 
154
- *Built with the [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic*
253
+ _Built with the [Model Context Protocol](https://modelcontextprotocol.io/) by Anthropic_
package/dist/api.d.ts CHANGED
@@ -1,13 +1,109 @@
1
- import type { Employee, Team, Location, Contract } from './types.js';
2
- export declare function listEmployees(options?: {
3
- team_id?: number;
4
- location_id?: number;
5
- }): Promise<Employee[]>;
1
+ /**
2
+ * FactorialHR API Client
3
+ *
4
+ * Provides access to FactorialHR API endpoints with caching, pagination, and retry logic.
5
+ */
6
+ import { type PaginatedResponse, type PaginationInput } from './pagination.js';
7
+ import { type Employee, type Team, type Location, type Contract, type Leave, type LeaveType, type Allowance, type Shift, type Folder, type Document, type JobRole, type JobLevel } from './schemas.js';
8
+ import type { ListEmployeesOptions, ListLeavesOptions, ListAllowancesOptions, ListShiftsOptions, ListDocumentsOptions } from './types.js';
9
+ /**
10
+ * List all employees with optional filtering and pagination
11
+ */
12
+ export declare function listEmployees(options?: ListEmployeesOptions): Promise<PaginatedResponse<Employee>>;
13
+ /**
14
+ * Get a specific employee by ID
15
+ */
6
16
  export declare function getEmployee(id: number): Promise<Employee>;
17
+ /**
18
+ * Search employees by name or email
19
+ */
7
20
  export declare function searchEmployees(query: string): Promise<Employee[]>;
8
- export declare function listTeams(): Promise<Team[]>;
21
+ /**
22
+ * List all teams
23
+ */
24
+ export declare function listTeams(options?: PaginationInput): Promise<PaginatedResponse<Team>>;
25
+ /**
26
+ * Get a specific team by ID
27
+ */
9
28
  export declare function getTeam(id: number): Promise<Team>;
10
- export declare function listLocations(): Promise<Location[]>;
29
+ /**
30
+ * List all locations
31
+ */
32
+ export declare function listLocations(options?: PaginationInput): Promise<PaginatedResponse<Location>>;
33
+ /**
34
+ * Get a specific location by ID
35
+ */
11
36
  export declare function getLocation(id: number): Promise<Location>;
12
- export declare function listContracts(employeeId?: number): Promise<Contract[]>;
37
+ /**
38
+ * List contracts, optionally filtered by employee ID
39
+ */
40
+ export declare function listContracts(employeeId?: number, options?: PaginationInput): Promise<PaginatedResponse<Contract>>;
41
+ /**
42
+ * List leaves with optional filtering
43
+ */
44
+ export declare function listLeaves(options?: ListLeavesOptions): Promise<PaginatedResponse<Leave>>;
45
+ /**
46
+ * Get a specific leave by ID
47
+ */
48
+ export declare function getLeave(id: number): Promise<Leave>;
49
+ /**
50
+ * List all leave types
51
+ */
52
+ export declare function listLeaveTypes(): Promise<LeaveType[]>;
53
+ /**
54
+ * Get a specific leave type by ID
55
+ */
56
+ export declare function getLeaveType(id: number): Promise<LeaveType>;
57
+ /**
58
+ * List allowances with optional filtering by employee
59
+ */
60
+ export declare function listAllowances(options?: ListAllowancesOptions): Promise<PaginatedResponse<Allowance>>;
61
+ /**
62
+ * List shifts with optional filtering
63
+ */
64
+ export declare function listShifts(options?: ListShiftsOptions): Promise<PaginatedResponse<Shift>>;
65
+ /**
66
+ * Get a specific shift by ID
67
+ */
68
+ export declare function getShift(id: number): Promise<Shift>;
69
+ /**
70
+ * List all folders
71
+ */
72
+ export declare function listFolders(): Promise<Folder[]>;
73
+ /**
74
+ * Get a specific folder by ID
75
+ */
76
+ export declare function getFolder(id: number): Promise<Folder>;
77
+ /**
78
+ * List documents with optional filtering by folder
79
+ */
80
+ export declare function listDocuments(options?: ListDocumentsOptions): Promise<PaginatedResponse<Document>>;
81
+ /**
82
+ * Get a specific document by ID
83
+ */
84
+ export declare function getDocument(id: number): Promise<Document>;
85
+ /**
86
+ * List all job roles
87
+ */
88
+ export declare function listJobRoles(): Promise<JobRole[]>;
89
+ /**
90
+ * Get a specific job role by ID
91
+ */
92
+ export declare function getJobRole(id: number): Promise<JobRole>;
93
+ /**
94
+ * List all job levels
95
+ */
96
+ export declare function listJobLevels(): Promise<JobLevel[]>;
97
+ /**
98
+ * Get a specific job level by ID
99
+ */
100
+ export declare function getJobLevel(id: number): Promise<JobLevel>;
101
+ /**
102
+ * Invalidate all cached data
103
+ */
104
+ export declare function clearCache(): void;
105
+ /**
106
+ * Invalidate cached data for a specific resource type
107
+ */
108
+ export declare function invalidateCache(resourceType: string): void;
13
109
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmGrE,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAGtB;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAM/D;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAcxE;AAGD,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAGjD;AAED,wBAAsB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMvD;AAGD,wBAAsB,aAAa,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAGzD;AAED,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAM/D;AAGD,wBAAsB,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAO5E"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}