datahub-countries-mcp 1.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/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # DataHub Countries MCP
2
+
3
+ Country codes, names, and regions from the public DataHub country codes catalog. No key required.
4
+
5
+ This file is self contained. It reads public data only and never writes to the machine. All output is bounded and honest about what could not be fetched.
6
+
7
+ ## Tools
8
+
9
+
10
+ * `list` List countries.
11
+
12
+ ## Usage
13
+
14
+ ```bash
15
+ npm install
16
+ npm run build
17
+ node dist/index.js
18
+ ```
19
+
20
+ Data comes from the public DataHub country codes dataset.
package/dist/api.js ADDED
@@ -0,0 +1,67 @@
1
+ const BASE = 'https://datahub.io/core/country-codes/r/country-codes.csv';
2
+ function parseCsv(text) {
3
+ const lines = text.split(/\r?\n/).filter((l) => l.trim());
4
+ if (lines.length < 2)
5
+ return [];
6
+ const header = lines[0].split(',').map((h) => h.trim().toLowerCase());
7
+ const nameIdx = header.findIndex((h) => h.includes('common_name') || h === 'name');
8
+ const officialIdx = header.findIndex((h) => h.includes('official_name'));
9
+ const a2Idx = header.findIndex((h) => h === 'iso3166_1_alpha_2');
10
+ const a3Idx = header.findIndex((h) => h === 'iso3166_1_alpha_3');
11
+ const numIdx = header.findIndex((h) => h === 'iso3166_1_numeric');
12
+ const regionIdx = header.findIndex((h) => h.includes('region') || h.includes('continent'));
13
+ const rows = [];
14
+ for (const line of lines.slice(1)) {
15
+ // simple split respecting quoted fields
16
+ const fields = [];
17
+ let cur = '';
18
+ let inQ = false;
19
+ for (const ch of line) {
20
+ if (ch === '"')
21
+ inQ = !inQ;
22
+ else if (ch === ',' && !inQ) {
23
+ fields.push(cur);
24
+ cur = '';
25
+ }
26
+ else
27
+ cur += ch;
28
+ }
29
+ fields.push(cur);
30
+ const pick = (idx) => (idx >= 0 ? fields[idx]?.trim() ?? '' : '');
31
+ const name = pick(nameIdx) || pick(officialIdx);
32
+ if (!name)
33
+ continue;
34
+ rows.push({
35
+ name,
36
+ official: pick(officialIdx),
37
+ alpha2: pick(a2Idx).toLowerCase(),
38
+ alpha3: pick(a3Idx).toLowerCase(),
39
+ numeric: pick(numIdx),
40
+ region: pick(regionIdx),
41
+ });
42
+ }
43
+ return rows;
44
+ }
45
+ export async function list(args = {}) {
46
+ const res = await fetch(BASE, {
47
+ headers: { 'User-Agent': 'mrfentmen-datahub-countries-mcp/1.0', Accept: 'text/csv' },
48
+ signal: AbortSignal.timeout(25000),
49
+ });
50
+ if (!res.ok)
51
+ throw new Error(`DataHub returned ${res.status}`);
52
+ const rows = parseCsv(await res.text());
53
+ if (!rows.length)
54
+ return 'No country data available.';
55
+ const q = (args.search ?? '').trim().toLowerCase();
56
+ const limit = Math.max(1, Math.min(args.limit ?? 20, 100));
57
+ const filtered = q
58
+ ? rows.filter((r) => `${r.name} ${r.official} ${r.alpha2} ${r.alpha3}`.toLowerCase().includes(q))
59
+ : rows;
60
+ const shown = filtered.slice(0, limit);
61
+ if (!shown.length)
62
+ return `No countries match "${q}".`;
63
+ return `Countries (${filtered.length} matched, ${shown.length} shown):\n` +
64
+ shown
65
+ .map((r, i) => `${i + 1}. ${r.name} (${r.alpha2}) ${r.alpha3 ? `| ${r.alpha3.toUpperCase()}` : ''}${r.region ? ` | ${r.region}` : ''}`)
66
+ .join('\n');
67
+ }
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { createServer } from "./server.js";
3
+ const main = async () => { const server = createServer(); await server.connect(new StdioServerTransport()); };
4
+ main().catch((error) => { console.error("Fatal error:", error); process.exit(1); });
package/dist/server.js ADDED
@@ -0,0 +1,24 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { list } from "./api.js";
4
+ const text = (value) => ({ content: [{ type: "text", text: value }] });
5
+ const textError = (t) => ({ content: [{ type: "text", text: t }], isError: true });
6
+ const READ_ONLY = { readOnlyHint: true, openWorldHint: true };
7
+ const error = (e) => `Error: ${e instanceof Error ? e.message : String(e)}`;
8
+ export function createServer() {
9
+ const server = new McpServer({ name: "datahub-countries-mcp", version: "1.0.0" });
10
+ server.registerTool("list", {
11
+ title: "List",
12
+ description: "List countries with codes.",
13
+ inputSchema: z.object({ search: z.string().describe("Optional search terms.").optional(), limit: z.number().describe("Max results.").optional() }),
14
+ annotations: READ_ONLY,
15
+ }, async (args) => {
16
+ try {
17
+ return text(await list(args));
18
+ }
19
+ catch (e) {
20
+ return textError(error(e));
21
+ }
22
+ });
23
+ return server;
24
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "type": "module",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/mrfentmen/datahub-countries-mcp.git"
7
+ },
8
+ "bin": {
9
+ "datahub-countries-mcp": "./dist/index.js"
10
+ },
11
+ "main": "./dist/index.js",
12
+ "files": [
13
+ "dist",
14
+ "server.json",
15
+ "README.md"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "start": "node dist/index.js",
20
+ "dev": "npm run build && node dist/index.js"
21
+ },
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.0.4",
25
+ "zod": "^3.23.8"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.0.0",
29
+ "typescript": "^5.6.0"
30
+ },
31
+ "name": "datahub-countries-mcp",
32
+ "description": "Country codes, names, and regions from the DataHub country catalog. No key required.",
33
+ "mcpName": "io.github.mrfentmen/datahub-countries-mcp",
34
+ "keywords": [
35
+ "mcp",
36
+ "countries",
37
+ "codes",
38
+ "data",
39
+ "regions"
40
+ ],
41
+ "engines": {
42
+ "node": ">=20"
43
+ }
44
+ }
package/server.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.mrfentmen/datahub-countries-mcp",
4
+ "description": "Country codes, names, and regions from the DataHub country catalog. No key required.",
5
+ "repository": {
6
+ "url": "https://github.com/mrfentmen/datahub-countries-mcp",
7
+ "source": "github"
8
+ },
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "registryType": "npm",
13
+ "identifier": "datahub-countries-mcp",
14
+ "version": "1.0.0",
15
+ "transport": {
16
+ "type": "stdio"
17
+ }
18
+ }
19
+ ]
20
+ }