@mrfentmen/ukg-kronos-mcp 1.0.0 → 1.0.1
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/README.md +2 -17
- package/dist/core.js +27 -18
- package/package.json +1 -1
- package/server.json +2 -2
- package/dist/gateway.d.ts +0 -14
- package/dist/gateway.js +0 -78
package/README.md
CHANGED
|
@@ -39,23 +39,8 @@ Or in an MCP client:
|
|
|
39
39
|
| `stats` | Numeric min/max/mean per field. |
|
|
40
40
|
| `format_reference` | Compact spec reference. |
|
|
41
41
|
| `sample` | A small valid example document. |
|
|
42
|
-
| `diff` |
|
|
43
|
-
| `to_json` |
|
|
44
|
-
|
|
45
|
-
<!-- paywall -->
|
|
46
|
-
## Premium tools
|
|
47
|
-
|
|
48
|
-
`diff` and `to_json` need a licence key. Their bodies run on our gateway, not
|
|
49
|
-
inside this package, so the key is what buys access. Buy one at
|
|
50
|
-
https://buy.polar.sh/polar_cl_mrO7rS5LZxpqM7oAFFEA10i9121J240U40IIj4JRZO4
|
|
51
|
-
and set it in your MCP client config:
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
"env": { "MCP_LICENSE_KEY": "polar_..." }
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Every other tool on this server stays free.
|
|
58
|
-
<!-- /paywall -->
|
|
42
|
+
| `diff` | Compare two documents. |
|
|
43
|
+
| `to_json` | Export every record as JSON. |
|
|
59
44
|
|
|
60
45
|
## Safety
|
|
61
46
|
|
package/dist/core.js
CHANGED
|
@@ -2,10 +2,8 @@ import { promises as fs } from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { errorMessage, fail, text, ToolError } from "./run.js";
|
|
5
|
-
import { GatewayError, premiumTool } from "./gateway.js";
|
|
6
5
|
const MAX_INPUT = 4_000_000;
|
|
7
6
|
const SKIP_DIRS = new Set([".git", "node_modules", "dist", "build", ".mcp-build"]);
|
|
8
|
-
const PREMIUM = new Set(["to_json", "diff"]);
|
|
9
7
|
async function readInput(input) {
|
|
10
8
|
if (input.path && input.content !== undefined)
|
|
11
9
|
throw new ToolError("Use path or content, not both");
|
|
@@ -293,21 +291,23 @@ export function registerFormatTools(server, format) {
|
|
|
293
291
|
return fail(errorMessage(error));
|
|
294
292
|
}
|
|
295
293
|
});
|
|
296
|
-
server.tool("to_json", `Export every parsed ${format.displayName} record as JSON
|
|
294
|
+
server.tool("to_json", `Export every parsed ${format.displayName} record as JSON.`, { ...sourceArgs }, async (a) => {
|
|
297
295
|
try {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
296
|
+
const { body, file } = await readInput(a);
|
|
297
|
+
const parsed = parseOrThrow(format, body);
|
|
298
|
+
return text(JSON.stringify({
|
|
299
|
+
file: file ?? null,
|
|
300
|
+
format: parsed.format,
|
|
301
|
+
meta: parsed.meta,
|
|
302
|
+
issues: parsed.issues,
|
|
303
|
+
records: parsed.records,
|
|
304
|
+
}, null, 2));
|
|
303
305
|
}
|
|
304
306
|
catch (error) {
|
|
305
|
-
if (error instanceof GatewayError)
|
|
306
|
-
return fail(error.message);
|
|
307
307
|
return fail(errorMessage(error));
|
|
308
308
|
}
|
|
309
309
|
});
|
|
310
|
-
server.tool("diff", `Compare two ${format.displayName} documents: added, removed and changed records
|
|
310
|
+
server.tool("diff", `Compare two ${format.displayName} documents: added, removed and changed records.`, {
|
|
311
311
|
leftPath: z.string().min(1).max(2_000).optional(),
|
|
312
312
|
leftContent: z.string().max(MAX_INPUT).optional(),
|
|
313
313
|
rightPath: z.string().min(1).max(2_000).optional(),
|
|
@@ -317,15 +317,24 @@ export function registerFormatTools(server, format) {
|
|
|
317
317
|
try {
|
|
318
318
|
const left = await readInput({ path: a.leftPath, content: a.leftContent, cwd: a.cwd });
|
|
319
319
|
const right = await readInput({ path: a.rightPath, content: a.rightContent, cwd: a.cwd });
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
const before = parseOrThrow(format, left.body);
|
|
321
|
+
const after = parseOrThrow(format, right.body);
|
|
322
|
+
const beforeFields = new Map(before.records.map((record) => [record.id, JSON.stringify(record.fields)]));
|
|
323
|
+
const afterFields = new Map(after.records.map((record) => [record.id, JSON.stringify(record.fields)]));
|
|
324
|
+
const added = [...afterFields.keys()].filter((id) => !beforeFields.has(id));
|
|
325
|
+
const removed = [...beforeFields.keys()].filter((id) => !afterFields.has(id));
|
|
326
|
+
const changed = [...afterFields.keys()].filter((id) => beforeFields.has(id) && beforeFields.get(id) !== afterFields.get(id));
|
|
327
|
+
return text(JSON.stringify({
|
|
328
|
+
format: before.format,
|
|
329
|
+
added: added.length,
|
|
330
|
+
removed: removed.length,
|
|
331
|
+
changed: changed.length,
|
|
332
|
+
unchanged: afterFields.size - added.length - changed.length,
|
|
333
|
+
records: { added, removed, changed },
|
|
334
|
+
issues: { left: before.issues.length, right: after.issues.length },
|
|
335
|
+
}, null, 2));
|
|
325
336
|
}
|
|
326
337
|
catch (error) {
|
|
327
|
-
if (error instanceof GatewayError)
|
|
328
|
-
return fail(error.message);
|
|
329
338
|
return fail(errorMessage(error));
|
|
330
339
|
}
|
|
331
340
|
});
|
package/package.json
CHANGED
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/mrfentmen/awesome-servers",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@mrfentmen/ukg-kronos-mcp",
|
|
14
|
-
"version": "1.0.
|
|
14
|
+
"version": "1.0.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|
package/dist/gateway.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin client for the premium gateway.
|
|
3
|
-
*
|
|
4
|
-
* Premium tool bodies run on the gateway, which checks a Polar licence key
|
|
5
|
-
* before it does any work, so removing anything here buys nothing.
|
|
6
|
-
*
|
|
7
|
-
* Set `MCP_LICENSE_KEY` to a Polar licence key. `MCP_GATEWAY_URL` overrides the
|
|
8
|
-
* endpoint, which is only useful for testing.
|
|
9
|
-
*/
|
|
10
|
-
export declare class GatewayError extends Error {
|
|
11
|
-
readonly refused: boolean;
|
|
12
|
-
constructor(message: string, refused: boolean);
|
|
13
|
-
}
|
|
14
|
-
export declare function premiumTool(tool: string, args: Record<string, unknown>): Promise<string>;
|
package/dist/gateway.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin client for the premium gateway.
|
|
3
|
-
*
|
|
4
|
-
* Premium tool bodies run on the gateway, which checks a Polar licence key
|
|
5
|
-
* before it does any work, so removing anything here buys nothing.
|
|
6
|
-
*
|
|
7
|
-
* Set `MCP_LICENSE_KEY` to a Polar licence key. `MCP_GATEWAY_URL` overrides the
|
|
8
|
-
* endpoint, which is only useful for testing.
|
|
9
|
-
*/
|
|
10
|
-
const DEFAULT_GATEWAY_URL = "https://mcp-gateway.contactae2000.workers.dev/mcp";
|
|
11
|
-
const DEFAULT_TIMEOUT_MS = 25000;
|
|
12
|
-
const USER_AGENT = "mrfentmen-mcp/1.0";
|
|
13
|
-
export class GatewayError extends Error {
|
|
14
|
-
refused;
|
|
15
|
-
constructor(message, refused) {
|
|
16
|
-
super(message);
|
|
17
|
-
this.refused = refused;
|
|
18
|
-
this.name = "GatewayError";
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export async function premiumTool(tool, args) {
|
|
22
|
-
const key = (process.env.MCP_LICENSE_KEY ?? "").trim();
|
|
23
|
-
if (!key) {
|
|
24
|
-
throw new GatewayError(`"${tool}" is a premium tool and no licence key is set. Set MCP_LICENSE_KEY in your MCP client config.`, true);
|
|
25
|
-
}
|
|
26
|
-
const url = (process.env.MCP_GATEWAY_URL ?? DEFAULT_GATEWAY_URL).trim();
|
|
27
|
-
const controller = new AbortController();
|
|
28
|
-
const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
|
|
29
|
-
let response;
|
|
30
|
-
try {
|
|
31
|
-
response = await fetch(url, {
|
|
32
|
-
method: "POST",
|
|
33
|
-
headers: {
|
|
34
|
-
"content-type": "application/json",
|
|
35
|
-
accept: "application/json",
|
|
36
|
-
"user-agent": USER_AGENT,
|
|
37
|
-
authorization: `Bearer ${key}`,
|
|
38
|
-
},
|
|
39
|
-
body: JSON.stringify({
|
|
40
|
-
jsonrpc: "2.0",
|
|
41
|
-
id: 1,
|
|
42
|
-
method: "tools/call",
|
|
43
|
-
params: { name: tool, arguments: args },
|
|
44
|
-
}),
|
|
45
|
-
signal: controller.signal,
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
catch {
|
|
49
|
-
throw new GatewayError(`"${tool}" could not reach the licence gateway. Check your connection and try again.`, false);
|
|
50
|
-
}
|
|
51
|
-
finally {
|
|
52
|
-
clearTimeout(timer);
|
|
53
|
-
}
|
|
54
|
-
if (!response.ok) {
|
|
55
|
-
throw new GatewayError(`"${tool}" could not reach the licence gateway (HTTP ${response.status}).`, false);
|
|
56
|
-
}
|
|
57
|
-
let body;
|
|
58
|
-
try {
|
|
59
|
-
body = (await response.json());
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
throw new GatewayError(`"${tool}" got an unreadable answer from the licence gateway.`, false);
|
|
63
|
-
}
|
|
64
|
-
if (body.error) {
|
|
65
|
-
throw new GatewayError(`"${tool}" was refused by the licence gateway: ${body.error.message ?? "unknown error"}`, false);
|
|
66
|
-
}
|
|
67
|
-
const result = body.result ?? {};
|
|
68
|
-
const text = (result.content ?? []).map((part) => part.text ?? "").join("\n").trim();
|
|
69
|
-
if (result.isError) {
|
|
70
|
-
if (result.structuredContent?.licenceRefusal) {
|
|
71
|
-
throw new GatewayError(text || `"${tool}" needs a valid licence key.`, true);
|
|
72
|
-
}
|
|
73
|
-
throw new GatewayError(text || `"${tool}" failed on the licence gateway.`, false);
|
|
74
|
-
}
|
|
75
|
-
if (!text)
|
|
76
|
-
throw new GatewayError(`"${tool}" returned no data.`, false);
|
|
77
|
-
return text;
|
|
78
|
-
}
|