ibronevik-taxi-mcp
# ibronevik-taxi-mcp
MCP-сервер над самописным API такси-сервиса (`/taxi/api/v1/...`). Выставляет ручки
бэка как инструменты для языковой модели.
Это **каркас** (этап 1). В нём собрана и проверена вся общая механика, на которую
дальше навешиваются ручки. Изменяющие инструменты сценария «жизненный цикл заказа»
подключаются поверх готового `TaxiClient`.
## Что уже работает
Четыре read-only инструмента, работающих **без учётной записи** (публичный
справочник прода):
| Инструмент | Назначение |
|---|---|
| `taxi_status` | доступность бэка, арендатор, версия справочника, состояние авторизации |
| `taxi_reference_list` | имена и размеры всех справочных таблиц |
| `taxi_reference_get` | содержимое указанных таблиц (`car_classes`, `currencies`, …) |
| `taxi_authenticate` | проверка входа по `TAXI_LOGIN`/`TAXI_PASSWORD` (токен не разглашается) |
## Что внутри каркаса
Три неочевидные особенности бэка, ради которых каркас и нужен, инкапсулированы
здесь один раз:
- **Тело запроса — форма, а не JSON.** Данные передаются полем `data` с
JSON-строкой (`src/core/transport.ts`). Отправка `application/json` молча
ломает поведение бэка.
- **Двухступенчатая авторизация с окном 10 секунд.**
`POST /auth/` → `auth_hash` → сразу `POST /token/` → `token` + `u_hash`
(`src/core/auth.ts`). Токен долгоживущий, кешируется; куки между шагами
тащить не нужно. На каждом запросе прикладываются `token` и `u_hash`;
при `auth_error` — один прозрачный перелогин.
- **Ответ всегда HTTP 200, код внутри тела; `304` для справочника — это успех.**
Кеш справочника по версии, обновление через `ucv`/`304` (`src/core/client.ts`).
Структура:
```
src/
config.ts конфигурация из окружения, построение URL ручки
core/
transport.ts form-кодирование, прокси-осведомлённый fetch, разбор JSON
auth.ts цепочка auth -> token, кеш token/u_hash
client.ts единый call(), разбор ответа, кеш справочника
errors.ts типы ошибок (транспорт / api / auth / запись)
mcp/
server.ts MCP stdio-сервер, регистрация инструментов
test/
smoke.ts проверка каркаса против прода (read-only, без аккаунта)
mcp-check.ts проверка MCP-слоя end-to-end настоящим MCP-клиентом
```
## Требования
- Node.js ≥ 22.6 (запускает TypeScript напрямую, без сборки).
## Установка и запуск
```bash
npm install
cp .env.example .env # при необходимости отредактировать
npm run smoke # проверка каркаса против прода (read-only)
node test/mcp-check.ts # проверка MCP-слоя end-to-end
npm start # запустить MCP-сервер (stdio)
npm run typecheck # проверка типов
```
Подключение к MCP-клиенту (stdio), пример конфигурации:
```json
{
"mcpServers": {
"ibronevik-taxi": {
"command": "node",
"args": ["/путь/к/mcp-server/src/mcp/server.ts"],
"env": { "TAXI_CONFIG": "0" }
}
}
}
```
## Тестирование: что можно и чего нельзя
- **Read-часть** (справочник) — тестируется на проде без учётной записи. Именно
это делают `smoke.ts` и `mcp-check.ts`.
- **Авторизация** — требует реальной учётной записи; замокать нельзя, шифрование
`u_hash` завязано на серверный секрет.
- **Изменяющие ручки** (сценарий 1) — на проде тестировать нельзя: каждый вызов
создаёт реальные записи в боевой базе. Нужен **тестовый тенант** (изолированная
база, где можно свободно создавать и удалять) либо тестовый аккаунт, чьи заказы
разрешено отменять. Полный цикл требует двух ролей — клиент (1) и водитель (2).
## Политика записи
Переменная `TAXI_WRITE_MODE` (`block` | `confirm` | `allow`, по умолчанию
`confirm`). Значение по умолчанию не случайно: MCP отдаёт ручки языковой модели,
а бэкенд не проверяет HTTP-метод (записи проходят и по GET). Поэтому запись по
умолчанию не должна выполняться «молча» — изменяющие инструменты проходят через
эту политику.
## Безопасность
Секретов в коде нет — вся конфигурация из окружения, `.env` не коммитится.
TDQS
Scored across 4 tools
Each tool addresses a separate concern: backend status, reference catalog listing, reference content retrieval, and authentication. There is no functional overlap between them.
All tools share the taxi_ prefix bind underscores, but the structure varies: taxi_status is a plain noun, taxi_reference_list is a noun compound, and taxi_reference_get puts the verb after the noun. This is readable but not a consistent verb_noun convention.
Four tools cover the narrow scope of the server without redundancy. Each one has a clear role, and the count feels neither thin nor bloated.
The reference data use-case is covered with list and get operations, but authenticate is a standalone capability that no other tool consumes, since all references are public. The set feels slightly incomplete around authenticated actions.