解説動画: QGIS Live Driver — MCPからQGISを操作するドライバ

qgis-plugin/qgis_live_driver/ は UIを持たない制御専用プラグインで、実行中QGISを外部から遠隔操作する面を提供する。 QWebEngineView を持たないため、WebEngineを使わない任意のQGIS環境・ 任意の他プラグインに対しても使える汎用部品。

pyeval でQGISプロセス内の任意Pythonを同期実行できるため、 PyQGISで書ける操作は全て制御可能: レイヤー/プロジェクト操作、 キャンバス、メニュー/アクション、qgis.utils.plugins 経由の他プラグイン、 Processing、QgsSettings、任意widgetの grab() による画像化 等。

さらに status/open_plugin/reload_plugin/bridge_call のnamedコマンドと、 plugin_id による他プラグインへのコマンド転送(ハブ機能)を持つ。

コマンド

コマンド 動作
pyeval QGISプロセス内で任意Pythonを同期実行し結果を返す。名前空間に iface / QgsProject / QgsApplication / driver を持つ → iface.activeLayer().name() や QgsProject.instance().mapLayers() 等で内部状態を直接取得・操作できる
screenshot iface.mapCanvas().saveAsImage(path) で地図キャンバスをPNG保存。target:"mainwindow" でQGISメインウィンドウを grab()
status pid / http_port / live_dir / ロード中プラグインと各driver・view有無を返す(生存確認・一覧用)
open_plugin plugin_id のプラグインをload+startし、open_dialog があれば開く
reload_plugin plugin_id のプラグインを sys.modules 掃除+reloadPlugin+open_dialog でホットリロード(QGIS再起動不要。自プラグイン自身も可)
bridge_call plugin_id + method + args で対象プラグインのbridgeオブジェクトをプロセス内で直接呼ぶ。WebChannelを通らないためJSレンダラー飢餓中でも動作する。JSON文字列の返値はパースして返す
eval / devreload viewを持たないため unsupported エラーを返す(ハングしない)。ただし plugin_id を付けると対象プラグインへ転送される(下記)

plugin_idルーティング(ハブ機能)

eval / pyeval / screenshot / devreload に plugin_id を付けると、 そのプラグインのLiveDriver(plugin.driver/plugin._live)へコマンドが 転送され、結果は呼び出し元の results.jsonl に返る。 つまりこのドライバのlive dir / HTTPポート1本で全プラグインを制御できる。

制御可能な範囲(pyeval)

対象 pyevalの例
レイヤー/プロジェクト iface.addVectorLayer(...) / QgsProject.instance().write()
キャンバス iface.mapCanvas().setExtent(...) / .refresh()
メニュー/ツールバー iface.actionZoomIn().trigger()、mainWindow().findChildren(QAction) で全アクション列挙・実行
他プラグイン qgis.utils.plugins["<id>"] で他プラグインのオブジェクトに到達
Processing processing.run("native:buffer", {...})
設定 QgsSettings().setValue(...)
任意ウィジェットの画像化 widget.grab().save(path)(pyeval経由)

制約:

AIアシスタントパネル

プラグイン > QGIS Live Driver > AI アシスタント で、 LLM APIを接続してQGISを対話操作するチャット型ドックを開ける (ai_panel.py + ai_client.py)。 モデルは上記コマンドに対応するツール群(qgis_pyeval / qgis_screenshot / …)をfunction callingでループ実行し、 結果をチャットに返す。リモート制御トグルOFFでも動作する (外部公開面を持たないパネル専用の内部ドライバを使う)。

AIアシスタントパネル モデル選択ドロップダウン
AIアシスタントパネルとモデル選択ドロップダウン(種別グループ+価格併記)

接続面(4系統・全て同じdispatchへ)

②③はプラグイン内蔵の http.server(stdlibのみ・127.0.0.1・空きポート自動選択)が提供。 ワーカースレッドが受けた命令は driver.submit() でメモリキューに入り、 GUIスレッドのQTimerがファイルJSONLと同じ要領で実行する(dispatchは1本に統一)。 ポート番号・live dir・認証トークン等の接続情報は ~/.qgis-live/<pid>-qgis_live_driver.json に書き出され、 クライアントはここから自動検出できる(QGIS_LIVE_REGISTRYで変更可)。 このファイルと live_dir/token はユーザ限定ACLで作成される。

flowchart TB
    subgraph EXT["外部クライアント(Harnessでも第三者アプリでも)"]
        APP["任意言語のアプリ"]
        LP["Harness: LivePage<br/>(live-drive.mjs)"]
        HTTP["MCP/RESTクライアント<br/>(curl・AIエージェント等)"]
    end

    subgraph TR["輸送層"]
        CMD["commands.jsonl"]
        RES["results.jsonl"]
        SRV["http.server 127.0.0.1:&lt;auto&gt;<br/>/mcp + /api/*"]
    end

    subgraph QGIS["常駐QGISプロセス"]
        LD["LiveDriver<br/>QTimer poll + メモリキュー"]
        CORE["iface / QgsProject /<br/>他プラグイン / widget全般"]
        LD --> CORE
    end

    APP & LP --> CMD
    HTTP --> SRV
    CMD --> LD
    SRV -->|"submit()"| LD
    LD --> RES
    RES --> APP & LP

HTTP RESTエンドポイント

