🏢

国土交通データプラットフォーム MCP サーバーが出てた

に公開

はじめに

tokadev です。

国土交通省が提供するオープンデータプラットフォームには、インフラ施設、PLATEAU(3D 都市モデル)、交通、地理・測量、気象・災害など、非常に多様なデータが公開されています。
これらのデータは GraphQL API でアクセスできるのですが、API 仕様を調べてクエリを書いて...という作業は少し手間がかかります。

と思っていたら公式の MCP が公開されました。

https://github.com/MLIT-DATA-PLATFORM/mlit-dpf-mcp.git

本記事では、実際に札幌市のデータを取得しながら、hands-on 形式で MCP サーバーの使い方を紹介します。


MCP サーバーとは

MCP(Model Context Protocol)は、LLM と外部サービスを接続するためのプロトコルです。

従来の方法では

  1. API 仕様を調べる
  2. GraphQL クエリを書く
  3. レスポンスをパースする

という手順が必要でしたが、MCP 経由であれば、自然言語で対話するだけでデータを取得できます。


導入

0. 準備

  • Claude Desktop
  • Python 3.10 以上
  • API キー(下記 URL から取得)

https://www.mlit-data.jp/

API キーの利用には MLIT DATA PLATFORM のアカウントの作成が必要になります。

https://www.mlit-data.jp/api_docs/usage/createAccount.html

1. リポジトリのクローン

git clone https://github.com/MLIT-DATA-PLATFORM/mlit-dpf-mcp.git
cd mlit-dpf-mcp
python -m venv .venv && source .venv/bin/activate
pip install -e .

2. 環境変数の設定

MLIT_API_KEY={your-api-key}
MLIT_BASE_URL=https://www.mlit-data.jp/api/v1/

3. Claude Desktop の設定

claude_desktop_config.json
{
  "mcpServers": {
    "mlit-dpf-mcp": {
      "command": "/path/to/.venv/bin/python",
      "args": ["/path/to/src/server.py"],
      "env": {
        "MLIT_API_KEY": "{your-api-key}",
        "MLIT_BASE_URL": "https://www.mlit-data.jp/api/v1/"
      }
    }
  }
}

設定を保存したら、Claude Desktop を再起動します。


データ取得

今回は札幌市に関連するデータを取得してみます。

1. 大通公園テレビ塔周辺の地理データ

札幌テレビ塔の近くにどんなデータがあるか教えて

MCP サーバーが自動的に以下を設定してデータを取得してくれます。

  1. さっぽろテレビ塔の位置(緯度 43.0618、経度 141.3565)を特定
  2. 適切なツール(search_by_point)を選択
  3. 妥当な検索範囲(今回は 500m)を設定
{
  "lat": 43.0618,
  "lon": 141.3565,
  "distance_m": 500,
  "size": 20
}

内部処理

質問からデータ取得までの流れを追ってみます。

1. ツール呼び出しの受信: handle_call_tool

Claude Desktop から MCP サーバーにリクエストが送信

2. パラメータ検証: model_validate
server.py
p = SearchByPoint.model_validate({
    "term": arguments.get("term"),
    "first": arguments.get("first", 0),
    "size": arguments.get("size", 50),
    "phrase_match": arguments.get("phrase_match", True),
    "prefecture_code": arguments.get("prefecture_code"),
    "point": {
        "lat": arguments["location_lat"],
        "lon": arguments["location_lon"],
        "distance": arguments["location_distance"],
    }
})
3. クライアントメソッド呼び出し: search_by_point
  1. で検証したパラメータを使用して search_by_point() を実行
server.py
data = await client.search_by_point(
    p.point.lat, p.point.lon, p.point.distance,
    term=p.term or "",
    first=p.first,
    size=p.size,
    phrase_match=p.phrase_match,
)
4. 位置フィルター作成: make_geodistance_filter,

位置情報からフィルター構造を作成、以下のような GraphQL フィルター構造が生成される。

client.py
loc = self.make_geodistance_filter(lat, lon, distance_m)

...

{
    "geoDistance": {
        "lat": 43.0618,
        "lon": 141.3565,
        "distance": 500
    }
}
5. GraphQL クエリ構築: build_search()

GraphQL クエリ文字列を構築

client.py
q = self.build_search(location_filter=loc, **kw)
6. クエリ実行: post_query()

GraphQL クエリを国土交通データプラットフォーム API に送信して結果を取得しているようです。

client.py
return await self.post_query(q)
query {
  search(
    locationFilter: {
      geoDistance: { lat: 43.0618, lon: 141.3565, distance: 500 }
    }
    first: 0
    size: 20
    phraseMatch: true
  ) {
    totalNumber
    searchResults {
      id
      title
      lat
      lon
      year
      dataset_id
      catalog_id
    }
  }
}

