payrolla-mcp 0.2.7 → 0.2.8
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 +108 -19
- 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"),
|
|
@@ -748,7 +834,8 @@ function registerTools(server, client) {
|
|
|
748
834
|
})).describe("Array of employees"),
|
|
749
835
|
year: z2.number().describe("Calculation year"),
|
|
750
836
|
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")
|
|
837
|
+
scenario: ScenarioConfigSchema.describe("Scenario configuration with changes to apply"),
|
|
838
|
+
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
839
|
},
|
|
753
840
|
async (params) => {
|
|
754
841
|
try {
|
|
@@ -787,7 +874,8 @@ function registerTools(server, client) {
|
|
|
787
874
|
})).describe("Array of employees"),
|
|
788
875
|
year: z2.number().describe("Calculation year"),
|
|
789
876
|
periodCount: z2.number().min(1).max(12).describe("Number of months"),
|
|
790
|
-
scenarios: z2.array(ScenarioConfigSchema).min(1).describe("Array of scenarios to compare")
|
|
877
|
+
scenarios: z2.array(ScenarioConfigSchema).min(1).describe("Array of scenarios to compare"),
|
|
878
|
+
parameterEvents: z2.array(ParameterEventSchema).optional().describe("Parameter changes that take effect from a specific month onwards (applies to all employees)")
|
|
791
879
|
},
|
|
792
880
|
async (params) => {
|
|
793
881
|
try {
|
|
@@ -815,13 +903,14 @@ function registerTools(server, client) {
|
|
|
815
903
|
);
|
|
816
904
|
server.tool(
|
|
817
905
|
"get_default_params",
|
|
818
|
-
"Get default Turkish payroll parameters for a given year",
|
|
906
|
+
"Get default Turkish payroll parameters for a given year and month",
|
|
819
907
|
{
|
|
820
|
-
year: z2.number().describe("Year to get parameters for (e.g., 2025)")
|
|
908
|
+
year: z2.number().describe("Year to get parameters for (e.g., 2025)"),
|
|
909
|
+
month: z2.number().min(1).max(12).optional().describe("Month to get parameters for (1-12, default: 1)")
|
|
821
910
|
},
|
|
822
911
|
async (params) => {
|
|
823
912
|
try {
|
|
824
|
-
const result = getDefaultParams(params);
|
|
913
|
+
const result = await getDefaultParams(client, params);
|
|
825
914
|
return {
|
|
826
915
|
content: [
|
|
827
916
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payrolla-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
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.6",
|
|
51
51
|
"zod": "^3.25.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|