payrolla-mcp 0.2.7 → 0.2.9
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 +21 -0
- package/dist/index.js +110 -20
- package/package.json +2 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Payrolla
|
|
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/dist/index.js
CHANGED
|
@@ -57,6 +57,10 @@ function buildCustomGlobalParams(customParams) {
|
|
|
57
57
|
incomeTaxLimits: customParams.incomeTaxLimits
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
+
function buildSSICutDefList(customParams) {
|
|
61
|
+
if (!customParams?.ssiCutDefList) return void 0;
|
|
62
|
+
return customParams.ssiCutDefList;
|
|
63
|
+
}
|
|
60
64
|
async function calculatePayroll(client, input) {
|
|
61
65
|
const {
|
|
62
66
|
name,
|
|
@@ -102,7 +106,8 @@ async function calculatePayroll(client, input) {
|
|
|
102
106
|
payments,
|
|
103
107
|
calculationParams: {
|
|
104
108
|
calculateMinWageExemption: true,
|
|
105
|
-
customGlobalParams: buildCustomGlobalParams(customParams)
|
|
109
|
+
customGlobalParams: buildCustomGlobalParams(customParams),
|
|
110
|
+
ssiCutDefList: buildSSICutDefList(customParams)
|
|
106
111
|
}
|
|
107
112
|
};
|
|
108
113
|
let totalCost = 0;
|
|
@@ -214,6 +219,7 @@ async function calculateBulkPayroll(client, input) {
|
|
|
214
219
|
// src/types/index.ts
|
|
215
220
|
var DEFAULT_PARAMS_2025 = {
|
|
216
221
|
year: 2025,
|
|
222
|
+
month: 1,
|
|
217
223
|
minWage: 26005.5,
|
|
218
224
|
minWageNet: 22104.67,
|
|
219
225
|
ssiLowerLimit: 26005.5,
|
|
@@ -241,14 +247,46 @@ var DEFAULT_PARAMS_2025 = {
|
|
|
241
247
|
};
|
|
242
248
|
|
|
243
249
|
// src/tools/params.ts
|
|
244
|
-
function
|
|
245
|
-
if (
|
|
246
|
-
return DEFAULT_PARAMS_2025;
|
|
250
|
+
function getFallbackParams(year, month = 1) {
|
|
251
|
+
if (year === 2025) {
|
|
252
|
+
return { ...DEFAULT_PARAMS_2025, month };
|
|
253
|
+
}
|
|
254
|
+
return { ...DEFAULT_PARAMS_2025, year, month };
|
|
255
|
+
}
|
|
256
|
+
async function getDefaultParams(client, input) {
|
|
257
|
+
const month = input.month || 1;
|
|
258
|
+
try {
|
|
259
|
+
const response = await client.payroll.getParams(input.year, month);
|
|
260
|
+
if (response.isSuccess && response.data) {
|
|
261
|
+
const gp = response.data.globalParams;
|
|
262
|
+
const ssiCutDefs = response.data.ssiCutDefs;
|
|
263
|
+
return {
|
|
264
|
+
year: response.data.year,
|
|
265
|
+
month: response.data.month,
|
|
266
|
+
minWage: gp.minWage,
|
|
267
|
+
minWageNet: gp.minWageNet,
|
|
268
|
+
ssiLowerLimit: gp.ssi_LowerLimit,
|
|
269
|
+
ssiUpperLimit: gp.ssi_UpperLimit,
|
|
270
|
+
stampTaxRatio: gp.stampTaxRatio,
|
|
271
|
+
incomeTaxBrackets: (gp.incomeTaxLimits || []).map((b, i) => ({
|
|
272
|
+
limit: b.limit,
|
|
273
|
+
rate: b.rate,
|
|
274
|
+
description: `Bracket ${i + 1}`
|
|
275
|
+
})),
|
|
276
|
+
ssiCutDefList: ssiCutDefs ? ssiCutDefs.map((def) => ({
|
|
277
|
+
nr: def.nr,
|
|
278
|
+
name: def.name,
|
|
279
|
+
employerRatio: def.employerRatio,
|
|
280
|
+
employeeRatio: def.employeeRatio
|
|
281
|
+
})) : void 0
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
console.warn(`Failed to fetch params: ${response.message}`);
|
|
285
|
+
return getFallbackParams(input.year, month);
|
|
286
|
+
} catch (error) {
|
|
287
|
+
console.error("Error fetching params from server:", error);
|
|
288
|
+
return getFallbackParams(input.year, month);
|
|
247
289
|
}
|
|
248
|
-
return {
|
|
249
|
-
...DEFAULT_PARAMS_2025,
|
|
250
|
-
year: input.year
|
|
251
|
-
};
|
|
252
290
|
}
|
|
253
291
|
function applyScenario(defaults, scenario) {
|
|
254
292
|
const result = {};
|
|
@@ -277,9 +315,29 @@ function applyRaise(wage, raisePercent) {
|
|
|
277
315
|
}
|
|
278
316
|
return wage * (1 + raisePercent / 100);
|
|
279
317
|
}
|
|
318
|
+
function getActiveParameters(baseParams, events, currentYear, currentMonth) {
|
|
319
|
+
const activeEvents = events.filter(
|
|
320
|
+
(e) => e.year < currentYear || e.year === currentYear && e.month <= currentMonth
|
|
321
|
+
).sort((a, b) => a.year - b.year || a.month - b.month);
|
|
322
|
+
let result = { ...baseParams };
|
|
323
|
+
for (const event of activeEvents) {
|
|
324
|
+
if (event.minWage !== void 0) result.minWage = event.minWage;
|
|
325
|
+
if (event.ssiLowerLimit !== void 0)
|
|
326
|
+
result.ssiLowerLimit = event.ssiLowerLimit;
|
|
327
|
+
if (event.ssiUpperLimit !== void 0)
|
|
328
|
+
result.ssiUpperLimit = event.ssiUpperLimit;
|
|
329
|
+
if (event.stampTaxRatio !== void 0)
|
|
330
|
+
result.stampTaxRatio = event.stampTaxRatio;
|
|
331
|
+
if (event.incomeTaxLimits !== void 0)
|
|
332
|
+
result.incomeTaxLimits = event.incomeTaxLimits;
|
|
333
|
+
if (event.ssiCutDefList !== void 0)
|
|
334
|
+
result.ssiCutDefList = event.ssiCutDefList;
|
|
335
|
+
}
|
|
336
|
+
return result;
|
|
337
|
+
}
|
|
280
338
|
async function simulateBudget(client, input) {
|
|
281
|
-
const { employees, year, periodCount, scenario } = input;
|
|
282
|
-
const defaults = getDefaultParams({ year });
|
|
339
|
+
const { employees, year, periodCount, scenario, parameterEvents } = input;
|
|
340
|
+
const defaults = await getDefaultParams(client, { year });
|
|
283
341
|
const customParams = applyScenario(defaults, scenario);
|
|
284
342
|
const employeeResults = [];
|
|
285
343
|
let totalYearlyCost = 0;
|
|
@@ -308,6 +366,12 @@ async function simulateBudget(client, input) {
|
|
|
308
366
|
type: pe.type,
|
|
309
367
|
paymentType: pe.paymentType
|
|
310
368
|
}));
|
|
369
|
+
const effectiveParams = getActiveParameters(
|
|
370
|
+
customParams,
|
|
371
|
+
parameterEvents || [],
|
|
372
|
+
calcYear,
|
|
373
|
+
calcMonth
|
|
374
|
+
);
|
|
311
375
|
const result = await calculatePayroll(client, {
|
|
312
376
|
name: emp.name,
|
|
313
377
|
wage: adjustedWage,
|
|
@@ -317,7 +381,7 @@ async function simulateBudget(client, input) {
|
|
|
317
381
|
month: calcMonth,
|
|
318
382
|
periodCount: 1,
|
|
319
383
|
extraPayments: extraPayments.length > 0 ? extraPayments : void 0,
|
|
320
|
-
customParams,
|
|
384
|
+
customParams: effectiveParams,
|
|
321
385
|
cumulativeIncomeTaxBase,
|
|
322
386
|
cumulativeMinWageIncomeTaxBase,
|
|
323
387
|
transferredSSIBase1,
|
|
@@ -366,7 +430,7 @@ async function simulateBudget(client, input) {
|
|
|
366
430
|
};
|
|
367
431
|
}
|
|
368
432
|
async function compareScenarios(client, input) {
|
|
369
|
-
const { employees, year, periodCount, scenarios } = input;
|
|
433
|
+
const { employees, year, periodCount, scenarios, parameterEvents } = input;
|
|
370
434
|
if (scenarios.length === 0) {
|
|
371
435
|
throw new Error("At least one scenario is required");
|
|
372
436
|
}
|
|
@@ -376,7 +440,8 @@ async function compareScenarios(client, input) {
|
|
|
376
440
|
employees,
|
|
377
441
|
year,
|
|
378
442
|
periodCount,
|
|
379
|
-
scenario
|
|
443
|
+
scenario,
|
|
444
|
+
parameterEvents
|
|
380
445
|
});
|
|
381
446
|
results.push({
|
|
382
447
|
name: scenario.name || `Scenario ${results.length + 1}`,
|
|
@@ -605,6 +670,26 @@ var PayEventSchema = z2.object({
|
|
|
605
670
|
z2.enum(["RegularPayment", "Overtime", "SocialAid", "ExtraPay"])
|
|
606
671
|
]).optional().describe("Payment category: 1/RegularPayment, 2/Overtime, 3/SocialAid, 4/ExtraPay (default: 4)")
|
|
607
672
|
});
|
|
673
|
+
var SSICutDefSchema = z2.object({
|
|
674
|
+
nr: z2.number().describe("Order number for the cut"),
|
|
675
|
+
name: z2.string().describe("Name of the SSI cut"),
|
|
676
|
+
employerRatio: z2.number().describe("Employer contribution ratio (e.g., 0.02 for 2%)"),
|
|
677
|
+
employeeRatio: z2.number().describe("Employee contribution ratio (e.g., 0.03 for 3%)")
|
|
678
|
+
});
|
|
679
|
+
var ParameterEventSchema = z2.object({
|
|
680
|
+
month: z2.number().min(1).max(12).describe("Month when parameter change takes effect (1-12)"),
|
|
681
|
+
year: z2.number().describe("Year when parameter change takes effect"),
|
|
682
|
+
name: z2.string().optional().describe("Description of the parameter change"),
|
|
683
|
+
minWage: z2.number().optional().describe("New minimum wage"),
|
|
684
|
+
ssiLowerLimit: z2.number().optional().describe("New SSI lower limit"),
|
|
685
|
+
ssiUpperLimit: z2.number().optional().describe("New SSI upper limit"),
|
|
686
|
+
stampTaxRatio: z2.number().optional().describe("New stamp tax ratio"),
|
|
687
|
+
incomeTaxLimits: z2.array(z2.object({
|
|
688
|
+
limit: z2.number(),
|
|
689
|
+
rate: z2.number()
|
|
690
|
+
})).optional().describe("New income tax brackets"),
|
|
691
|
+
ssiCutDefList: z2.array(SSICutDefSchema).optional().describe("Custom SSI cut definitions (replaces defaults from this month onwards)")
|
|
692
|
+
});
|
|
608
693
|
var CustomParamsSchema = z2.object({
|
|
609
694
|
minWage: z2.number().optional().describe("Custom minimum wage (gross)"),
|
|
610
695
|
minWageNet: z2.number().optional().describe("Custom minimum wage (net)"),
|
|
@@ -614,7 +699,8 @@ var CustomParamsSchema = z2.object({
|
|
|
614
699
|
incomeTaxLimits: z2.array(z2.object({
|
|
615
700
|
limit: z2.number().describe("Upper limit for this bracket"),
|
|
616
701
|
rate: z2.number().describe("Tax rate (e.g., 0.15 for 15%)")
|
|
617
|
-
})).optional().describe("Custom income tax brackets")
|
|
702
|
+
})).optional().describe("Custom income tax brackets"),
|
|
703
|
+
ssiCutDefList: z2.array(SSICutDefSchema).optional().describe("Custom SSI cut definitions")
|
|
618
704
|
});
|
|
619
705
|
var EmployeeInputSchema = z2.object({
|
|
620
706
|
name: z2.string().describe("Employee name"),
|
|
@@ -647,7 +733,8 @@ function createServer() {
|
|
|
647
733
|
}
|
|
648
734
|
const payrollaClient = new PayrollaClient2({
|
|
649
735
|
apiKey,
|
|
650
|
-
timeout:
|
|
736
|
+
timeout: 12e4
|
|
737
|
+
// 2 minutes
|
|
651
738
|
});
|
|
652
739
|
const server = new McpServer({
|
|
653
740
|
name: "payrolla-mcp",
|
|
@@ -748,7 +835,8 @@ function registerTools(server, client) {
|
|
|
748
835
|
})).describe("Array of employees"),
|
|
749
836
|
year: z2.number().describe("Calculation year"),
|
|
750
837
|
periodCount: z2.number().min(1).max(12).describe("Number of months (use 12 for yearly)"),
|
|
751
|
-
scenario: ScenarioConfigSchema.describe("Scenario configuration with changes to apply")
|
|
838
|
+
scenario: ScenarioConfigSchema.describe("Scenario configuration with changes to apply"),
|
|
839
|
+
parameterEvents: z2.array(ParameterEventSchema).optional().describe("Parameter changes that take effect from a specific month onwards (applies to all employees). Unlike payEvents, these persist for subsequent months.")
|
|
752
840
|
},
|
|
753
841
|
async (params) => {
|
|
754
842
|
try {
|
|
@@ -787,7 +875,8 @@ function registerTools(server, client) {
|
|
|
787
875
|
})).describe("Array of employees"),
|
|
788
876
|
year: z2.number().describe("Calculation year"),
|
|
789
877
|
periodCount: z2.number().min(1).max(12).describe("Number of months"),
|
|
790
|
-
scenarios: z2.array(ScenarioConfigSchema).min(1).describe("Array of scenarios to compare")
|
|
878
|
+
scenarios: z2.array(ScenarioConfigSchema).min(1).describe("Array of scenarios to compare"),
|
|
879
|
+
parameterEvents: z2.array(ParameterEventSchema).optional().describe("Parameter changes that take effect from a specific month onwards (applies to all employees)")
|
|
791
880
|
},
|
|
792
881
|
async (params) => {
|
|
793
882
|
try {
|
|
@@ -815,13 +904,14 @@ function registerTools(server, client) {
|
|
|
815
904
|
);
|
|
816
905
|
server.tool(
|
|
817
906
|
"get_default_params",
|
|
818
|
-
"Get default Turkish payroll parameters for a given year",
|
|
907
|
+
"Get default Turkish payroll parameters for a given year and month",
|
|
819
908
|
{
|
|
820
|
-
year: z2.number().describe("Year to get parameters for (e.g., 2025)")
|
|
909
|
+
year: z2.number().describe("Year to get parameters for (e.g., 2025)"),
|
|
910
|
+
month: z2.number().min(1).max(12).optional().describe("Month to get parameters for (1-12, default: 1)")
|
|
821
911
|
},
|
|
822
912
|
async (params) => {
|
|
823
913
|
try {
|
|
824
|
-
const result = getDefaultParams(params);
|
|
914
|
+
const result = await getDefaultParams(client, params);
|
|
825
915
|
return {
|
|
826
916
|
content: [
|
|
827
917
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payrolla-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "MCP server for Payrolla payroll budget simulations - enables LLMs to calculate Turkish payroll and simulate budget scenarios",
|
|
5
5
|
"author": "Payrolla",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
50
|
-
"payrolla": "^0.2.
|
|
50
|
+
"payrolla": "^0.2.8",
|
|
51
51
|
"zod": "^3.25.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|