Урок 3 из 4 · 40 мин

Интеграции: MCP, OGC API, ArcGIS FeatureServer, встраивание и тайлы

Данные сети ТГИД отдаёт в стандартных форматах: ИИ-клиентам — по MCP (JSON-RPC), ГИС — по OGC API (Features и Processes) и ArcGIS FeatureServer, сайтам — встраиваемой картой с SDK. Карта рисует сеть векторными тайлами из martin, GeoServer и архивов PMTiles. У каждой двери свой вход и свои правила ошибок; урок объясняет, почему они такие.

Интеграции: MCP, OGC API, ArcGIS FeatureServer, встраивание и тайлы

Кратко. Данные сети ТГИД отдаёт в стандартных форматах: ИИ-клиентам — по MCP (JSON-RPC), ГИС — по OGC API (Features и Processes) и ArcGIS FeatureServer, сайтам — встраиваемой картой с SDK. Карта рисует сеть векторными тайлами из martin, GeoServer и архивов PMTiles. У каждой двери свой вход и свои правила ошибок; урок объясняет, почему они такие.

Зачем это

Чем стандартнее интерфейс, тем меньше кода у потребителя: QGIS, ArcGIS Pro, GDAL и Claude Desktop подключаются без доработок. Но каждый стандарт навязывает свои привычки — ошибки с HTTP 200, публичный ключ, отдельные номера объектов. Не зная их, легко написать клиент, который молча теряет ошибки или данные.

Карта интеграций

Дверь Протокол Вход Запись
MCP JSON-RPC 2.0 поверх POST /mcp токен scope: mcp или входа только run_calculation
OGC API — Features REST, GeoJSON в CRS84 токен входа часть 4: узлы, участки, задвижки, источники
OGC API — Processes REST, RFC 7807 при ошибке токен входа heat-hydraulic — настоящий расчёт
ArcGIS FeatureServer GeoServices REST, Esri JSON ключ scope: arcgis или входа нет
Встраиваемая карта iframe /embed + postMessage ключ встраивания tge_… нет
Тайлы MVT cookie сессии, токен или ключ встраивания нет

Слои одни и те же у OGC, FeatureServer и встраиваемой карты: участки, узлы, потребители, источники, задвижки. Участков и узлов внутренних схем (камер, ЦТП) в них нет: их нет на местности.

MCP

  • Один адрес, только POST: без потоков и сессий (GET и DELETE — 405). Методы — initialize, ping, tools/list, tools/call; пакет — до 10 сообщений.
  • Два вида ошибок. Протокол — ошибки JSON-RPC (−32700, −32600, −32601, −32602). Инструмент (неверный аргумент, нет права, превышена частота) — обычный результат с isError: true: модель читает причину и исправляет вызов, а не обрывает разговор.
  • Защита. Заголовок Origin не из CORS_ALLOWED_ORIGINS — 403: так страница чужого сайта в браузере пользователя не дотянется до /mcp (защита от DNS rebinding). Частота — 60 вызовов в минуту, run_calculation — 5 за 10 минут и только с правом «Запуск расчётов».
  • Один реестр. Инструменты описаны в tgid_mcp/tools.py; тот же реестр у помощника ИИ и у OGC Processes. Ответ — JSON без геометрии, списки обрезаны до 200, ПДн маскируются по правам владельца токена.

OGC API — Features и Processes

  • Геометрия всегда в WGS 84 в порядке «долгота, широта» (CRS84); bbox — тоже. API сам пересчитывает координаты из системы города.
  • Страницы — limit до 10 000 и ссылка rel: next, пока страница полная. Общего числа (numberMatched) нет.
  • Реальные и обобщённые потребители лежат в разных таблицах, и номера в них совпадают. Поэтому id обобщённого сдвинут на 1 000 000 000, а номер в таблице — в source_id.
  • Запись (часть 4) идёт теми же операциями, что редактор: права, журнал отмены, audit_log. Версия — ETag, If-Match с устаревшей версией — 412: два редактора не затрут правки друг друга.
  • Процессы — те же инструменты MCP. Восемь выполняются сразу, heat-hydraulic ставит задание Celery: 201 и Location на /jobs/{id}. Ошибки — application/problem+json.

ArcGIS FeatureServer

Только чтение, maxRecordCount 2000, листание — resultOffset и exceededTransferLimit. Ошибки — как у ArcGIS Server: HTTP 200 и {"error": {"code": 498 | 499 | 400, …}}. where понимает только 1=1, «поле = число» и OBJECTID IN (…): разбор в параметры вместо подстановки текста клиента исключает SQL-инъекцию. Ключ ArcGIS обычно идёт в адресе (?token=) — так подключают ArcGIS Pro. В журнале действий ТГИД он заменяется звёздочками, а за журналы своего прокси отвечает владелец прокси.

Встраиваемая карта

