MCP server

Thirteen read-only tools for weather forecasts, earthquakes, severe weather warnings and region lookup. The server is hosted, so most clients need only a URL.

Connecting a client

The endpoint speaks Streamable HTTP and needs no API key: https://mcp-bmkg.dhanypedia.com/mcp

One command. Also available as a plugin: claude plugin marketplace add dhanyyudi/bmkg-api, then claude plugin install bmkg@bmkg-api.

Claude Code
claude mcp add --transport http bmkg https://mcp-bmkg.dhanypedia.com/mcp

Using a separate API instance

The local server reads from this public instance by default. The following environment variable points it at another one:

MCP client config
{
  "mcpServers": {
    "bmkg": {
      "command": "uvx",
      "args": ["bmkg-api-mcp"],
      "env": { "BMKG_API_BASE_URL": "http://localhost:8099/v1" }
    }
  }
}

Tools

Weather tools need a village-level adm4_code such as 31.74.04.1006. search_regions returns one, as does walking from provinces through regencies and districts to villages.

ToolArgumentsReturns
get_latest_earthquakenoneThe latest earthquake
get_recent_earthquakesnoneThe last 15 earthquakes of magnitude 5.0 or more
get_felt_earthquakesnoneThe last 15 earthquakes that were felt
get_nearby_earthquakeslatitude, longitude, radius_kmRecent earthquakes around a point
get_weather_forecastadm4_code3-day forecast in 3-hour steps
get_current_weatheradm4_codeForecast for the current 3-hour slot
get_weather_warningslanguageActive severe weather warnings by province
check_location_warningslocation, languageActive warnings that mention a place
search_regionsquery, limitRegions matching a name, with codes
get_provincesnoneProvinces with two-digit codes
get_districtsprovince_codeRegencies and cities of a province
get_subdistrictsdistrict_codeDistricts of a regency or city
get_villagessubdistrict_codeVillages, with adm4 codes

The server also offers seven prompts: earthquake, weather, region lookup, emergency preparedness, travel, research and daily briefing.

Response format

Every tool returns the same envelope. The status value is checked first.

Tool result
{
  "status": "success",
  "data": { "magnitude": 5.4, "region": "18 km TimurLaut Pekalongan" },
  "error": null,
  "meta": {
    "tool_version": "2.0.0",
    "operation": "get_latest_earthquake",
    "trace_id": "4b1f0c7e9d2a4f6c8e3b5a7d9c1e2f30",
    "latency_ms": 84.2,
    "source": "BMKG (Badan Meteorologi, Klimatologi, dan Geofisika)",
    "fetched_at": "2026-02-16T08:30:00Z",
    "cache_ttl_seconds": 60,
    "served_from_cache": false,
    "details": {},
    "warnings": []
  }
}

On failure, status is "error", data is null and error.code holds one of these codes:

CodeMeaning
INVALID_ARGUMENTThe API rejected an argument
NOT_FOUNDNo data for that input, for example a code without a forecast
RATE_LIMITEDToo many requests. A retry works after one minute
UPSTREAM_UNAVAILABLEBMKG or the API is temporarily unreachable
INTERNAL_ERRORAny other failure. meta.trace_id identifies it in a report

Arguments that do not match a tool's schema, such as a malformed code or a latitude out of range, are rejected by the protocol before the tool runs.

Upgrading from 1.x

  • Results are wrapped in the envelope above. What used to be the whole result is now under data.
  • Failures used to be {"error": "<text>"}. They are now status "error" with a code.
  • The debug_ping and get_cache_stats tools were removed.
  • search_regions returns 20 results by default. The limit argument raises that.