エンドポイント 内容
GET /api/health {"ok":true,"pid":...,"plugin":"qgis_live_driver"}
GET /api/tools ツール仕様JSON(function calling系AIが読む用)
GET /api/status status コマンドの結果
POST /api/cmd コマンドJSONをそのままdispatch({"type":"reload_plugin","plugin_id":"..."} 等すべて有効)
POST /api/pyeval {"code":"...", "plugin_id":"..."} → {"result":...}
POST /api/eval {"expression":"...", "plugin_id":"<id>"} → 対象プラグインへ転送(plugin_id無しなら unsupported)
POST /api/screenshot {"path":"...","plugin_id":"...","target":"..."} → PNGバイナリ(Content-Type: image/png)
POST /mcp MCP JSON-RPC (initialize/tools/list/tools/call/ping)

MCP tools は qgis_<コマンド種別> の命名で、引数はコマンドJSONの キーにそのまま対応する(plugin_id / target / method / args 等)。

ファイルプロトコル詳細

ドライバが起動すると <live_base>/qgis-<pid>/qgis_live_driver/ をポーリングする (live base は WEBENGINE_LIVE_DIR env、またはメニュートグル利用時は ~/.qgis-live/run):

外部アプリ → commands.jsonl に1行1JSONを追記(各行に "token" 必須)
           → QTimer(200ms)が読み取り実行
           → results.jsonl に {id, result|error} を追記で返却

外部公開(Copilot Studio等からの接続)

/mcp は Copilot Studio が対応する Streamable HTTP transport 互換。 本プラグインは localhost限定運用を設計前提とするが、 どうしてもクラウドから接続したい場合は以下の手順が使える(非推奨・自己責任)。

1. 認証キーと公開ツールの絞り込み(QGIS起動前にenvを設定)

全エンドポイントは常にトークン照合を要求する (/api/health除く)。既定のキーは起動ごとに自動生成される セッショントークン(レジストリJSON/live_dir/token参照)。 QGIS_LIVE_API_KEY を設定するとその固定キーも追加で受け付ける。

$env:QGIS_LIVE_API_KEY = "<ランダムなキー>"
# 推奨: 公開ツールを限定。pyevalは任意コード実行のため除外
$env:QGIS_LIVE_TOOLS = "status,screenshot"
npm run live:ensure

2. HTTPSで公開(トンネル)

Copilot Studioはクラウドのため公開URLが必要。ローカルポートをトンネルする:

devtunnel host -p <port> --allow-anonymous
# または
ngrok http <port>

(TLS終端とFQDN払い出しはトンネル側が担い、認証は /mcp 側のAPIキーが担う)

3. Copilot Studio 側の設定

エージェントの Tools → Add a tool → New tool → Model Context Protocol で MCP onboarding wizardを開き、Server URL に https://<トンネルFQDN>/mcp、 認証に API key を選んで QGIS_LIVE_API_KEY の値を入力する。 generative orchestration が有効なエージェントが必要。 追加後は qgis_status 等がツールとして使える。

REST面を使う場合は Power Apps カスタムコネクタ経由で /api/* を包む方法もある。

Deploy Mode ダイアログ(開発/利用の切替)

プラグイン > QGIS Live Driver > 配置モード で、Harness管理下の deployモードをQGIS内から確認・切替できる(Harnessリポジトリ利用時のみ。 切替は内部で deploy-plugin.ps1 を起動する)。

切替はUI操作のみ(AIからの書込は不可)。bridgeメソッド deployMode() で 状態をJSONで読取専用に公開している。詳細な対応関係は 使い方・deployモード を参照。

GeoSuite共有ツールバー

管理対象プラグインのツールバー項目は GeoSuite ツールバーに 集約される(どのプラグインが先に有効化されても同じツールバーに載る find-or-create方式)。ドライバ有効中は常時表示が強制され (表示メニューからの非表示化は無効)、先頭にはモードバッジ (開発=「開発モード」の赤背景白文字、利用=歯車アイコンのみ、 5秒毎に自動更新)を載せ、 クリックすると配置モードダイアログを開く。

Harnessなしでの単独導入

Driverの利用にこのリポジトリは要らない:

# このリポジトリからなら一括deploy(任意)
powershell -ExecutionPolicy Bypass -File scripts/deploy-plugin.ps1 -Install

# 手動でも可: qgis-plugin/qgis_live_driver/ を
# python/plugins/qgis_live_driver/ へコピーし、QGISのプラグイン管理で有効化

あとは WEBENGINE_LIVE_DIR を設定した状態でQGISを起動するか、 プラグインメニューの QGIS Live Driver → リモート制御 (localhostのみ) を ONにするだけで、live dirとレジストリJSONが作られ、上記4系統のいずれでも接続できる (未設定・OFFなら何もしない無害なプラグイン)。

セキュリティ: pyeval は任意コード実行であり、本プラグインは localhost限定のリモート制御面として以下で保護される: HTTPは 127.0.0.1 バインドのみ・全エンドポイントでセッショントークン必須・ Host/Originがloopback以外なら拒否(DNSリバインド・ブラウザ経由対策)。 ファイルJSONLも各行の token 照合必須。トークンはユーザ限定ACLの ファイル(live_dir/token・レジストリJSON)にのみ保存される。 脅威モデルの境界: 同一ユーザ権限の任意プロセスはトークンを 読めるため防げない(あらゆるlocalhostサービスの限界)。 信頼境界はローカルユーザアカウントである。 詳細は セキュリティモデル を参照。