flowchart LR
  S["Сайт-родитель"] -- "iframe /embed?key=tge_…" --> E["Страница /embed"]
  E -- "сайт есть в ключе?" --> E
  E -- "config и тайлы по ключу" --> A["API"]
  S <-- "postMessage: команды и события" --> E
  • Ключ публичный — он виден в коде страницы. В базе хранится только его SHA-256. Сайт-родитель проверяет сама страница /embed в браузере; серверу тайлов хватает действующего ключа. Поэтому в тайлах встраивания нет имён потребителей, а слои и фрагменты ограничены ключом.
  • Сообщения. Карта принимает команды только от сайта-родителя из ключа и отвечает только ему, а не *. SDK tgid-embed.js принимает только сообщения своего iframe (event.source) с адреса карты (event.origin). Свой код без SDK должен делать те же проверки.
  • Заголовки. /embed разрешено показывать во фрейме любого сайта (frame-ancestors *), остальные страницы ТГИД — только во фрейме самого ТГИД. SDK создаёт iframe с referrerpolicy="strict-origin-when-cross-origin": без адреса сайта Firefox не сообщит родителя, и карта не откроется.

Встраиваемая карта на странице сайта

Векторные тайлы

Источник Что Как обновляется
martin участки, узлы, здания — функции tgid_mvt_* в базе города, построенные из SQL-представлений GeoServer версия rev в viewparams
GeoServer остальные слои рабочей области (кеш GWC) та же версия
PMTiles через API здания из запечённого архива версия архива ?v=
тайлы встраивания слои ключа, участки прорежены на обзорных зумах кеш 10 мин

Главная идея — ключ кеша меняется вместе с данными: веб добавляет в адрес тайла версию данных (GET /api/v1/map/data-version), после расчёта или правки она растёт. Старый тайл не отдают ни кеш сервера, ни браузер, и сбрасывать кеши вручную не нужно. Функции martin после переконвертации базы API возвращает сам.

Как сделать в ТГИД

Задания

1. Прочитайте ответ FeatureServer

Скрипт выгрузки получил ответ и записал «0 задвижек» (данные вымышленные):

GET …/FeatureServer/4/query?where=fileid%3D74&returnCountOnly=true&f=json&token=<ключ>
HTTP 200  {"error":{"code":498,"message":"…","details":[]}}

Что на самом деле произошло и как это должен был понять скрипт?

Ответ

Ключ не принят (498): истёк, чужое назначение или пароль владельца сменён. FeatureServer, как ArcGIS Server, отвечает на ошибки кодом 200, поэтому скрипт должен проверять поле error в теле, а не только HTTP-код. Нужен новый ключ ArcGIS из личного кабинета.

2. Чья ошибка в MCP

Агент получил два ответа. Какой из них должен исправить разработчик клиента, а какой — сама модель?

{"jsonrpc":"2.0","id":7,"error":{"code":-32601,"message":"Метод не поддерживается: tools/run"}}
{"jsonrpc":"2.0","id":8,"result":{"content":[{"type":"text","text":"…нет права «Запуск расчётов»"}],"isError":true}}
Ответ

Первый — ошибка протокола: клиент вызвал несуществующий метод, правильный — tools/call. Это исправляет разработчик клиента. Второй — результат инструмента: у владельца токена нет права на run_calculation. Модель должна сообщить об этом пользователю; права выдаёт администратор.

3. Найдите ошибки во встраивании

Разработчик портала встроил карту без SDK:

<iframe src="https://tgid.example/itwin-map/embed?key=tge_DEMO" referrerpolicy="no-referrer"></iframe>
<script>
  window.addEventListener('message', (e) => { if (e.data.type === 'select') showCard(e.data.id) })
  frame.contentWindow.postMessage({ source: 'tgid-embed', v: 1, type: 'setView', zoom: 15 }, '*')
</script>
Ответ
  1. referrerpolicy="no-referrer": в Firefox страница не узнает сайт-родитель и не откроет карту — нужна strict-origin-when-cross-origin. 2. Обработчик не проверяет e.origin (адрес сайта ТГИД) и e.source (окно своего iframe) — любое окно подсунет «выбор объекта». 3. Команда отправлена на '*' вместо адреса ТГИД. 4. Команда до события ready может потеряться: SDK копит такие команды сам.

4. Почему нет новых участков

Пользователь встраиваемой карты добавил участок в ТГИД, а на сайте акимата его нет даже через 5 минут на зуме 11. Ошибка ли это?

Ответ

Скорее всего нет. На обзорных зумах встраиваемая карта прореживает участки (до z12 — только Ду от 500), а тайлы этих зумов API держит в памяти 10 минут. Проверьте: виден ли участок на крупном зуме; входит ли его фрагмент в фрагменты ключа; открыт ли в ключе слой участков.

Проверьте себя

Решено 0 из 7
1Инструмент MCP вызван с неверным аргументом. Как сервер ТГИД сообщит об этом?
2Клиент FeatureServer считает ответ успешным, раз HTTP-код 200. В чём риск?
3Почему параметр where у FeatureServer понимает только 1=1, «поле = число» и OBJECTID IN (…)?
4Ключ встраивания виден в коде страницы чужого сайта. Что тогда защищает карту?
5После правки сети пользователь видит на карте новые участки, хотя кеш GWC и martin никто не сбрасывал. Почему?
6В коллекции consumers OGC API у потребителя id = 1000000005. Что это значит?
7Свой сайт принимает события встроенной карты через window.addEventListener('message', …). Какая проверка обязательна?