Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MCP Appsでつくるチャット駆動な地図アプリ

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

MCP Appsでつくるチャット駆動な地図アプリ

Avatar for Shinsuke Nakamori

Shinsuke Nakamori

September 09, 2026

More Decks by Shinsuke Nakamori

Other Decks in Programming

Transcript

  1. 01 自己紹介 中森 紳介 所属・担当 株式会社 MIERUNE / エンジニアリングマネージャー 最近の関心

    お芋関連の期間限定商品が出始めたので、いっぱい食べたい。 でも月見バーガーも食べたい。 好きなJCT 生麦JCT 羽田から横浜方面に向かう際、以下の2択から選べる素敵なJCT → みなとみらいの「THE・横浜」な景色を見ながら走るルート → 車好きの聖地・大黒PAに寄りつつ、ベイブリッジを渡るルート ↑ 文字で読んでも、どこなのかよく分かりませんね 本名じゃない時
  2. 02 モチベーション 地図 × AI で、まず思いつくかたち 地図アプリ 地図 主役 チャット

    付け足し 既存ユーザー(既にGISを使っている人)は便利になる!...が 「地図アプリを導入していること」が入口になっているので、 新規ユーザー獲得には繋がりにくい
  3. 02 モチベーション チャットから地図を呼び出す チャット 主役 生麦JCTあたりの地図を見せて 地図 LLM が必要に応じて呼び出す 〈このまま会話が続く〉

    入口は、すでに普及しているチャットアプリ 地図アプリの導入は要らない※ 地図で見せるかどうかは、人間が思いつかなく ても LLM 側で判断できる GISを使っていない人が、地図での可視化を体験するきっかけを作れるのでは ※ とはいえ MCPサーバーを繋ぐ手間は残るので、導入の手間がゼロでは無いのが現状
  4. 03 チャットに埋め込むアプリ 好きなテンプレートで作れる 基本テンプレート 以下のフレームワークが用意されている vanillajs preact solid react vue

    svelte 実例のカタログ(20件ほど) pdf PDF.js のビューア。arxiv などの URL も開ける sheet-music ABC記法を楽譜として描画し、その場で再生できる system-monitor CPU・メモリを2秒ごとに取得してグラフ表示 map-serverというCesiumJSを使ったテンプレートも用意されているが、 今回は使い慣れている svelte-maplibre-gl を使いたかったので、Svelte のテンプレートを使用した github.com/modelcontextprotocol/ext-apps
  5. 04 仕組み MCP Apps は3つの環境で動いている ① ホスト環境(Claude Desktop) Claude(LLM) ホスト(AppBridge)

    MCPプロトコル ② MCPサーバー環境 リソース取得 UIリソース (mcp-app.html) postMessage ツール (show-map) ③ サンドボックス iframe UI (MapLibre が地図を描画) チャット欄に表示される部分
  6. 04 仕組み HTML はどうやって iframe に届くのか ① ホスト環境(Claude Desktop) Claude(LLM)

    ホスト(AppBridge) MCPプロトコル ② MCPサーバー環境 リソース取得 UIリソース (mcp-app.html) postMessage iframe と外の世界をつなぐ、唯一の橋 ツール (show-map) ③ サンドボックス iframe UI (MapLibre が地図を描画) チャット欄に表示される部分
  7. 04 仕組み 補足 UI を出しているのは LLM ではない Claude(LLM) tools/call を発行して

    データを受け取るだけ 「UI を表示しよう」とは 判断していない ホスト ツール定義の ui:// の紐づきを見て UI を取得・表示する 決定的なプログラムの処理であって LLM の判断ではない URI がズレると、データは正常に返るのに UI だけが描画されない
  8. 04 仕組み 補足 ツール実行から地図表示までの流れ Claude(LLM) — 接続時 — — 実行時

    — ホスト(AppBridge) サンドボックス iframe tools/list ツール定義:show-map には ui://map が紐づく tools/call show-map サーバーへ転送 結果 = データのみ(center/zoom の JSON) 結果を Claude へ転送(中身はホストも保持) ホストの定型処理:ツール定義に ui://map が紐づいているかを機械的にチェック → あれば UI 表示フローを起動(LLM の判断・指示ではない) resources/read ui://map(紐づいた URI を読む) HTML 文字列(mcp-app.html) HTML を流し込み iframe 生成 postMessage(保持していた入力+結果データ) ここで初めて MapLibre が地図を描画 MCPサーバー
  9. 04 仕組み 地図タイルは外部から取ってくる ① ホスト環境(Claude Desktop) Claude(LLM) ホスト(AppBridge) MCPプロトコル ②

    MCPサーバー環境 リソース取得 UIリソース (mcp-app.html) postMessage ツール (show-map) ③ サンドボックス iframe UI (MapLibre が地図を描画) チャット欄に表示される部分 fetch 外部リソース (地図タイル等)
  10. 04 仕組み サンドボックス iframe は外と繋がっていない ① ホスト環境(Claude Desktop) Claude(LLM) ホスト(AppBridge)

    MCPプロトコル ② MCPサーバー環境 リソース取得 UIリソース (mcp-app.html) postMessage ツール (show-map) ③ サンドボックス iframe UI (MapLibre が地図を描画) チャット欄に表示される部分 宣言していないオリジンへの通信は、デフォルトで全部遮断される fetch 外部リソース (地図タイル等)
  11. 04 仕組み 通信したいオリジンは自分で宣言する _meta: { ui: { csp: { connectDomains:

    [ "https://<tile-origin>", "blob:", ], resourceDomains: [ "https://<tile-origin>", "blob:", "data:", ], }, }, } 実装は合っているのに、背景地図が出ない 宣言したオリジンだけを許可するホワイトリスト方式 背景地図も外部から取得するので、宣言しないと取得できない
  12. 04 仕組み 地図の操作をフィードバックするには ① ホスト環境(Claude Desktop) ② MCPサーバー環境 ツール (show-map)

    Claude(LLM) コンテキストに反映 ホスト(AppBridge) リソース取得 updateModelContext UIリソース (mcp-app.html) ③ サンドボックス iframe UI (MapLibre が地図を描画) チャット欄に表示される部分 fetch 外部リソース (地図タイル等) 地図操作をトリガーにコンテキストを更新して、LLMにフィードバックする
  13. 05 まとめ まとめ 1 チャットの中に任意の UI を出せる MCP Apps で、会話に埋め込む地図やフォームを構築できる

    2 UI が動くのはサンドボックス環境 外の世界からは切り離された環境に置かれている 3 外との出入りは、自分で設定する タイル等の外部通信はホワイトリストで定義、 LLM へのフィードバックはイベントトリガーでコンテキスト更新