レスポンス

{
  "data": {
    "search": {
      "totalNumber": 386,
      "searchResults": [
        {
          "id": "28276384-89ea-488f-bd73-d98450fa4c3e",
          "title": "行政区域",
          "lat": 43.06180000000000,
          "lon": 141.35650000000000,
          "year": null,
          "dataset_id": "dpf_administrations_areas",
          "catalog_id": "dpf_area_data"
        },
        {
          "id": "8fb65cb6-a7e3-4b15-bf17-1c71be572a9f",
          "title": "人口及び世帯 5次メッシュ(250mメッシュ)",
          "lat": 43.06250000000000,
          "lon": 141.35800000000000,
          "year": "2020",
          "dataset_id": "dpf_population_data",
          "catalog_id": "dpf_statistical_data"
        },
        {
          "id": "bb69a28b-d750-4527-8d1a-ca8c2a2f010f",
          "title": "72時間実行雨量",
          "lat": 43.06100000000000,
          "lon": 141.35400000000000,
          "year": null,
          "dataset_id": "sip4d-effectiverain-e72h",
          "catalog_id": "sip4d"
        },
        {
          "id": "72fa11fb-9938-4631-8c03-1fad1303cb6d",
          "title": "札幌",
          "lat": 43.112500000000004,
          "lon": 141.35,
          "year": "2020",
          "dataset_id": "qol_mma",
          "catalog_id": "qol"
        }
      ]
    }
  }
}

取得結果

  • 総件数:386 件(半径 500m 以内)
  • 取得件数:20 件
  • データ種別:行政区域、人口統計(250m メッシュ)、災害対策(降雨量)、都市圏 QOL

2. PLATEAU 3D 都市モデル

次に、PLATEAU 3D 都市モデルデータを取得してみます。

PLATEAU は国土交通省が主導する 3D 都市モデルの整備・活用プロジェクトです。
建物の形状、道路、土地利用、災害リスクなど、様々な都市情報が 3D モデル化されています。

https://www.mlit.go.jp/plateau/

PLATEAUの3Dモデルって、どの都市のデータが使えるの?
  • レスポンス
[
  {
    "id": "1e1decc8-2fde-4638-95e4-a0f43aed677d",
    "title": "3D都市モデル(Project PLATEAU)加賀市(2021年度)",
    "dataset_id": "mlit_plateau_3d_2021",
    "catalog_id": "mlit_plateau",
    "year": "2021"
  },
  {
    "id": "60136edb-e33b-4bcd-82f4-bd3cfc284a0f",
    "title": "3D都市モデル(Project PLATEAU)太地町(2021年度)",
    "dataset_id": "mlit_plateau_3d_2021",
    "catalog_id": "mlit_plateau",
    "year": "2021"
  },
  {
    "id": "b12e4430-4a50-4cab-bafa-2c5a0a419fff",
    "title": "3D都市モデル(Project PLATEAU)海田町(2021年度)",
    "dataset_id": "mlit_plateau_3d_2021",
    "catalog_id": "mlit_plateau",
    "year": "2021"
  },
  {
    "id": "39832cf0-dcf3-485f-8c14-3d2474104b82",
    "title": "3D都市モデル(Project PLATEAU)沼津市(2021年度)",
    "dataset_id": "mlit_plateau_3d_2021",
    "catalog_id": "mlit_plateau",
    "year": "2021"
  }
]

4 つの都市の PLATEAU データが利用可能のようです。

  • 加賀市(石川県)
  • 太地町(和歌山県)
  • 海田町(広島県)
  • 沼津市(静岡県)

2.1 取得結果

  • 加賀市(石川県)の場合
    • メタデータ: 23 項目(緯度・経度、データ URL、年度など)
    • ファイル: 6 件(CityGML、カタログファイルなど)
    • データ URL: G 空間情報センターへのリンク

2.2 札幌市の PLATEAU 3D 都市モデル(公式サイトから取得)

札幌市の PLATEAU データは国土交通データプラットフォーム API には含まれていませんが、 G 空間情報センター経由で公開されていました。

札幌市の3D都市モデルのデータをダウンロードしてください。
  1. 札幌市データが API に含まれていないことを確認
  2. G 空間情報センターの公式サイトを案内
  • 概要
    • 対象地域: 札幌市(北区・中央区を含む)
    • 年度: 2020 年度
    • カバー範囲: LOD1(651.36km²)、LOD2(3.27km²)
    • ライセンス: 商用利用を含め自由に利用可能
  • データ形式
    • CityGML 2.0 - 標準的な 3D 都市モデル形式
    • 3D Tiles - Web 表示に最適化された形式
    • FBX - 3DCG ソフトウェア用
    • OBJ - 汎用 3D モデル形式
    • GeoJSON - 2D 地理情報形式

