MCP-сервер карт: найти ближайшее место, перевести адрес в координаты, объяснить дорогу словами
  • Python 95%
  • Nix 5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Aleksandr 5cd97b3fee Первая версия MCP-сервера карт
Три задачи: найти ближайшее место, перевести адрес в координаты и обратно,
объяснить дорогу словами.

Главное — последнее. Навигаторская лента («через 180 м направо») человеку
неудобна: метры на глаз он не меряет, зато видит вывески. Поэтому каждый
поворот привязывается к заметному объекту у перекрёстка и к стороне, с
которой тот окажется, а названия улиц склоняются.

Источники спрятаны за общим протоколом. OSM (Nominatim, Overpass, OSRM)
работает без ключей и стоит по умолчанию; Яндекс пока заготовка — написан
по документации и вживую не проверялся.

Co-Authored-By: Eva
2026-08-10 21:04:52 +03:00
maps_mcp Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
scripts Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
.gitignore Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
AGENTS.md Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
CHANGELOG.md Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
flake.lock Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
flake.nix Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
pyproject.toml Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00
README.md Первая версия MCP-сервера карт 2026-08-10 21:04:52 +03:00

maps-mcp

MCP-сервер карт: найти ближайшее место, перевести адрес в координаты и обратно, объяснить дорогу человеческими словами.

Главное здесь — последнее. Навигаторская лента («через 180 м направо») человеку неудобна: метры на глаз он не меряет, зато видит вывески. Поэтому сервер привязывает каждый поворот к заметному объекту у перекрёстка и к стороне, с которой тот окажется:

Проезжай 500 м по улице Льва Толстого — справа будет электроника «Miele»,
    там поверни направо на Зубовскую улицу.
Едь 1,2 км по улице Пречистенка — по пути слева останется супермаркет
    «Азбука daily» — слева будет остановка Метро «Кропоткинская»,
    там возьми правее на Соймоновский проезд.
...
Ты на месте: Красная площадь. Ориентир — одежда «Bosco».

Инструменты

Инструмент Что делает
maps_search Места вокруг точки: «аптека», «ближайшая пятёрочка», «кофейня». Ближайшие первыми, с адресом, часами и расстоянием.
maps_geocode Адрес словами → координаты, разобранные по частям.
maps_reverse Координаты → адрес.
maps_route Дорога словами: directions — готовые фразы, steps — те же шаги числами.
maps_providers Какие источники подключены и какой основной.

maps_route принимает и адрес, и название места, и координаты строкой («55.7336, 37.5875»). Режимы: walk (по умолчанию), car, bike. Общественного транспорта нет — его не умеет ни один из источников.

Источники

Выбираются переменной MAPS_PROVIDER, в отдельном вызове — параметром provider.

osm (по умолчанию) — Nominatim, Overpass и OSRM. Ключей не требует. База заведений в России неровная: сетевые точки местами не размечены, часы работы есть не у всех. Публичные инстансы Overpass ограничивают частоту запросов, поэтому зеркала перебираются по очереди, а неудача не роняет маршрут — он просто описывается без ориентиров, и об этом сообщает поле note.

yandexзаготовка. Геокодер, Поиск по организациям и Router API v2 написаны по документации и вживую не проверялись: ключей не было. Прежде чем включать, сверь разбор ответов с реальными. Отдельно учти, что Router API отдаёт голую геометрию — ни манёвров, ни улиц в его ответе нет, поэтому повороты вычисляются из ломаной, а улицы дозапрашиваются обратным геокодером. Ориентиры и там берутся из Overpass: он отдаёт вывески вдоль всей ломаной одним бесплатным запросом.

Настройки

Переменная Смысл
MAPS_PROVIDER osm (по умолчанию) или yandex.
MAPS_CITY Город, к которому привязан поиск без координат.
MAPS_ORIGIN Точка «где я» (55.7336,37.5875) для поиска и старта маршрутов.
MAPS_NOMINATIM_URL, MAPS_OVERPASS_URL, MAPS_OSRM_URL Свои инстансы вместо публичных. У Overpass — список через запятую.
MAPS_USER_AGENT Кем представляться публичным сервисам.
YANDEX_API_KEY Общий ключ Яндекса; отдельные — YANDEX_GEOCODER_KEY, YANDEX_PLACES_KEY, YANDEX_ROUTER_KEY.

MAPS_ORIGIN стоит задать: без него «ближайшее» отсчитывается от центра города, а маршруту без origin просто неоткуда стартовать.

MAPS_OSRM_URL ожидает раскладку FOSSGIS — сервер отвечает по путям /routed-foot, /routed-car, /routed-bike. Демо-сервер router.project-osrm.org не подходит: у него собран только автомобильный профиль, а пеший и велосипедный он молча считает машиной.

Установка

Флейк даёт пакет, devShell и NixOS-модуль:

services.maps-mcp = {
  enable = true;
  city = "Москва";
  origin = "55.7336,37.5875";
};

Модуль лишь ставит пакет и прокидывает настройки в окружение — сам сервер работает по stdio, его запускает ядро (mcp.servers.maps.command = "maps-mcp").

Как устроено

maps_mcp/
  server.py       инструменты MCP
  narrate.py      пересказ маршрута словами: ориентиры, стороны, склейка шагов
  morph.py        склонение названий улиц («по Большому Чудову переулку»)
  geo.py          расстояния, курсы, стороны света, человеческие метры
  models.py       Place, Address, RouteStep, Route
  providers/      источники за общим протоколом

Маршрут проходит через три стадии. Источник отдаёт шаги, compress_steps склеивает те, между которыми ничего не происходит (маршрутизатор рвёт улицу на каждой смене имени), затем enrich одним запросом добирает вывески у поворотов и названия улиц для безымянных перегонов — пеший маршрут идёт по тротуарам, а тротуар в OSM почти всегда безымянный. После этого narrate собирает фразы.

Ориентир выбирается не по близости, а по заметности: сетевую вывеску видно через дорогу, безымянную парикмахерскую — только вплотную. Один объект называется в маршруте один раз, иначе всю дорогу будешь «поворачивать у той же самой Пятёрочки».

Проверка

Тестов нет — всё интересное живёт в чужих API:

nix develop -c python scripts/smoke.py

Скрипт дёргает инструменты по настоящим картам и печатает ответы: глазами видно, не уехал ли формат и не развалился ли пересказ.