bmkg-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 +17 -0
- package/dist/api.d.ts +7 -0
- package/dist/api.js +53 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +54 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# bmkg-mcp
|
|
2
|
+
|
|
3
|
+
Keyless BMKG Indonesia: village-level 3-hourly forecasts plus felt and latest earthquakes.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
No API key needed.
|
|
8
|
+
|
|
9
|
+
Please credit BMKG as the data source in your application (required by BMKG).
|
|
10
|
+
|
|
11
|
+
## Tools
|
|
12
|
+
|
|
13
|
+
- `get_forecast` — 3-hourly 3-day BMKG forecast for an Indonesian village by adm4 code (e.g. 31.71.03.1001 Kemayoran, Jakarta). Codes at kodewilayah.id.
|
|
14
|
+
- `get_felt_earthquakes` — Recently felt Indonesian earthquakes: magnitude, depth, location, MMI scale.
|
|
15
|
+
- `get_latest_earthquakes` — Latest Indonesian earthquakes M5+: time, coordinates, magnitude, region.
|
|
16
|
+
|
|
17
|
+
Part of [awesome-mcps](https://github.com/mrfentmen/awesome-mcps).
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare class BmkgError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare function errorMessage(e: unknown): string;
|
|
5
|
+
export declare function getForecast(adm4: string): Promise<string>;
|
|
6
|
+
export declare function getFeltEarthquakes(): Promise<string>;
|
|
7
|
+
export declare function getLatestEarthquakes(): Promise<string>;
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export class BmkgError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "BmkgError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export function errorMessage(e) {
|
|
8
|
+
return e instanceof Error ? e.message : String(e);
|
|
9
|
+
}
|
|
10
|
+
const UA = { "User-Agent": "awesome-mcps/1.0" };
|
|
11
|
+
function envStrict(name) {
|
|
12
|
+
const v = process.env[name];
|
|
13
|
+
if (!v)
|
|
14
|
+
throw new BmkgError(`Set the ${name} environment variable.`);
|
|
15
|
+
return v;
|
|
16
|
+
}
|
|
17
|
+
async function authHeaders() {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
function pretty(data) {
|
|
21
|
+
const t = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
22
|
+
return t.length > 12000 ? t.slice(0, 12000) + "\n…(truncated)" : t;
|
|
23
|
+
}
|
|
24
|
+
async function req(url, init = {}) {
|
|
25
|
+
const res = await fetch(url, { headers: { ...UA, ...(await authHeaders()), ...(init.headers ?? {}) }, ...init });
|
|
26
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
27
|
+
const data = ct.includes("json") ? await res.json() : await res.text();
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
const detail = typeof data === "string" ? data.slice(0, 300) : JSON.stringify(data).slice(0, 300);
|
|
30
|
+
throw new BmkgError(`HTTP ${res.status}: ${detail}`);
|
|
31
|
+
}
|
|
32
|
+
return data;
|
|
33
|
+
}
|
|
34
|
+
export async function getForecast(adm4) {
|
|
35
|
+
let url = `https://api.bmkg.go.id/publik/prakiraan-cuaca`;
|
|
36
|
+
const qs = new URLSearchParams();
|
|
37
|
+
qs.append("adm4", String(adm4));
|
|
38
|
+
const qstr = qs.toString();
|
|
39
|
+
if (qstr)
|
|
40
|
+
url += (url.includes('?') ? '&' : '?') + qstr;
|
|
41
|
+
const data = await req(url);
|
|
42
|
+
return pretty(data);
|
|
43
|
+
}
|
|
44
|
+
export async function getFeltEarthquakes() {
|
|
45
|
+
let url = `https://data.bmkg.go.id/DataMKG/TEWS/gempadirasakan.json`;
|
|
46
|
+
const data = await req(url);
|
|
47
|
+
return pretty(data);
|
|
48
|
+
}
|
|
49
|
+
export async function getLatestEarthquakes() {
|
|
50
|
+
let url = `https://data.bmkg.go.id/DataMKG/TEWS/gempaterkini.json`;
|
|
51
|
+
const data = await req(url);
|
|
52
|
+
return pretty(data);
|
|
53
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2
|
+
import { createServer } from "./server.js";
|
|
3
|
+
async function main() {
|
|
4
|
+
const server = createServer();
|
|
5
|
+
const transport = new StdioServerTransport();
|
|
6
|
+
await server.connect(transport);
|
|
7
|
+
console.error("MCP server running on stdio");
|
|
8
|
+
}
|
|
9
|
+
main().catch((err) => {
|
|
10
|
+
console.error("Fatal error:", err);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
});
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { errorMessage, getForecast, getFeltEarthquakes, getLatestEarthquakes, } from "./api.js";
|
|
4
|
+
const text = (t) => ({ content: [{ type: "text", text: t }] });
|
|
5
|
+
const textError = (t) => ({ content: [{ type: "text", text: t }], isError: true });
|
|
6
|
+
const READ_ONLY = { readOnlyHint: true, openWorldHint: true };
|
|
7
|
+
export function createServer() {
|
|
8
|
+
const server = new McpServer({
|
|
9
|
+
name: "bmkg-mcp",
|
|
10
|
+
version: "1.0.0",
|
|
11
|
+
});
|
|
12
|
+
server.registerTool("get_forecast", {
|
|
13
|
+
title: "Get village forecast",
|
|
14
|
+
description: "3-hourly 3-day BMKG forecast for an Indonesian village by adm4 code (e.g. 31.71.03.1001 Kemayoran, Jakarta). Codes at kodewilayah.id.",
|
|
15
|
+
inputSchema: z.object({
|
|
16
|
+
adm4: z.string().describe("Village code W.X.Y.Z"),
|
|
17
|
+
}),
|
|
18
|
+
annotations: READ_ONLY,
|
|
19
|
+
}, async ({ adm4 }) => {
|
|
20
|
+
try {
|
|
21
|
+
return text(await getForecast(adm4));
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
return textError(errorMessage(e));
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
server.registerTool("get_felt_earthquakes", {
|
|
28
|
+
title: "Get felt earthquakes",
|
|
29
|
+
description: "Recently felt Indonesian earthquakes: magnitude, depth, location, MMI scale.",
|
|
30
|
+
inputSchema: z.object({}),
|
|
31
|
+
annotations: READ_ONLY,
|
|
32
|
+
}, async ({}) => {
|
|
33
|
+
try {
|
|
34
|
+
return text(await getFeltEarthquakes());
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return textError(errorMessage(e));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
server.registerTool("get_latest_earthquakes", {
|
|
41
|
+
title: "Get latest earthquakes",
|
|
42
|
+
description: "Latest Indonesian earthquakes M5+: time, coordinates, magnitude, region.",
|
|
43
|
+
inputSchema: z.object({}),
|
|
44
|
+
annotations: READ_ONLY,
|
|
45
|
+
}, async ({}) => {
|
|
46
|
+
try {
|
|
47
|
+
return text(await getLatestEarthquakes());
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
return textError(errorMessage(e));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return server;
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bmkg-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Keyless BMKG Indonesia: village-level 3-hourly forecasts plus felt and latest earthquakes.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"mcpName": "io.github.mrfentmen/bmkg-mcp",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/mrfentmen/awesome-mcps.git"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"bmkg-mcp": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.json",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"dev": "rm -rf dist && tsc -p tsconfig.json && node dist/index.js",
|
|
22
|
+
"inspect": "npx @modelcontextprotocol/inspector node dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"mcp",
|
|
26
|
+
"bmkg",
|
|
27
|
+
"indonesia",
|
|
28
|
+
"weather",
|
|
29
|
+
"earthquake"
|
|
30
|
+
],
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
34
|
+
"zod": "^3.23.8"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"typescript": "^5.6.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=20"
|
|
42
|
+
}
|
|
43
|
+
}
|