curl でのダウンロードします。
※ CityGML, 3D Tiles いずれも容量が大きいのでダウンロードする際は注意してください。

  • CityGML 形式
curl -o sapporo_citygml.zip \
  "https://assets.cms.plateau.reearth.io/assets/be/3b8cfb-5459-4f9d-b08c-fb4ab72fbdbd/01100_sapporo-shi_city_2020_citygml_7_op.zip"
  • 3D Tiles 形式
curl -o sapporo_3dtiles.zip \
  "https://assets.cms.plateau.reearth.io/assets/bc/a36c1c-5b8d-45f4-8d00-134c7e782459/01100_sapporo-shi_city_2020_3dtiles_mvt_7_op.zip"

データの中身

CityGML ファイルの構成例:

01100_sapporo-shi_city_2020_citygml_7_op/
├── udx/
│   ├── bldg/              # 建物モデル(LOD0, LOD1, LOD2)
│   ├── tran/              # 道路モデル
│   ├── luse/              # 土地利用
│   ├── urf/               # 都市計画決定情報
│   ├── fld/               # 洪水浸水想定
│   ├── tnm/               # 津波浸水想定
│   ├── lsld/              # 土砂災害警戒区域
│   ├── dem/               # 地形モデル
│   └── unrgd/             # 地下街モデル(LOD4)
├── codelists/             # コードリスト
└── schemas/               # XMLスキーマ

3. 札幌市中央区の大量データ一括取得

札幌市中央区のデータをまとめて全部取得したいです
  • レスポンス
{
  "batches": 5,
  "count": 500,
  "items": [
    {
      "id": "00045c85-23cf-445d-88a7-48e658c6d1b9",
      "title": "幌西会館(幌西まちづくりセンター)"
    },
    {
      "id": "0008e147-1c16-45f5-a824-187820ab0d7d",
      "title": "一般国道230号 札幌市 石山交差点舗装外一連工事"
    },
    {
      "id": "004c8d0a-c033-402e-8ae8-1b295c71f926",
      "title": "札幌市中央区南8条西3丁目1−7 医療法人社団 産婦人科吉尾医院"
    },
    {
      "id": "009bab3c-888f-4261-a65f-cfc1f5a92182",
      "title": "アートチャイルドケア札幌桑園"
    },
    {
      "id": "00a1301d-4e61-4cb6-9d90-a4f17b6e4a55",
      "title": "札幌市中央区北11条西13丁目1番1号 市立札幌病院"
    }
  ]
}
  • データ内訳:公共施設(20%)、医療施設(25%)、福祉施設(15%)、インフラ(30%)、その他(10%)

"batches": 5,
"count": 500,

大量のデータを取得する際は内部的にバッチ処理で一括取得しているようです。

4. 札幌市中央区の統計情報

札幌市中央区ってどれくらいデータがあるの?
  • レスポンス
{
  "data": {
    "countData": {
      "dataCount": 3201,
      "slices": null
    }
  }
}
  • 総データ件数:3,201 件
  • データセット別内訳:null(API 制約により取得不可)

このとき MCP サーバーが実行した GraphQL クエリ、「札幌市中央区」のワードから見慣れた市区町村コードが設定されています。

query {
  countData(
    attributeFilter: { attributeName: "DPF:municipality_code", is: "011011" }
    sliceSetting: { type: "dataset" }
  ) {
    dataCount
    slices {
      attributeName
      attributeValue
      dataCount
    }
  }
}

おわりに

本記事では、国土交通データプラットフォーム MCP サーバーの使い方を、札幌市のデータ取得を例に紹介しました。この MCP サーバーを使って、地域データの可視化や分析・PLATEAU データと他の統計データを組み合わせた 3D 可視化などに活用出来ると面白そうですね。

参考リンク

国土交通データプラットフォーム

https://www.mlit-data.jp/

GitHub リポジトリ

https://github.com/MLIT-DATA-PLATFORM/mlit-dpf-mcp

API ドキュメント

https://www.mlit-data.jp/api_docs/

G 空間情報センター(札幌市 PLATEAU)

https://www.geospatial.jp/ckan/dataset/plateau-01100-sapporo-shi-2020

PLATEAU 公式サイト

https://www.mlit.go.jp/plateau/

PLATEAU VIEW

https://plateauview.mlit.go.jp/

レスキューナウテックブログ

Discussion