krs-poland-mcp-server 1.0.1 → 1.0.2
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/logo.png +0 -0
- package/package.json +4 -7
- package/src/index.ts +15 -0
- package/src/server.ts +27 -0
- package/src/tools/currentExtract.ts +53 -0
- package/src/tools/fullExtract.ts +52 -0
- package/src/tools/index.ts +7 -0
- package/src/types/krs.ts +25 -0
- package/src/utils/api.ts +31 -0
- package/src/utils/format.ts +13 -0
- package/tsconfig.json +15 -0
package/logo.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "krs-poland-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "The MCP server for KRS Poland public API.",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -8,12 +8,9 @@
|
|
|
8
8
|
"build": "tsc && echo '#!/usr/bin/env node' | cat - build/index.js > build/index.tmp && mv build/index.tmp build/index.js && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
|
9
9
|
"start": "node build/index.js"
|
|
10
10
|
},
|
|
11
|
-
|
|
12
|
-
"files": ["build"],
|
|
13
|
-
"engines": { "node": ">=18.17" },
|
|
14
11
|
"repository": {
|
|
15
12
|
"type": "git",
|
|
16
|
-
"url": "git+https://github.com/pkolawa/
|
|
13
|
+
"url": "git+https://github.com/pkolawa/krs-poland-mcp-server.git"
|
|
17
14
|
},
|
|
18
15
|
"keywords": ["mcp", "poland", "krs"],
|
|
19
16
|
"author": {
|
|
@@ -26,9 +23,9 @@
|
|
|
26
23
|
"krs-poland-mcp-server": "./build/index.js"
|
|
27
24
|
},
|
|
28
25
|
"bugs": {
|
|
29
|
-
"url": "https://github.com/pkolawa/
|
|
26
|
+
"url": "https://github.com/pkolawa/krs-poland-mcp-server/issues"
|
|
30
27
|
},
|
|
31
|
-
"homepage": "https://github.com/pkolawa/
|
|
28
|
+
"homepage": "https://github.com/pkolawa/krs-poland-mcp-server#readme",
|
|
32
29
|
"dependencies": {
|
|
33
30
|
"@modelcontextprotocol/sdk": "^1.18.0",
|
|
34
31
|
"zod": "^3.25.76"
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { server } from "./server.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
|
|
4
|
+
async function main() {
|
|
5
|
+
const transport = new StdioServerTransport();
|
|
6
|
+
await server.connect(transport);
|
|
7
|
+
console.error("KRS MCP Server running on stdio");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (process.argv[1] === (import.meta && import.meta.url && new URL(import.meta.url).pathname)) {
|
|
11
|
+
main().catch((error) => {
|
|
12
|
+
console.error("Fatal error in main():", error);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
});
|
|
15
|
+
}
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { getKrsCurrentExtractTool } from "./tools/currentExtract.js";
|
|
3
|
+
import { getKrsFullExtractTool } from "./tools/fullExtract.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
|
|
6
|
+
export const server = new McpServer({
|
|
7
|
+
name: "krs",
|
|
8
|
+
version: "1.0.0",
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
server.registerTool("Get Current KRS Record",
|
|
12
|
+
{
|
|
13
|
+
title: "get-krs-current-extract",
|
|
14
|
+
description: "Get current status of the entity in KRS",
|
|
15
|
+
inputSchema: getKrsCurrentExtractTool.schema
|
|
16
|
+
},
|
|
17
|
+
(params, extra) => getKrsCurrentExtractTool.handler(params, extra)
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
server.registerTool("Get Full KRS Record",
|
|
21
|
+
{
|
|
22
|
+
title: "get-krs-full-extract",
|
|
23
|
+
description: "Get full status of the entity in KRS",
|
|
24
|
+
inputSchema: getKrsFullExtractTool.schema
|
|
25
|
+
},
|
|
26
|
+
(params, extra) => getKrsFullExtractTool.handler(params, extra)
|
|
27
|
+
);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { makeKRSRequest, buildExtractUrl } from "../utils/api.js";
|
|
3
|
+
import { KrsExtract } from "../types/krs.js";
|
|
4
|
+
import { formatCompanyHeadline } from "../utils/format.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* KRS Open API – odpis aktualny (JSON)
|
|
8
|
+
* rejestr: 'P' (przedsiębiorców) | 'S' (stowarzyszeń)
|
|
9
|
+
*/
|
|
10
|
+
export const getKrsCurrentExtractTool = {
|
|
11
|
+
description: "Pobierz odpis aktualny KRS (JSON) dla wskazanego numeru KRS i rejestru (P/S).",
|
|
12
|
+
schema: {
|
|
13
|
+
krs: z
|
|
14
|
+
.string()
|
|
15
|
+
.regex(/^[0]\d{9}$/, "Numer KRS powinien mieć 10 cyfr")
|
|
16
|
+
.describe("Numer KRS (10 cyfr)"),
|
|
17
|
+
rejestr:
|
|
18
|
+
z
|
|
19
|
+
.string()
|
|
20
|
+
.length(1, "Rejestr musi być pojedynczym znakiem: P lub S")
|
|
21
|
+
.regex(/^[pPsS]$/, "Rejestr musi być literą P lub S (wielkość liter bez znaczenia)")
|
|
22
|
+
.transform((val) => val.toUpperCase() as "P" | "S")
|
|
23
|
+
.describe("Rejestr: P – przedsiębiorców, S – stowarzyszeń (P/S, wielkość liter bez znaczenia)"),
|
|
24
|
+
},
|
|
25
|
+
handler: async (args: { krs: string; rejestr: string}, _extra: unknown) => {
|
|
26
|
+
const { krs, rejestr } = args;
|
|
27
|
+
const url = buildExtractUrl({ type: "OdpisAktualny", rejestr, krs });
|
|
28
|
+
const extract = await makeKRSRequest<KrsExtract>(url);
|
|
29
|
+
|
|
30
|
+
if (!extract) {
|
|
31
|
+
return {
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
type: "text" as const,
|
|
35
|
+
text: `Nie udało się pobrać odpisu aktualnego dla KRS ${krs} (${rejestr}).`,
|
|
36
|
+
_meta: {},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const headline = formatCompanyHeadline(extract);
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: "text" as const,
|
|
47
|
+
text: `Odpis aktualny – ${headline}\n\n(Zwrócono obiekt JSON z odpisem aktualnym)\n\n${JSON.stringify(extract, null, 2)}`,
|
|
48
|
+
_meta: {},
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { makeKRSRequest, buildExtractUrl } from "../utils/api.js";
|
|
3
|
+
import { KrsExtract } from "../types/krs.js";
|
|
4
|
+
import { formatCompanyHeadline } from "../utils/format.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* KRS Open API – odpis pełny (JSON)
|
|
8
|
+
*/
|
|
9
|
+
export const getKrsFullExtractTool = {
|
|
10
|
+
description: "Pobierz odpis pełny KRS (JSON) dla wskazanego numeru KRS i rejestru (P/S).",
|
|
11
|
+
schema: {
|
|
12
|
+
krs: z
|
|
13
|
+
.string()
|
|
14
|
+
.regex(/^[0]\d{9}$/, "Numer KRS powinien mieć 10 cyfr")
|
|
15
|
+
.describe("Numer KRS (10 cyfr)"),
|
|
16
|
+
rejestr:
|
|
17
|
+
z
|
|
18
|
+
.string()
|
|
19
|
+
.length(1, "Rejestr musi być pojedynczym znakiem: P lub S")
|
|
20
|
+
.regex(/^[pPsS]$/, "Rejestr musi być literą P lub S (wielkość liter bez znaczenia)")
|
|
21
|
+
.transform((val) => val.toUpperCase() as "P" | "S")
|
|
22
|
+
.describe("Rejestr: P – przedsiębiorców, S – stowarzyszeń (P/S, wielkość liter bez znaczenia)"),
|
|
23
|
+
},
|
|
24
|
+
handler: async (args: { krs: string; rejestr: "P" | "S" }, _extra: unknown) => {
|
|
25
|
+
const { krs, rejestr } = args;
|
|
26
|
+
const url = buildExtractUrl({ type: "OdpisPelny", rejestr, krs });
|
|
27
|
+
const extract = await makeKRSRequest<KrsExtract>(url);
|
|
28
|
+
|
|
29
|
+
if (!extract) {
|
|
30
|
+
return {
|
|
31
|
+
content: [
|
|
32
|
+
{
|
|
33
|
+
type: "text" as const,
|
|
34
|
+
text: `Nie udało się pobrać odpisu pełnego dla KRS ${krs} (${rejestr}).`,
|
|
35
|
+
_meta: {},
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const headline = formatCompanyHeadline(extract);
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text" as const,
|
|
46
|
+
text: `Odpis pełny – ${headline}\n\n(Zwrócono obiekt JSON z odpisem pełnym)\n\n${JSON.stringify(extract, null, 2)}`,
|
|
47
|
+
_meta: {},
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
package/src/types/krs.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface KrsExtract {
|
|
2
|
+
// Many providers show a top-level split into działy (1..6) for odpisy.
|
|
3
|
+
dzial1?: {
|
|
4
|
+
danePodstawowe?: {
|
|
5
|
+
numerKRS?: string;
|
|
6
|
+
nazwa?: string;
|
|
7
|
+
formaPrawna?: string;
|
|
8
|
+
siedziba?: string;
|
|
9
|
+
adres?: string;
|
|
10
|
+
nip?: string;
|
|
11
|
+
regon?: string;
|
|
12
|
+
};
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
podstawoweDane?: {
|
|
16
|
+
numerKRS?: string;
|
|
17
|
+
nazwa?: string;
|
|
18
|
+
formaPrawna?: string;
|
|
19
|
+
nip?: string;
|
|
20
|
+
regon?: string;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
};
|
|
23
|
+
nazwa?: string;
|
|
24
|
+
[key: string]: unknown; // keep schema-open for all other sections/fields
|
|
25
|
+
}
|
package/src/utils/api.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const USER_AGENT = "krs-mcp/1.0";
|
|
2
|
+
|
|
3
|
+
// Known public base for KRS Open API (REST returning JSON odpisy).
|
|
4
|
+
// If MS changes routing/domains, adjust this single constant.
|
|
5
|
+
const KRS_API_BASE = "https://api-krs.ms.gov.pl/api/krs";
|
|
6
|
+
|
|
7
|
+
type ExtractType = "OdpisAktualny" | "OdpisPelny";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Build URL for KRS odpis (OdpisAktualny/OdpisPelny).
|
|
11
|
+
* Historically documented as REST with typ odpisu + KRS + rejestr (P/S), JSON in response.
|
|
12
|
+
* Example effective form (subject to MS routing):
|
|
13
|
+
* `${KRS_API_BASE}/{typ_odpisu}/{rejestr}/{krs}`
|
|
14
|
+
*/
|
|
15
|
+
export function buildExtractUrl(opts: { type: ExtractType; rejestr: string; krs: string }): string {
|
|
16
|
+
const { type, rejestr, krs } = opts;
|
|
17
|
+
// Prefer path params; keep query fallback if needed by future changes.
|
|
18
|
+
return `${KRS_API_BASE}/${type}/${krs}?rejestr=${rejestr}&format=json`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function makeKRSRequest<T>(url: string): Promise<T | null> {
|
|
22
|
+
const headers = { Accept: "application/json" };
|
|
23
|
+
try {
|
|
24
|
+
const res = await fetch(url, { headers });
|
|
25
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
26
|
+
return (await res.json()) as T;
|
|
27
|
+
} catch (err) {
|
|
28
|
+
console.error("KRS request error:", err);
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { KrsExtract } from "../types/krs.js";
|
|
2
|
+
|
|
3
|
+
export function formatCompanyHeadline(extract: KrsExtract): string {
|
|
4
|
+
// The JSON structure differs by section; we pick common safe fields if present:
|
|
5
|
+
const krs = extract?.dzial1?.danePodstawowe?.numerKRS ?? extract?.podstawoweDane?.numerKRS ?? "KRS ?";
|
|
6
|
+
const name =
|
|
7
|
+
extract?.dzial1?.danePodstawowe?.nazwa ??
|
|
8
|
+
extract?.podstawoweDane?.nazwa ??
|
|
9
|
+
extract?.nazwa ??
|
|
10
|
+
"Nieznana nazwa";
|
|
11
|
+
|
|
12
|
+
return `${name} (KRS ${krs})`;
|
|
13
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "Node16",
|
|
5
|
+
"moduleResolution": "Node16",
|
|
6
|
+
"outDir": "./build",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"],
|
|
14
|
+
"exclude": ["node_modules"]
|
|
15
|
+
}
|