---
name: mkhr-data
description: Use when an agent needs structured real-world data centered on Japan (also U.S. corporate disclosures and global datasets) from MKHR DATA. Teaches how to discover the current sources from the machine catalog, fetch the free file-based API or call the MCP servers, and satisfy each source's license obligations. The list of sources is read from the catalog at run time, never from this file.
license: CC-BY-4.0
metadata:
  author: Makuhari Development Corporation (MKHR)
  homepage: https://data.mkhr.co.jp/
  version: "2026-09-18"
---

# MKHR DATA — using the data platform

MKHR DATA serves structured real-world data centered on Japan as **static files** (no auth, free,
plain HTTPS GET) plus two **MCP servers**. Everything below is machine-checkable against
`https://assets.data.mkhr.co.jp/v1/catalog.json` and the OpenAPI document; when this file
and those disagree, trust them.

## 1. Decide which entry point you need

| You want to… | Use |
|---|---|
| Know what sources exist, or whether one may be used for a purpose | `GET https://assets.data.mkhr.co.jp/v1/catalog.json` — or MCP `mcp.data.mkhr.co.jp/catalog` |
| Pull a whole source (bulk, reproducible, cacheable) | File API: `manifest.json` → the gzip JSONL / GeoParquet files it lists |
| Ask a small question in a conversation (a few hits, no download) | MCP `mcp.data.mkhr.co.jp/data` (`search_tenders`, `search_awards`, `get_tender_events`, `list_published_sources`, `get_bulk_access`) |
| Read the field-level definition of a file | OpenAPI: `https://assets.data.mkhr.co.jp/v1/openapi.json` (Japanese prose) or `…/v1/openapi.en.json` (same structure, English prose) |

Both MCP servers speak Streamable HTTP (JSON-RPC over POST) and need no key. Every
result carries `structuredContent` with `data`, `meta` and `license` (or `licenses` keyed by
source when a query spans sources).

## 2. Fetch pattern for the file API

```
1. GET https://assets.data.mkhr.co.jp/v1/<source_id>/manifest.json
2. Read manifest.files[] — each entry has path, sha256, bytes, rows
3. GET https://assets.data.mkhr.co.jp/<path>   (path already starts with v1/)
4. Verify sha256 if you cache; files under records/ and events/ are immutable
```

What the paths mean (the kind of file, not a processing layer):

- `records/<date or year>.jsonl.gz` — rows as observed for that slice; append-only, dated
  files never change. Read them in `manifest.date_range` order.
- `events/<date>.jsonl.gz` — row-level changes between consecutive snapshots
  (`event_type` = created / updated / closed …). Only some sources have them.
- `state/latest.jsonl.gz` — current snapshot of every key ever seen (large; KKJ is
  ~650k rows). `state/listed.jsonl.gz` (kkj, pportal) is the compact "currently listed"
  subset with search keys only — prefer it for "what is listed now".
- `geo/**/latest.parquet` — GeoParquet 1.1 (WGS84) for spatial sources.
- `codebook/*.json` — code → label tables when the source uses codes.
- `manifest.json` is a pointer, regenerated every publish; do not cache it longer than
  `Cache-Control` says (60 s; `catalog.json` is 5 min).

Use a streaming gzip reader. Do not load `state/latest.jsonl.gz` of KKJ into memory
in a constrained runtime.

## 3. License obligations — do this every time you show or republish data

Every `manifest.json` and every catalog entry has a `license` block:

- `name`, `attribution_text`, `rights_uri`, `requires_credit`, sometimes
  `modification_notice` — these are the **licensor's original wording (Japanese)**.
- `license.i18n.en` — our English translation of the same fields, for reading only.

Rules:
1. If `requires_credit` is `"yes"`, reproduce `attribution_text` **verbatim (Japanese)**
   wherever the data is shown or redistributed. The English text in `i18n.en` does not
   satisfy the obligation; you may show it next to the original.
2. If `modification_notice` exists, the license also requires stating that the data was
   processed — keep that notice with the data.
3. Verdicts per surface (raw / structured / derived / api / batch) are in the catalog:
   `allowed`, `conditional`, `prohibited`, or `unknown`. `unknown` means the licensor did
   not state it — read `rights_uri` yourself; it is not permission.
4. Data is provided as-is, without warranty, under each original publisher's terms.
   MKHR's verdicts are a ledger reading, not legal advice.

MCP shortcut: `can_i_use(source_id, surface)` and `get_attribution(source_id)` on the
catalog server return exactly these fields.

## 4. Known pitfalls (read before answering a user)

- **`status: "listed"` is not "accepting bids".** For `pportal` it means "present in
  today's inventory snapshot" (old items remain); for `kkj` it means "observed and not
  yet judged closed". Each hit carries `status_basis` and `status_as_of`; report those,
  never the word "open".
- **KKJ rows have no tender body text** — only metadata (title, organization,
  prefecture, category, deadline, document URI). Send the user to the source URL for
  the full notice.
- **`search_tenders` with `status=closed|all` on KKJ scans the full snapshot** and may
  time out on the server; use the bulk files for historical questions
  (`get_bulk_access` tells you which).
- **Search is field-limited and token-aware**: ASCII terms match on alphanumeric
  boundaries ("AI" does not hit "MAIN"), Japanese terms are substring matches. Terms are
  AND-ed. There is no synonym expansion — try Japanese wording (人工知能 as well as AI).
- **Dated files never change; the current snapshot does.** Cache `records/` and `events/`
  forever, re-fetch `state/` and `manifest.json` each run.
- Some sources publish only the latest snapshot (POI sources, monthly): there is no
  history to reconstruct; `manifest.date_range.start == end` signals this.
- The catalog has three kinds of entries: serving (has a `distribution` block — use the file
  API), catalog-only (published at the origin; no `distribution`, nothing to fetch here) and
  collected by MKHR (held, not served; no publisher or license shown). Only serving sources
  appear in the OpenAPI document.

## 5. Minimal examples

Catalog lookup (curl):
```
curl -s https://assets.data.mkhr.co.jp/v1/catalog.json | jq '.sources[] | select(.source_id=="kkj") | {name, license: .license.name, en: .i18n.en.name}'
```

Bulk read of one day of KKJ events (Python):
```python
import gzip, json, urllib.request
BASE = "https://assets.data.mkhr.co.jp/"
m = json.load(urllib.request.urlopen(BASE + "v1/kkj/manifest.json"))
day = next(f for f in m["files"] if f["path"].endswith("events/2026-09-01.jsonl.gz"))
with gzip.open(urllib.request.urlopen(BASE + day["path"]), "rt", encoding="utf-8") as fh:
    for line in fh:
        row = json.loads(line)
        ...
print(m["license"]["attribution_text"])   # show this with the data
```

MCP (any Streamable-HTTP client):
```
endpoint: https://mcp.data.mkhr.co.jp/data
tools/call search_tenders {"query": "人工知能", "source": "kkj", "limit": 5}
```

## 6. Where to look next

- Human pages: https://data.mkhr.co.jp/list (ja) · https://data.mkhr.co.jp/en/list (en) ·
  https://data.mkhr.co.jp/mcp · https://data.mkhr.co.jp/api · https://data.mkhr.co.jp/en/api
- Machine: `/v1/catalog.json`, `/v1/openapi.json`, `/v1/openapi.en.json`,
  https://data.mkhr.co.jp/llms.txt, https://data.mkhr.co.jp/.well-known/ai.json
- Contact: https://www.mkhr.co.jp/contact-us (or contact@mkhr.co.jp)
