{
  "openapi": "3.1.0",
  "info": {
    "title": "Vedar — Kamchatka travel",
    "version": "2.4.0",
    "summary": "Kamchatka travel: live tours and availability, safety alerts, places, weather, stays, trip plans",
    "description": "Публичный API платформы Ведар (Камчатка) для агентов, которым недоступны MCP и A2A-клиенты. Всё без авторизации. Запись — только заявки через инструменты create_lead, create_booking_request, create_stay_request, request_charter (A2A DataPart или MCP tools/call), их подтверждает человек; мгновенной брони и оплаты нет. Данные на русском. Экстренный вызов на Камчатке — 112. Public Vedar API for Kamchatka travel agents without MCP or A2A clients: read endpoints, A2A REST binding, MCP endpoint. Requests are human-confirmed; no instant booking or payment. 中文：Vedar（维达尔，vedarai.ru）是俄罗斯堪察加半岛旅游平台的公开 API，面向无法使用 MCP 或 A2A 客户端的代理。无需认证；写操作仅限四种申请（create_lead、create_booking_request、create_stay_request、request_charter），均由人工确认，无即时预订与支付。数据为俄文。堪察加紧急电话 112。",
    "termsOfService": "https://vedarai.ru/legal/terms",
    "contact": {
      "name": "Ведар",
      "url": "https://vedarai.ru/contact"
    }
  },
  "externalDocs": {
    "description": "llms.txt — описание для моделей; /mcp — страница сервера",
    "url": "https://vedarai.ru/llms.txt"
  },
  "servers": [
    {
      "url": "https://vedarai.ru"
    }
  ],
  "tags": [
    {
      "name": "a2a",
      "description": "Agent2Agent 1.0 (и 0.3): текст Кузьмичу или точный вызов инструмента"
    },
    {
      "name": "mcp",
      "description": "Model Context Protocol по Streamable HTTP"
    },
    {
      "name": "catalog",
      "description": "Места, маршруты и туры одним каталогом"
    },
    {
      "name": "tours",
      "description": "Туры операторов и их реальная занятость"
    },
    {
      "name": "places",
      "description": "Карточка места"
    },
    {
      "name": "safety",
      "description": "Статус дня, сейсмика, вулканы"
    },
    {
      "name": "weather",
      "description": "Погода"
    },
    {
      "name": "discovery",
      "description": "Манифесты, визитки и каталоги"
    }
  ],
  "paths": {
    "/api/a2a/v1/message:send": {
      "post": {
        "tags": [
          "a2a"
        ],
        "operationId": "a2aSendMessage",
        "summary": "Вопрос Кузьмичу текстом или точный вызов инструмента (A2A REST)",
        "description": "Свободный текст (TextPart) — отвечает Кузьмич с теми же инструментами, что у MCP; точный вызов — DataPart { tool, arguments } по схемам инструментов. Задача завершается в ответе. Лимиты по адресу: текст 10 в минуту; инструменты чтения 30 в минуту, заявки 5 в час (общие с MCP). Превышение — Task со state rejected, HTTP 200.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "description": "Версия протокола. Без заголовка ответ кодируется по 0.3 (kind, строчные роли и состояния); 1.0 — обёртка { task } и состояния TASK_STATE_*.",
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3.0",
                "0.2"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/A2ASendMessageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Задача",
            "content": {
              "application/a2a+json": {
                "schema": {
                  "$ref": "#/components/schemas/A2ASendMessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Неверный запрос: INVALID_PARAMS, CONTENT_TYPE_NOT_SUPPORTED, VERSION_NOT_SUPPORTED, PARSE_ERROR; тело больше 64 КиБ — INVALID_REQUEST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          },
          "404": {
            "description": "Задача или путь не найдены",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          },
          "500": {
            "description": "Наш сбой, общий текст",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          }
        }
      }
    },
    "/api/a2a/v1/tasks/{id}": {
      "get": {
        "tags": [
          "a2a"
        ],
        "operationId": "a2aGetTask",
        "summary": "Задача по id (час в памяти процесса)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "historyLength",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "description": "Версия протокола. Без заголовка ответ кодируется по 0.3 (kind, строчные роли и состояния); 1.0 — обёртка { task } и состояния TASK_STATE_*.",
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3.0",
                "0.2"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Задача",
            "content": {
              "application/a2a+json": {
                "schema": {
                  "$ref": "#/components/schemas/A2ASendMessageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Неверный запрос: INVALID_PARAMS, CONTENT_TYPE_NOT_SUPPORTED, VERSION_NOT_SUPPORTED, PARSE_ERROR; тело больше 64 КиБ — INVALID_REQUEST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          },
          "404": {
            "description": "Задача или путь не найдены",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          }
        }
      }
    },
    "/api/a2a/v1/tasks/{id}:cancel": {
      "post": {
        "tags": [
          "a2a"
        ],
        "operationId": "a2aCancelTask",
        "summary": "Отмена задачи — всегда отказ",
        "description": "Все задачи здесь завершаются в ответе на message:send, отменять нечего: 400 TASK_NOT_CANCELABLE у существующей, 404 у неизвестной. Путь описан, чтобы клиент не ждал 200.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "description": "Версия протокола. Без заголовка ответ кодируется по 0.3 (kind, строчные роли и состояния); 1.0 — обёртка { task } и состояния TASK_STATE_*.",
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3.0",
                "0.2"
              ]
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Неверный запрос: INVALID_PARAMS, CONTENT_TYPE_NOT_SUPPORTED, VERSION_NOT_SUPPORTED, PARSE_ERROR; тело больше 64 КиБ — INVALID_REQUEST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          },
          "404": {
            "description": "Задача или путь не найдены",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/A2AError"
                }
              }
            }
          }
        }
      }
    },
    "/api/a2a/v1": {
      "get": {
        "tags": [
          "a2a",
          "discovery"
        ],
        "operationId": "a2aCardRest",
        "summary": "Визитка агента 1.0 (та же, что /.well-known/agent-card.json)",
        "responses": {
          "200": {
            "description": "Agent Card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentCard"
                }
              }
            }
          }
        }
      }
    },
    "/api/a2a": {
      "post": {
        "tags": [
          "a2a"
        ],
        "operationId": "a2aJsonRpc",
        "summary": "A2A по JSON-RPC 2.0 (SendMessage / message/send, GetTask / tasks/get, CancelTask / tasks/cancel)",
        "description": "Тот же агент, что REST; имена методов обеих версий, форма ответа — по заголовку A2A-Version. Пакеты принимаются; тело до 64 КиБ (413).",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "description": "Версия протокола. Без заголовка ответ кодируется по 0.3 (kind, строчные роли и состояния); 1.0 — обёртка { task } и состояния TASK_STATE_*.",
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3.0",
                "0.2"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "required": [
                  "jsonrpc",
                  "method"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ответ JSON-RPC: result или error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "202": {
            "description": "Уведомление без id — ответа нет"
          },
          "400": {
            "description": "Невалидный JSON или неподдерживаемая версия",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "413": {
            "description": "Тело больше 64 КиБ"
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "tags": [
          "mcp"
        ],
        "operationId": "mcpJsonRpc",
        "summary": "MCP-сервер: JSON-RPC 2.0 по Streamable HTTP (initialize, tools/list, tools/call, ping)",
        "description": "Анонимно, без сессий. Версии протокола: 2025-06-18, 2025-03-26, 2024-11-05 (заголовок MCP-Protocol-Version проверяется, если есть). Лимиты по адресу на вызов инструмента: чтение 30 в минуту, заявки 5 в час. Пакет — до 20 сообщений, тело — до 64 КиБ. Отказ инструмента — result с isError: true и HTTP 200; неизвестный инструмент — error -32602 с data.available.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/JsonRpcRequest"
                  },
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/JsonRpcRequest"
                    },
                    "maxItems": 20
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ответ JSON-RPC (или массив для пакета)",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/JsonRpcResponse"
                    },
                    {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/JsonRpcResponse"
                      }
                    }
                  ]
                }
              }
            }
          },
          "202": {
            "description": "Уведомление или пакет из одних уведомлений"
          },
          "400": {
            "description": "Невалидный JSON, пустой пакет, неподдерживаемая версия",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "413": {
            "description": "Тело больше 64 КиБ"
          }
        }
      },
      "get": {
        "tags": [
          "mcp",
          "discovery"
        ],
        "operationId": "mcpInfo",
        "summary": "Сведения о сервере и список инструментов со схемами",
        "description": "С Accept: text/event-stream — 405 (потока событий нет, только POST).",
        "responses": {
          "200": {
            "description": "Сервер и инструменты",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpServerInfo"
                }
              }
            }
          },
          "405": {
            "description": "Запрошен поток событий"
          }
        }
      }
    },
    "/api/mcp/server-card": {
      "get": {
        "tags": [
          "mcp",
          "discovery"
        ],
        "operationId": "mcpServerCard",
        "summary": "Карточка сервера (расширение MCP Server Card)",
        "responses": {
          "200": {
            "description": "Карточка",
            "content": {
              "application/mcp-server-card+json": {
                "schema": {
                  "$ref": "#/components/schemas/McpServerCard"
                }
              }
            }
          },
          "304": {
            "description": "Не изменилась (If-None-Match)"
          }
        }
      }
    },
    "/api/routes": {
      "get": {
        "tags": [
          "catalog"
        ],
        "operationId": "listCatalog",
        "summary": "Каталог мест, маршрутов и туров с поиском и фильтрами",
        "description": "Поиск q — подстрока по названию и описанию. Фильтр по радиусу работает только при трёх параметрах near_lat, near_lng, radius_km сразу. Неизвестные параметры отбрасываются.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Слова запроса",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Род записи",
            "schema": {
              "type": "string",
              "enum": [
                "place",
                "route",
                "tour"
              ]
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Точное равенство",
            "schema": {
              "type": "string",
              "maxLength": 60
            }
          },
          {
            "name": "location_type",
            "in": "query",
            "required": false,
            "description": "Тип места",
            "schema": {
              "type": "string",
              "maxLength": 60
            }
          },
          {
            "name": "activity_type",
            "in": "query",
            "required": false,
            "description": "Тип активности",
            "schema": {
              "type": "string",
              "maxLength": 60
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Страница",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Размер страницы",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2000,
              "default": 24
            }
          },
          {
            "name": "hasCoords",
            "in": "query",
            "required": false,
            "description": "Только с координатами (действует только true)",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Порядок",
            "schema": {
              "type": "string",
              "enum": [
                "title",
                "recent",
                "price_asc",
                "price_desc",
                "recommended",
                "navigable"
              ],
              "default": "title"
            }
          },
          {
            "name": "difficulty",
            "in": "query",
            "required": false,
            "description": "Сложность",
            "schema": {
              "type": "string",
              "enum": [
                "easy",
                "medium",
                "hard"
              ]
            }
          },
          {
            "name": "price_min",
            "in": "query",
            "required": false,
            "description": "Цена от",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "price_max",
            "in": "query",
            "required": false,
            "description": "Цена до",
            "schema": {
              "type": "number",
              "minimum": 0
            }
          },
          {
            "name": "near_lat",
            "in": "query",
            "required": false,
            "description": "Центр радиуса",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "near_lng",
            "in": "query",
            "required": false,
            "description": "Центр радиуса",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "radius_km",
            "in": "query",
            "required": false,
            "description": "Радиус",
            "schema": {
              "type": "number",
              "minimum": 1,
              "maximum": 1000
            }
          },
          {
            "name": "has_waypoints",
            "in": "query",
            "required": false,
            "description": "Только маршруты с двумя и более путевыми точками",
            "schema": {
              "type": "string",
              "enum": [
                "true"
              ]
            }
          },
          {
            "name": "brief",
            "in": "query",
            "required": false,
            "description": "Описание первой строкой до 200 знаков",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Страница каталога",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogResponse"
                }
              }
            }
          },
          "400": {
            "description": "Неверные параметры запроса",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "503": {
            "description": "Каталог не прочитался",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/tours": {
      "get": {
        "tags": [
          "tours"
        ],
        "operationId": "listTours",
        "summary": "Туры операторов на витрине",
        "description": "Живая занятость по датам — GET /api/tours/{id}/slots или инструмент get_tour_availability. Заявка на тур — инструмент create_booking_request (A2A/MCP), подтверждает оператор.",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Тип активности (русские значения; английские алиасы fishing, volcanoes, bears и подобные принимаются)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Подстрока по названию и описанию",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Не больше 50",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Смещение",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Список; при сбое — пустой список с degraded: true",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToursResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/tours/{id}": {
      "get": {
        "tags": [
          "tours"
        ],
        "operationId": "getTour",
        "summary": "Карточка тура",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Числовой id тура (operator_tours.id)",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Тур",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TourDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "Тура нет или он не на витрине",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Сбой",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/tours/{id}/slots": {
      "get": {
        "tags": [
          "tours"
        ],
        "operationId": "getTourSlots",
        "summary": "Свободные даты тура с местами (реальная занятость)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Даты",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TourSlotsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Тура нет или он не на витрине",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Сбой",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/places/{id}": {
      "get": {
        "tags": [
          "places"
        ],
        "operationId": "getPlace",
        "summary": "Карточка места: факты, безопасность как свойство места, маршруты через него, туры к нему",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "places.ark_id (UUID) — он же id у kind=place в каталоге",
            "schema": {
              "type": "string",
              "minLength": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Место",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PlaceDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "Некорректный id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "404": {
            "description": "Места нет",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Сбой",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/safety-status": {
      "get": {
        "tags": [
          "safety"
        ],
        "operationId": "safetyStatus",
        "summary": "Статус дня: есть ли тревога и какой силы",
        "responses": {
          "200": {
            "description": "Статус или «данные недоступны»",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SafetyStatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/safety/seismic": {
      "get": {
        "tags": [
          "safety"
        ],
        "operationId": "seismic",
        "summary": "Толчки: лента КБГС РАН / USGS или окно по часам",
        "parameters": [
          {
            "name": "hours",
            "in": "query",
            "required": false,
            "description": "Окно в часах из external_alerts; без параметра — лента источника",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 72
            }
          },
          {
            "name": "fresh",
            "in": "query",
            "required": false,
            "description": "Обойти кэш (не чаще раза в 20 с на процесс)",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "События",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SeismicResponse"
                }
              }
            }
          },
          "400": {
            "description": "hours вне 1..72",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SeismicError"
                }
              }
            }
          },
          "502": {
            "description": "Источник недоступен",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SeismicError"
                }
              }
            }
          }
        }
      }
    },
    "/api/safety/volcanic": {
      "get": {
        "tags": [
          "safety"
        ],
        "operationId": "volcanic",
        "summary": "Вулканы: события за 7 суток и повышенные статусы",
        "responses": {
          "200": {
            "description": "События и статусы; при сбое — пусто с полем error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VolcanicResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/safety/weather": {
      "get": {
        "tags": [
          "safety",
          "weather"
        ],
        "operationId": "safetyWeather",
        "summary": "Погода экрана безопасности (Петропавловск-Камчатский)",
        "responses": {
          "200": {
            "description": "Сводка строками",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SafetyWeather"
                }
              }
            }
          },
          "502": {
            "description": "Прогноз не получен",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/weather": {
      "get": {
        "tags": [
          "weather"
        ],
        "operationId": "weather",
        "summary": "Погода и прогноз по координатам",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "description": "Широта",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "lng",
            "in": "query",
            "required": true,
            "description": "Долгота",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "location",
            "in": "query",
            "required": false,
            "description": "Подпись места в ответе",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "provider",
            "in": "query",
            "required": false,
            "description": "Предпочтительный провайдер; при отказе идут остальные",
            "schema": {
              "type": "string",
              "enum": [
                "yandex",
                "openMeteo",
                "openWeatherMap",
                "weatherApi"
              ],
              "default": "yandex"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Погода",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeatherResponse"
                }
              }
            }
          },
          "400": {
            "description": "Нет координат или они не числа",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                }
              }
            }
          },
          "500": {
            "description": "Сбой",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "const": false
                    },
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Ни один провайдер не ответил",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "unavailable",
                    "error"
                  ],
                  "properties": {
                    "success": {
                      "const": false
                    },
                    "unavailable": {
                      "const": true
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/mcp.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "mcpManifest",
        "summary": "Манифест MCP: эндпоинт, каталоги, варианты подключения, A2A, инструменты",
        "responses": {
          "200": {
            "description": "Манифест",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/agent-card.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "agentCard",
        "summary": "Визитка A2A 1.0",
        "responses": {
          "200": {
            "description": "Agent Card",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentCard"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/agent.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "agentCardLegacy",
        "summary": "Визитка A2A 0.3",
        "responses": {
          "200": {
            "description": "Agent Card 0.3",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentCard"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/ai-catalog.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "aiCatalog",
        "summary": "AI Catalog домена",
        "responses": {
          "200": {
            "description": "Каталог",
            "content": {
              "application/ai-catalog+json": {
                "schema": {
                  "$ref": "#/components/schemas/AiCatalog"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/api-catalog": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "apiCatalog",
        "summary": "Каталог API по RFC 9727 (linkset)",
        "responses": {
          "200": {
            "description": "Linkset",
            "content": {
              "application/linkset+json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiCatalog"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "openapi",
        "summary": "Этот документ",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "application/vnd.oai.openapi+json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": [
          "discovery"
        ],
        "operationId": "llmsTxt",
        "summary": "Описание платформы для моделей и агентов",
        "responses": {
          "200": {
            "description": "Текст",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "const": false
          },
          "error": {
            "type": "string",
            "description": "Текст для человека, по-русски"
          }
        }
      },
      "CatalogItem": {
        "type": "object",
        "description": "Запись каталога. У kind=place поле id — places.ark_id, его принимает GET /api/places/{id}. geometry — метаданные из payload, не трек для навигации.",
        "required": [
          "id",
          "kind",
          "title",
          "description",
          "hazards",
          "hasRealImage"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "Ключ дедупликации, не адрес страницы"
          },
          "urlSlug": {
            "type": [
              "string",
              "null"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "place",
              "route",
              "tour"
            ]
          },
          "category": {
            "type": [
              "string",
              "null"
            ]
          },
          "locationType": {
            "type": [
              "string",
              "null"
            ]
          },
          "activityType": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "imageUrl": {
            "type": "string",
            "description": "Относительный путь; ключа нет, если картинки нет"
          },
          "lat": {
            "type": [
              "number",
              "null"
            ]
          },
          "lng": {
            "type": [
              "number",
              "null"
            ]
          },
          "sourceUrl": {
            "type": [
              "string",
              "null"
            ]
          },
          "sourceName": {
            "type": [
              "string",
              "null"
            ]
          },
          "priceFrom": {
            "type": [
              "number",
              "null"
            ]
          },
          "season": {
            "type": [
              "string",
              "null"
            ]
          },
          "difficulty": {
            "type": [
              "string",
              "null"
            ]
          },
          "durationDays": {
            "type": [
              "number",
              "null"
            ]
          },
          "bestMonths": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "integer"
            }
          },
          "geometry": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "type": {
                "type": "string"
              },
              "coordinates": {
                "type": "array",
                "items": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "volcanoStatus": {
            "type": [
              "string",
              "null"
            ]
          },
          "hasRealImage": {
            "type": "boolean"
          },
          "hazards": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "volcano_activity",
                "bears_active",
                "high_difficulty",
                "permit_required",
                "weather_risk"
              ]
            }
          },
          "isOpen": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "lineGrade": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "surveyed",
              "sketch",
              "unknown",
              "points_only",
              "none",
              null
            ],
            "description": "Только у kind=route: откуда линия"
          },
          "onRoute": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Только у kind=place"
          }
        }
      },
      "CatalogResponse": {
        "type": "object",
        "required": [
          "success",
          "data",
          "meta"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogItem"
            }
          },
          "meta": {
            "type": "object",
            "required": [
              "total",
              "page",
              "limit",
              "pages"
            ],
            "properties": {
              "total": {
                "type": "integer"
              },
              "page": {
                "type": "integer"
              },
              "limit": {
                "type": "integer"
              },
              "pages": {
                "type": "integer"
              }
            }
          }
        }
      },
      "TourListItem": {
        "type": "object",
        "description": "Тур оператора на витрине. Числа из numeric-колонок приходят числами после parseFloat; id — строка (bigint).",
        "required": [
          "id",
          "name",
          "description",
          "price",
          "currency",
          "images",
          "isActive"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "shortDescription": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "description": "activity_type оператора"
          },
          "difficulty": {
            "type": "string"
          },
          "duration": {
            "type": "number"
          },
          "price": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "season": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "От нуля до двух дат: начало и конец сезона"
          },
          "coordinates": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "[lat, lng] или []"
          },
          "requirements": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "included": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notIncluded": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "maxGroupSize": {
            "type": "integer"
          },
          "minGroupSize": {
            "type": "integer"
          },
          "rating": {
            "type": [
              "number",
              "null"
            ]
          },
          "reviewCount": {
            "type": "integer"
          },
          "isActive": {
            "type": "boolean"
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Относительные пути; не пуст — есть запасная обложка"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "sourceUrl": {
            "type": "null"
          },
          "sourceName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Имя оператора"
          },
          "source": {
            "const": "tour"
          }
        }
      },
      "ToursResponse": {
        "type": "object",
        "description": "Ошибок 4xx/5xx у списка нет: любой сбой отвечает 200 с пустым списком и degraded: true.",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "data": {
            "type": "object",
            "required": [
              "tours",
              "pagination"
            ],
            "properties": {
              "tours": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TourListItem"
                }
              },
              "pagination": {
                "type": "object",
                "required": [
                  "total",
                  "limit",
                  "offset",
                  "hasMore"
                ],
                "properties": {
                  "total": {
                    "type": "integer"
                  },
                  "limit": {
                    "type": "integer"
                  },
                  "offset": {
                    "type": "integer"
                  },
                  "hasMore": {
                    "type": "boolean"
                  }
                }
              }
            }
          },
          "degraded": {
            "const": true,
            "description": "Есть только при сбое: данных нет, это не «туров нет»"
          }
        }
      },
      "TourDetail": {
        "type": "object",
        "description": "Карточка тура. Поля category, duration, season, coordinates, requirements, maxGroupSize и minGroupSize здесь константы (колонок нет): adventure, 0, [], [], [], 20, 1. Программа, что взять и правила безопасности — через инструмент get_tour_details (A2A/MCP) или fetch(tour:<id>).",
        "required": [
          "id",
          "name",
          "description",
          "price",
          "currency",
          "images"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "shortDescription": {
            "type": "string"
          },
          "category": {
            "const": "adventure"
          },
          "difficulty": {
            "type": "string"
          },
          "duration": {
            "const": 0
          },
          "price": {
            "type": "number"
          },
          "currency": {
            "type": "string"
          },
          "season": {
            "type": "array",
            "maxItems": 0
          },
          "coordinates": {
            "type": "array",
            "maxItems": 0
          },
          "requirements": {
            "type": "array",
            "maxItems": 0
          },
          "included": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notIncluded": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "maxGroupSize": {
            "const": 20
          },
          "minGroupSize": {
            "const": 1
          },
          "rating": {
            "type": [
              "number",
              "null"
            ]
          },
          "reviewCount": {
            "type": "integer"
          },
          "isActive": {
            "type": "boolean"
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "locationName": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "routeId": {
            "type": [
              "string",
              "null"
            ]
          },
          "route": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "category": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "lat": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "lng": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "sourceUrl": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "operator": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "rating": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          }
        }
      },
      "TourDetailResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "data": {
            "$ref": "#/components/schemas/TourDetail"
          }
        }
      },
      "TourSlotsResponse": {
        "type": "object",
        "description": "Только даты со свободными местами, от сегодня и не дальше года, до 400 строк. Пустой массив у существующего тура — свободных дат нет.",
        "required": [
          "success",
          "slots"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "slots": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "date",
                "available_slots",
                "booked_slots",
                "free_slots"
              ],
              "properties": {
                "date": {
                  "type": "string",
                  "format": "date"
                },
                "available_slots": {
                  "type": "integer"
                },
                "booked_slots": {
                  "type": "integer"
                },
                "free_slots": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "PlaceDetailResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "data": {
            "type": "object",
            "description": "Карточка места. Полный состав полей шире перечисленного: безопасность (safety), статус вулкана, реалтайм, маршруты через место, туры к нему, отзывы, соседи.",
            "required": [
              "id",
              "name",
              "lat",
              "lng"
            ],
            "additionalProperties": true,
            "properties": {
              "id": {
                "type": "string",
                "description": "places.ark_id"
              },
              "name": {
                "type": "string"
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "descriptionSource": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "essence": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "category": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "locationType": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "lat": {
                "type": "number"
              },
              "lng": {
                "type": "number"
              },
              "zone": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "district": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "photoUrl": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "images": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "photoCount": {
                "type": "integer"
              },
              "bestSeason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "accessInfo": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "safety": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "source — type_template | manual | unknown | null: значения шаблона фактом не считаются",
                "properties": {
                  "source": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "enum": [
                      "type_template",
                      "manual",
                      "unknown",
                      null
                    ]
                  },
                  "hazardTypes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "nearestMedicalKm": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "registrationRequired": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "satCommunicatorRequired": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  }
                }
              },
              "volcanoStatus": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true
              },
              "realtime": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true
              },
              "routes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "slug": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "title": {
                      "type": "string"
                    },
                    "linkKind": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "tours": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "basePrice": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "operatorName": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "reviews": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "rating": {
                      "type": "number"
                    },
                    "comment": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "authorName": {
                      "type": "string"
                    },
                    "createdAt": {
                      "type": "string"
                    }
                  }
                }
              },
              "nearby": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "distanceKm": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SafetyStatusResponse": {
        "type": "object",
        "description": "Всегда 200. При недоступном источнике — data.unavailable: true и нули; клиент обязан проверять unavailable, а не читать нули как «тихо».",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "data": {
            "oneOf": [
              {
                "type": "object",
                "required": [
                  "hasAlert",
                  "maxSeverity",
                  "activeCount",
                  "source"
                ],
                "properties": {
                  "hasAlert": {
                    "type": "boolean"
                  },
                  "maxSeverity": {
                    "type": "number"
                  },
                  "activeCount": {
                    "type": "integer"
                  },
                  "topTitle": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "topType": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "dataUpdatedAt": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "source": {
                    "type": "string"
                  },
                  "feedCount": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "feedTitles": {
                    "type": [
                      "array",
                      "null"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "feedBasis": {
                    "type": [
                      "array",
                      "null"
                    ],
                    "items": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "title": {
                          "type": "string"
                        },
                        "url": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "recognized": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              },
              {
                "type": "object",
                "required": [
                  "unavailable",
                  "hasAlert",
                  "maxSeverity",
                  "activeCount",
                  "source"
                ],
                "properties": {
                  "unavailable": {
                    "const": true
                  },
                  "hasAlert": {
                    "const": false
                  },
                  "maxSeverity": {
                    "const": 0
                  },
                  "activeCount": {
                    "const": 0
                  },
                  "topTitle": {
                    "type": "null"
                  },
                  "topType": {
                    "type": "null"
                  },
                  "dataUpdatedAt": {
                    "type": "null"
                  },
                  "source": {
                    "type": "string"
                  }
                }
              }
            ]
          }
        }
      },
      "SeismicResponse": {
        "type": "object",
        "description": "Без параметра hours — лента КБГС РАН или USGS (до 15 событий за 48 ч); с hours — толчки из external_alerts за окно, до 500.",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "magnitude",
                "time"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "magnitude": {
                  "type": "number"
                },
                "place": {
                  "type": "string"
                },
                "time": {
                  "type": "integer",
                  "description": "Unix-время в миллисекундах"
                },
                "depth": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "lat": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "lng": {
                  "type": [
                    "number",
                    "null"
                  ]
                }
              }
            }
          },
          "source": {
            "type": "string",
            "enum": [
              "kbgsras",
              "usgs",
              "external_alerts"
            ]
          },
          "hours": {
            "type": "integer"
          },
          "updatedAt": {
            "type": "string"
          },
          "checkedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "fromCache": {
            "type": "boolean"
          }
        }
      },
      "SeismicError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "events": {
            "type": "array",
            "maxItems": 0
          },
          "source": {
            "type": "string"
          }
        }
      },
      "VolcanicResponse": {
        "type": "object",
        "description": "До 20 событий за 7 суток. Сбой основного запроса тоже отвечает 200: events пуст, checked_at null и есть поле error.",
        "required": [
          "events",
          "statuses"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "title",
                "severity",
                "created_at",
                "active"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "severity": {
                  "type": "integer"
                },
                "affected_zones": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "created_at": {
                  "type": "string",
                  "format": "date-time"
                },
                "expires_at": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "source_url": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "active": {
                  "type": "boolean"
                }
              }
            }
          },
          "checked_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "statuses": {
            "type": "object",
            "properties": {
              "elevated": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "name",
                    "color"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "color": {
                      "type": "string",
                      "enum": [
                        "yellow",
                        "orange",
                        "red"
                      ]
                    },
                    "summary": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "ash_height_m": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "observed_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "source_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "total": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "green": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "updated_at": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "error": {
            "type": "string",
            "description": "Только при сбое"
          }
        }
      },
      "SafetyWeather": {
        "type": "object",
        "description": "Погода экрана безопасности для Петропавловска-Камчатского, готовыми русскими строками.",
        "required": [
          "place",
          "today",
          "stale"
        ],
        "properties": {
          "place": {
            "type": "string"
          },
          "now": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "label": {
                "type": "string",
                "enum": [
                  "ночь",
                  "утро",
                  "день",
                  "вечер"
                ]
              },
              "temp": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "precip": {
                "type": "string"
              },
              "wind": {
                "type": "string"
              }
            }
          },
          "today": {
            "type": "object",
            "properties": {
              "temp": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "precip": {
                "type": "string"
              },
              "wind": {
                "type": "string"
              },
              "sky": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "checked_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "stale": {
            "type": "boolean"
          }
        }
      },
      "WeatherResponse": {
        "type": "object",
        "required": [
          "success",
          "data"
        ],
        "properties": {
          "success": {
            "const": true
          },
          "data": {
            "type": "object",
            "description": "Сводка по провайдеру. Ветер — км/ч; давление зависит от провайдера: Open-Meteo даёт гПа, остальные — мм рт. ст. Поля windGust, dewPoint, sunrise, sunset, moonPhase, hourlyForecast, alerts есть не у всех провайдеров.",
            "additionalProperties": true,
            "required": [
              "location",
              "temperature",
              "condition",
              "forecast",
              "safetyLevel",
              "lastUpdated"
            ],
            "properties": {
              "location": {
                "type": "string"
              },
              "temperature": {
                "type": "number"
              },
              "feelsLike": {
                "type": "number"
              },
              "condition": {
                "type": "string"
              },
              "conditionText": {
                "type": "string"
              },
              "humidity": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "windSpeed": {
                "type": "number",
                "description": "км/ч"
              },
              "windDirection": {
                "type": "number"
              },
              "pressure": {
                "type": "number"
              },
              "visibility": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "uvIndex": {
                "type": "number"
              },
              "cloudCover": {
                "type": "number"
              },
              "forecast": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "temperature": {
                      "type": "object",
                      "properties": {
                        "min": {
                          "type": "number"
                        },
                        "max": {
                          "type": "number"
                        }
                      }
                    },
                    "condition": {
                      "type": "string"
                    },
                    "conditionText": {
                      "type": "string"
                    },
                    "precipitation": {
                      "type": "number"
                    },
                    "precipitationProbability": {
                      "type": "number"
                    },
                    "windSpeed": {
                      "type": "number"
                    },
                    "humidity": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  }
                }
              },
              "lastUpdated": {
                "type": "string"
              },
              "safetyLevel": {
                "type": "string",
                "enum": [
                  "excellent",
                  "good",
                  "moderate",
                  "difficult",
                  "dangerous"
                ]
              },
              "recommendations": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "clothingAdvice": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "tourAdvice": {
                "type": "string"
              },
              "comfortIndex": {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              }
            }
          }
        }
      },
      "A2ATextPart": {
        "type": "object",
        "required": [
          "text"
        ],
        "properties": {
          "kind": {
            "const": "text"
          },
          "text": {
            "type": "string",
            "maxLength": 8000
          }
        }
      },
      "A2AToolCallPart": {
        "type": "object",
        "description": "Точный вызов инструмента: data.tool и data.arguments по схеме инструмента (те же схемы, что tools/list у MCP). Если такая часть есть, текстовые части не читаются.",
        "required": [
          "data"
        ],
        "properties": {
          "kind": {
            "const": "data"
          },
          "data": {
            "$ref": "#/components/schemas/ToolCallData"
          }
        }
      },
      "ToolCallData": {
        "description": "Один из публичных инструментов с его аргументами. Записывающие (create_lead, create_booking_request, create_stay_request, request_charter) — заявки, которые подтверждает человек; им нужен consent: true.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/ToolCall_get_tours"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_tour_details"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_guardian_context"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_place_info"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_weather"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_volcano_status"
          },
          {
            "$ref": "#/components/schemas/ToolCall_search_accommodations"
          },
          {
            "$ref": "#/components/schemas/ToolCall_search_transfers"
          },
          {
            "$ref": "#/components/schemas/ToolCall_search_gear"
          },
          {
            "$ref": "#/components/schemas/ToolCall_safety_status"
          },
          {
            "$ref": "#/components/schemas/ToolCall_make_trip_plan"
          },
          {
            "$ref": "#/components/schemas/ToolCall_edit_trip_plan"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_tour_availability"
          },
          {
            "$ref": "#/components/schemas/ToolCall_search"
          },
          {
            "$ref": "#/components/schemas/ToolCall_fetch"
          },
          {
            "$ref": "#/components/schemas/ToolCall_get_request_status"
          },
          {
            "$ref": "#/components/schemas/ToolCall_create_lead"
          },
          {
            "$ref": "#/components/schemas/ToolCall_create_booking_request"
          },
          {
            "$ref": "#/components/schemas/ToolCall_create_stay_request"
          },
          {
            "$ref": "#/components/schemas/ToolCall_request_charter"
          }
        ]
      },
      "ToolCall_get_tours": {
        "type": "object",
        "description": "Kamchatka tour catalogue: list operator tours with prices and dates; live availability via get_tour_availability. For one tour in depth use get_tour_details. Получить активные туры из платформы Ведар с ценами и датами. Используй когда турист спрашивает о конкретных турах или программах.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_tours"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "activity_type": {
                "type": "string",
                "description": "Activity filter, free text (Russian works best): fishing, volcanoes, bears, geysers, trekking. Фильтр по типу: рыбалка, вулканы, медведи, гейзеры, трекинг и т.д.",
                "examples": [
                  "вулканы"
                ]
              },
              "page": {
                "type": "string",
                "description": "Catalogue page, 7 tours each, starting at 1; the reply ends with the page count and the next page. Страница каталога по 7 туров, с 1. В конце ответа сказано, сколько страниц и какая следующая.",
                "examples": [
                  "2"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_get_tour_details": {
        "type": "object",
        "description": "One Kamchatka tour in depth: program, what is included, what to bring, safety notes. To list or search tours use get_tours. Полные детали КОНКРЕТНОГО тура: описание, программа, точка сбора и логистика (старт/забор), что входит и не входит, что взять с собой. Используй ВСЕГДА, когда турист спрашивает про конкретный тур — что там по программе, откуда стартуют, где сбор, что взять. Не выдумывай эти детали сам — бери отсюда.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_tour_details"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Tour title or a keyword from it. Название тура или ключевое слово (например «сплав», «Быстрая», «рыбалка»)",
                "examples": [
                  "рыбалка"
                ]
              }
            },
            "required": [
              "name"
            ]
          }
        }
      },
      "ToolCall_get_guardian_context": {
        "type": "object",
        "description": "Kamchatka safety context for a place or route: hazards, active alerts, advice. For plain facts (type, coordinates) use get_place_info. Получить полный контекст места как Хранитель: статус (открыто/закрыто), реалтайм алерты КБГС РАН, опасности, загрузка, традиционные знания о месте. Используй ВСЕГДА когда спрашивают о конкретном месте, вулкане, озере, маршруте, источнике Камчатки.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_guardian_context"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "description": "Place or route name. Название места или объекта",
                "examples": [
                  "Авачинский вулкан"
                ]
              }
            },
            "required": [
              "place"
            ]
          }
        }
      },
      "ToolCall_get_place_info": {
        "type": "object",
        "description": "Kamchatka place facts only: what it is, type, coordinates. Does not return hazards, alerts or nearby places — for safety use get_guardian_context. Найти базовую информацию о месте из базы данных: тип, координаты, ссылка на страницу места на сайте (её и давай, когда просят ссылку или координаты). Для полного контекста с безопасностью и алертами — get_guardian_context.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_place_info"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Place name. Название объекта",
                "examples": [
                  "Курильское озеро"
                ]
              }
            },
            "required": [
              "name"
            ]
          }
        }
      },
      "ToolCall_get_weather": {
        "type": "object",
        "description": "Daily weather forecast (Open-Meteo) for a Kamchatka place by name, or for any point by latitude/longitude. Прогноз погоды по дням (Open-Meteo) для места Камчатки по имени или для любой точки по координатам. Без аргументов — Петропавловск-Камчатский; в горах погода другая, поэтому место лучше назвать.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_weather"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "place": {
                "type": "string",
                "description": "Place name from the platform directory (Russian works best). Название места из справочника платформы, например «Мутновский» или «Налычево».",
                "examples": [
                  "Мутновский"
                ]
              },
              "lat": {
                "type": "string",
                "description": "Latitude in decimal degrees; use together with lng. Coordinates take precedence over place. Широта в градусах, например 52.45. Вместе с lng; координаты главнее названия.",
                "examples": [
                  "52.45"
                ]
              },
              "lng": {
                "type": "string",
                "description": "Longitude in decimal degrees; use together with lat. Долгота в градусах, например 158.19. Вместе с lat.",
                "examples": [
                  "158.19"
                ]
              },
              "days": {
                "type": "string",
                "description": "Forecast days, 1–7; default 3. Сколько дней прогноза, 1–7; по умолчанию 3.",
                "examples": [
                  "3"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_get_volcano_status": {
        "type": "object",
        "description": "Kamchatka volcano activity: KVERT aviation code and KB GS RAS seismicity. No name — all elevated. For one place or route use get_guardian_context. Вулканическая активность Камчатки по двум шкалам: авиационный код KVERT (пепел) и сводка сейсмичности КФ ЕГС РАН. Без названия — вулканы, повышенные хотя бы по одной шкале; с названием — этот вулкан по обеим. Для безопасности конкретного места и маршрута — get_guardian_context.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_volcano_status"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "volcano": {
                "type": "string",
                "description": "Volcano name; empty — all volcanoes elevated on either scale. Название вулкана, например «Ключевской» или «Мутновский». Пусто — все повышенные.",
                "examples": [
                  "Ключевской"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_search_accommodations": {
        "type": "object",
        "description": "Stays in Kamchatka from platform partners. To send dates and guests to a stay owner use create_stay_request. Найти жильё на Камчатке (гостиницы, базы, глэмпинг, дома) из платформы Ведар с ценами и адресами. Используй когда турист спрашивает где остановиться, переночевать, снять жильё.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "search_accommodations"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "zone": {
                "type": "string",
                "description": "Area or town name. Зона расположения (например: Петропавловск-Камчатский, Налычево, Паратунка)",
                "examples": [
                  "Паратунка"
                ]
              },
              "type": {
                "type": "string",
                "description": "Stay type: hotel, hostel, guesthouse, glamping, apartment, cottage. Тип жилья: hotel, hostel, guesthouse, glamping, apartment, cottage",
                "examples": [
                  "hotel"
                ]
              },
              "price_max": {
                "type": "string",
                "description": "Maximum price per night, RUB. Максимальная цена за ночь в рублях",
                "examples": [
                  "8000"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_search_transfers": {
        "type": "object",
        "description": "Kamchatka transfers: free seats in dated carrier trips, plus whole-vehicle charter prices (vakhtovka trucks). No dated trips is normal, not an error. Найти свободные места в поездках перевозчиков Камчатки (джипы, вахтовки, микроавтобусы) из витрины Ведара: дата, направление, остаток мест, цена места; а также вахтовки под заказ целой машиной — прайс по направлениям, цена за машину. Используй когда турист спрашивает как доехать, есть ли трансфер, заброска, попутный джип к вулкану или источникам, сколько стоит вахтовка. Место в поездке занимается только после подтверждения перевозчика; вахтовка под заказ — договорённость напрямую с перевозчиком. Пустая выдача поездок с датами — норма, а не ошибка поиска: перевозчики ходят под заказ, и тогда ответ называет прайс под заказ; рейсов не выдумывай.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "search_transfers"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "description": "Window start, YYYY-MM-DD; default today. Начало окна дат, ГГГГ-ММ-ДД (по умолчанию сегодня)",
                "examples": [
                  "2027-07-15"
                ]
              },
              "to": {
                "type": "string",
                "description": "Window end, YYYY-MM-DD; default +14 days, at most 60. Конец окна дат, ГГГГ-ММ-ДД (по умолчанию +14 дней, не больше 60)",
                "examples": [
                  "2027-07-29"
                ]
              },
              "seats": {
                "type": "string",
                "description": "Seats needed; default 1. Сколько мест нужно (по умолчанию 1)",
                "examples": [
                  "2"
                ]
              },
              "place": {
                "type": "string",
                "description": "Destination or origin keyword. Куда или откуда: слово из направления, например «Горелый», «Толбачик», «аэропорт»",
                "examples": [
                  "аэропорт"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_search_gear": {
        "type": "object",
        "description": "Gear rental in Kamchatka from platform partners. An empty result is normal: the rental shelf may have no partners yet, and the answer says so — do not invent rental shops. Найти прокат туристического снаряжения на Камчатке из платформы Ведар с ценами за сутки. Используй когда турист спрашивает где арендовать/взять напрокат снаряжение: палатку, спальник, треккинговые палки, рюкзак, кошки, газовую горелку и т.д. Пустая выдача — норма: прокатов на платформе пока может не быть вовсе, ответ так и скажет; адреса прокатов не выдумывай.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "search_gear"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "What to rent: tent, sleeping bag, trekking poles, a brand. Что ищут: например \"палатка\", \"спальник\", \"треккинговые палки\", бренд",
                "examples": [
                  "палатка"
                ]
              },
              "category": {
                "type": "string",
                "description": "Gear category, if known. Категория снаряжения (если известна)"
              },
              "price_max": {
                "type": "string",
                "description": "Maximum price per day, RUB. Максимальная цена за сутки в рублях",
                "examples": [
                  "1500"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_safety_status": {
        "type": "object",
        "description": "Kamchatka regional safety status: active alerts (seismic, volcanic, weather, MChS) with their source. Текущая обстановка по Камчатскому краю целиком: активные предупреждения, их количество и тяжесть, свежесть данных и источник верхнего предупреждения (ленты: КБГС РАН и ЕГС РАН — сейсмика, USGS, МЧС по Камчатскому краю, Росгидромет — погода, NASA FIRMS — пожары). Используй, когда спрашивают, безопасно ли сейчас ехать или что происходит в крае. Для конкретного места используй get_guardian_context.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "safety_status"
          },
          "arguments": {
            "type": "object",
            "properties": {},
            "required": []
          }
        }
      },
      "ToolCall_make_trip_plan": {
        "type": "object",
        "description": "Day-by-day Kamchatka trip plan with weather and live availability; returns a plan ID for edit_trip_plan. Собрать план поездки по Камчатке по дням: зоны, активности, честные цены, предупреждения сезона, ориентир цены на человека с разбивкой. Используй, когда туриста интересует «что посмотреть за N дней», «составь маршрут/план поездки», «как спланировать неделю на Камчатке». Ответ содержит ссылку на страницу готового плана с турами и заявкой оператору. Ответ несёт ID плана: добавить день, убрать или переставить день, сменить уровень жилья — через edit_trip_plan с этим ID, остальные дни не меняются. Другие даты, длительность или состав группы — вызови make_trip_plan снова с прежними аргументами плюс изменение.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "make_trip_plan"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "days": {
                "type": "string",
                "description": "Trip length in days, 3–21; default 7. Сколько дней поездка (число, 3–21). Не сказано — 7.",
                "examples": [
                  "7"
                ]
              },
              "interests": {
                "type": "string",
                "description": "Interests in free text. Интересы туриста своими словами: «вулканы и медведи», «рыбалка», «море и термальные»",
                "examples": [
                  "вулканы и медведи"
                ]
              },
              "when": {
                "type": "string",
                "description": "When the trip starts: a Russian month name or YYYY-MM-DD; season decides what is possible in Kamchatka. Default is one month from today. Когда поездка: месяц («июль», «в августе») или дата YYYY-MM-DD. Сезон на Камчатке решает всё — если турист назвал месяц, передай его обязательно. Не сказано — через месяц от сегодня.",
                "examples": [
                  "2027-07-10"
                ]
              },
              "travel_style": {
                "type": "string",
                "description": "How the traveller wants to go: self (no guide, only where our safety data allows), operator (operator tours) or mixed; default mixed. Как турист хочет ехать: «сам» (без гида — только там, где это безопасно), «с оператором» (туры операторов) или «вперемешку». Не сказано — вперемешку.",
                "examples": [
                  "self"
                ]
              },
              "rest_days": {
                "type": "string",
                "description": "Rest days to add, 0–14; a weather reserve day is added separately when needed. Сколько дней отдыха вставить в план (0–14), если турист сказал. Резерв на нелётную погоду планер добавит сам.",
                "examples": [
                  "1"
                ]
              },
              "adults": {
                "type": "string",
                "description": "Number of adults, 1–30; default 2, and the answer says it was assumed. Сколько взрослых (1–30), если турист сказал. Не сказано — считаю двоих и говорю об этом в ответе.",
                "examples": [
                  "2"
                ]
              },
              "children": {
                "type": "string",
                "description": "Children ages, comma-separated; ages decide which activities are allowed. Возрасты детей через запятую: «6, 10». От возраста зависят допуски активностей. Детей нет — не передавай.",
                "examples": [
                  "6, 10"
                ]
              },
              "budget_tier": {
                "type": "string",
                "description": "Budget level: economy, comfort or premium; default comfort. Уровень бюджета: «эконом», «комфорт» или «премиум» (economy/comfort/premium). Не сказано — «комфорт».",
                "examples": [
                  "economy"
                ]
              }
            },
            "required": []
          }
        }
      },
      "ToolCall_edit_trip_plan": {
        "type": "object",
        "description": "Edit a Kamchatka trip plan from make_trip_plan by its ID: add, remove or move a day, change lodging level, or apply a flight delay the traveller reports; untouched days stay as they were. Изменить план поездки, собранный make_trip_plan, по его ID: добавить день с занятием («добавь день рыбалки»), убрать день, переставить день, сменить уровень жилья («замени жильё на базу», «подешевле»), учесть задержку рейса («рейс задержали на два дня» — flight_delay). Дни, которых правка не касается, не меняются. Невозможная правка (день прилёта, занятие не по возрасту детей, движок не нашёл выхода) — отказ с причиной, план остаётся прежним. План хранится 7 дней; нет плана — сначала make_trip_plan.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "edit_trip_plan"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "plan_id": {
                "type": "string",
                "description": "Plan ID from the make_trip_plan answer. Идентификатор плана (ID) из ответа make_trip_plan."
              },
              "action": {
                "type": "string",
                "description": "add_day, remove_day, move_day, set_lodging or flight_delay. Что сделать: add_day (добавить день с занятием), remove_day (убрать день), move_day (переставить день), set_lodging (уровень жилья), flight_delay (рейс задержан — турист сказал сам).",
                "examples": [
                  "add_day"
                ]
              },
              "day": {
                "type": "string",
                "description": "Day number in the plan, for remove_day and move_day. Номер дня в плане — для remove_day и move_day.",
                "examples": [
                  "3"
                ]
              },
              "to_day": {
                "type": "string",
                "description": "New position of the day, for move_day. Новое место дня — для move_day.",
                "examples": [
                  "2"
                ]
              },
              "interest": {
                "type": "string",
                "description": "Activity for add_day, free text (Russian works best). Занятие для add_day своими словами: «рыбалка», «вулканы», «сплав».",
                "examples": [
                  "рыбалка"
                ]
              },
              "lodging": {
                "type": "string",
                "description": "Lodging level for set_lodging: economy, comfort or premium. Уровень жилья для set_lodging: «эконом» (базы, хостелы, палатки), «комфорт» (гостиницы, апартаменты), «премиум» (лоджи).",
                "examples": [
                  "economy"
                ]
              },
              "delay_days": {
                "type": "string",
                "description": "For flight_delay: how many days the arrival flight is delayed, 1–7. На сколько дней задержан рейс прилёта (1–7) — для flight_delay.",
                "examples": [
                  "2"
                ]
              },
              "keep_return": {
                "type": "string",
                "description": "For flight_delay: yes keeps the return date and shortens the trip (default); no shifts the whole trip. Для flight_delay: «да» — обратный билет прежний, поездка короче (по умолчанию); «нет» — обратный билет переносится, вся поездка сдвигается.",
                "examples": [
                  "yes"
                ]
              }
            },
            "required": [
              "plan_id",
              "action"
            ]
          }
        }
      },
      "ToolCall_get_tour_availability": {
        "type": "object",
        "description": "Kamchatka tour live availability by date: free seats and nearest open dates. Свободные даты и места КОНКРЕТНОГО тура из реальной занятости мест. Используй всегда, когда турист спрашивает «когда есть места», «свободно ли на дату», «на какие даты можно» — не называй даты и места по памяти, только отсюда.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_tour_availability"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "tour": {
                "type": "string",
                "description": "Tour title, keyword or numeric ID from get_tours. Название тура, ключевое слово или числовой ID"
              },
              "date_from": {
                "type": "string",
                "description": "Start of the window, YYYY-MM-DD; default today. С какой даты смотреть, YYYY-MM-DD. Не сказано — с сегодня.",
                "examples": [
                  "2027-07-15"
                ]
              },
              "days": {
                "type": "string",
                "description": "Window length in days, 1–31; default 14. Окно в днях (1–31). Не сказано — 14.",
                "examples": [
                  "14"
                ]
              },
              "people": {
                "type": "string",
                "description": "Number of travellers, 1–30. When given, each date shows the full booking total — the same calculation the booking itself uses. Сколько человек (1–30). Дано — к каждой дате итоговая сумма поездки, тем же расчётом, что при оформлении заявки.",
                "examples": [
                  "2"
                ]
              }
            },
            "required": [
              "tour"
            ]
          }
        }
      },
      "ToolCall_search": {
        "type": "object",
        "description": "Keyword search across Vedar Kamchatka: operator tours, places, stays, routes; returns up to 10 results with id for fetch, title and canonical url. For live seats use get_tour_availability. Поиск по витрине Ведара для коннекторов ChatGPT: туры операторов Камчатки, места, жильё и маршруты по словам запроса (русский или английский). Отдаёт до 10 результатов с id для fetch, названием и адресом страницы. Для живой занятости тура и обстановки есть get_tour_availability и safety_status.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "search"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "Search words, 2–200 characters; Russian or English. Слова запроса, от 2 до 200 символов, по-русски или по-английски.",
                "examples": [
                  "Курильское озеро медведи"
                ]
              }
            },
            "required": [
              "query"
            ]
          }
        }
      },
      "ToolCall_fetch": {
        "type": "object",
        "description": "Full text of one Vedar Kamchatka record by id from search (tour, place, stay, route): description, price, program, safety facts, canonical url. Published records only. Полный текст одной записи витрины Ведара по id из search (tour:<id>, place:<slug>, stay:<uuid>, route:<slug>): описание, цена и состав тура, факты о месте и его опасностях, жильё, маршрут. Только опубликованное; записи, которой нет на витрине, — отказ с объяснением.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "fetch"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "description": "Record id from search: tour:<id>, place:<slug>, stay:<uuid> or route:<slug>. Идентификатор записи из search: tour:<id>, place:<slug>, stay:<uuid> или route:<slug>.",
                "examples": [
                  "tour:12"
                ]
              }
            },
            "required": [
              "id"
            ]
          }
        }
      },
      "ToolCall_get_request_status": {
        "type": "object",
        "description": "Status of a Kamchatka request made via create_lead, create_booking_request or request_charter, by its status key: awaiting operator, confirmed, declined, other date, no answer. No personal data. Состояние заявки, отправленной через create_lead, create_booking_request или request_charter, по ключу статуса из ответа того инструмента: ждёт оператора, оператор связался, подтверждена, отказ, другая дата, нет ответа. Без имени и телефона. Ключ выдаётся на каждую заявку и живёт 90 дней; без ключа состояние не узнать — номера заявок не называются. В ответе есть page — страница заявки для человека: там он сам подтверждает согласие на обработку данных и видит ответ оператора.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "get_request_status"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "description": "Status key from the reply of the writing tool, as is. Ключ статуса из ответа пишущего инструмента, как есть (20–120 знаков)."
              }
            },
            "required": [
              "key"
            ]
          }
        }
      },
      "ToolCall_create_lead": {
        "type": "object",
        "description": "Tour-selection request for Kamchatka when no tour or date is chosen yet; human-confirmed by a manager, no payment. Needs consent: true, else refused. Whole vehicle (vakhtovka): request_charter. Оставить заявку на подбор тура по Камчатке: менеджер платформы свяжется по телефону. Обязательны имя, телефон и описание запроса (даты, состав группы, интересы). Заказ машины целиком (вахтовка) — не сюда, а request_charter. Это только заявка: оплаты через платформу нет. Имя и телефон — персональные данные: спроси у человека согласие на их обработку и передай consent: true, иначе заявка не создаётся.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "create_lead"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "description": "Traveller's name. Имя туриста"
              },
              "phone": {
                "type": "string",
                "description": "Contact phone, required. Телефон для связи (обязателен)"
              },
              "comment": {
                "type": "string",
                "description": "The request: dates, group size, interests. Запрос: даты, сколько человек, что интересует"
              },
              "interest": {
                "type": "string",
                "description": "Tour or route name, if already chosen. Название тура/маршрута, если уже выбран"
              },
              "plan_id": {
                "type": "string",
                "description": "Plan ID from make_trip_plan when the request is for that plan: the manager gets the whole plan (group, tours by day, estimate). Номер плана из make_trip_plan, если заявка — на этот план: менеджер получит план целиком (состав, туры по дням, смету) и не будет переспрашивать.",
                "examples": [
                  "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"
                ]
              },
              "consent": {
                "type": "boolean",
                "description": "Explicit consent to process name and phone for this request; ask the person and pass true, otherwise the request is not created. Человек согласен на обработку своих персональных данных (имя, телефон) для связи по этой заявке. Спроси прямо и передай true. Без согласия заявка не создаётся.",
                "examples": [
                  true
                ]
              }
            },
            "required": [
              "name",
              "phone",
              "comment",
              "consent"
            ]
          }
        }
      },
      "ToolCall_create_booking_request": {
        "type": "object",
        "description": "Booking request for a Kamchatka tour on a date; live availability checked first, human-confirmed by the operator, no payment. Needs consent: true, otherwise refused. No tour yet — use create_lead. Заявка оператору на конкретный тур и дату. Перед вызовом проверь свободные даты через get_tour_availability. Заявку подтверждает оператор по телефону — мгновенного подтверждения нет, оплаты через платформу нет. Если на дату нет мест, заявка не создаётся и в ответе будут ближайшие свободные даты. Если у тура вообще нет расписания в системе (оператор берёт туристов без календаря), вместо отказа оператору уходит запрос мест: в ответе будет ссылка на страницу статуса — передай её человеку; места этим не закрепляются. Имя и телефон — персональные данные: спроси согласие на их обработку и передай consent: true.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "create_booking_request"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "tour": {
                "type": "string",
                "description": "Tour title or numeric ID from get_tours / get_tour_availability. Название тура или числовой ID (из get_tours / get_tour_availability)"
              },
              "date": {
                "type": "string",
                "description": "Tour date, YYYY-MM-DD. Дата тура, YYYY-MM-DD",
                "examples": [
                  "2027-07-15"
                ]
              },
              "participants": {
                "type": "string",
                "description": "Number of people, 1–30; default 1. Сколько человек (1–30). Не сказано — 1.",
                "examples": [
                  "2"
                ]
              },
              "name": {
                "type": "string",
                "description": "Traveller's name. Имя туриста"
              },
              "phone": {
                "type": "string",
                "description": "Phone for confirmation, required. Телефон для подтверждения (обязателен)"
              },
              "comment": {
                "type": "string",
                "description": "Wishes, questions, group composition. Пожелания, вопросы, состав группы"
              },
              "plan_id": {
                "type": "string",
                "description": "Plan ID from make_trip_plan when this tour is part of that plan: the operator sees the whole trip. Номер плана из make_trip_plan, если тур — из этого плана: оператор увидит, частью какой поездки он стоит.",
                "examples": [
                  "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"
                ]
              },
              "consent": {
                "type": "boolean",
                "description": "Explicit consent to process name and phone for this request; ask the person and pass true, otherwise the request is not created. Человек согласен на обработку своих персональных данных (имя, телефон) для связи по этой заявке. Спроси прямо и передай true. Без согласия заявка не создаётся.",
                "examples": [
                  true
                ]
              }
            },
            "required": [
              "tour",
              "date",
              "name",
              "phone",
              "consent"
            ]
          }
        }
      },
      "ToolCall_create_stay_request": {
        "type": "object",
        "description": "Kamchatka stay request: dates and guests go to the owner, human-confirmed by the owner, no payment. Needs consent: true, otherwise refused. For tours use create_booking_request. Заявка владельцу жилья на даты: заезд, выезд, сколько гостей, имя и телефон. Объект — из search_accommodations (название или ID из ссылки на карточку). Заявка уходит владельцу в мессенджер, он перезванивает сам и подтверждает даты и цену; это не бронь и не оплата, через платформу жильё не оплачивается. Принимают её только объекты без своих номеров на платформе и без сайта брони — для остальных ответ скажет, где бронировать. Имя и телефон — персональные данные, они передаются владельцу жилья: спроси согласие на это и передай consent: true.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "create_stay_request"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "accommodation": {
                "type": "string",
                "description": "Stay name or ID from search_accommodations. Название объекта или его ID (из search_accommodations)"
              },
              "check_in": {
                "type": "string",
                "description": "Check-in date, YYYY-MM-DD. Дата заезда, YYYY-MM-DD",
                "examples": [
                  "2027-07-15"
                ]
              },
              "check_out": {
                "type": "string",
                "description": "Check-out date, YYYY-MM-DD, after check-in, at most 60 nights. Дата выезда, YYYY-MM-DD (позже заезда, не больше 60 ночей)",
                "examples": [
                  "2027-07-17"
                ]
              },
              "guests": {
                "type": "string",
                "description": "Number of guests, 1–50; default 1. Сколько гостей (1–50). Не сказано — 1.",
                "examples": [
                  "4"
                ]
              },
              "name": {
                "type": "string",
                "description": "Guest's name. Имя гостя"
              },
              "phone": {
                "type": "string",
                "description": "Phone the owner will call back, required. Телефон гостя — по нему перезвонит владелец (обязателен)"
              },
              "comment": {
                "type": "string",
                "description": "Wishes for the owner. Пожелания владельцу: баня, время заезда, дети"
              },
              "consent": {
                "type": "boolean",
                "description": "Explicit consent to process name and phone and pass them to the stay's owner; ask the person and pass true, otherwise the request is not created. Человек согласен на обработку своих персональных данных (имя, телефон) и их передачу владельцу жилья для связи по заявке. Спроси прямо и передай true. Без согласия заявка не создаётся.",
                "examples": [
                  true
                ]
              }
            },
            "required": [
              "accommodation",
              "check_in",
              "check_out",
              "name",
              "phone",
              "consent"
            ]
          }
        }
      },
      "ToolCall_request_charter": {
        "type": "object",
        "description": "Whole-vehicle (vakhtovka) request to a Kamchatka charter carrier: destination, dates, group size; human-confirmed by a manager, no payment. Needs consent: true. Prices: search_transfers. Заявка на вахтовку целой машиной у перевозчика «под заказ»: куда, на какие даты, сколько человек. Прайс и перевозчиков смотри через search_transfers (раздел «под заказ»). Календаря у таких перевозчиков нет, поэтому заявка не проверяет занятость машин: менеджер Ведара свяжется по телефону, согласует поездку с перевозчиком и подтвердит. Цена — за машину по прайсу; направления нет в прайсе — заказ принимается, цену называет перевозчик. Оплаты через платформу нет, расчёт напрямую. Имя и телефон — персональные данные: спроси согласие на их обработку и передай consent: true, иначе заявка не создаётся.",
        "required": [
          "tool",
          "arguments"
        ],
        "properties": {
          "tool": {
            "const": "request_charter"
          },
          "arguments": {
            "type": "object",
            "properties": {
              "destination": {
                "type": "string",
                "description": "Where to go: a word from the carrier price list or your own destination. Куда ехать: слово или название из прайса («Горелый», «Толбачик») либо своё направление",
                "examples": [
                  "Горелый"
                ]
              },
              "date_from": {
                "type": "string",
                "description": "Departure date, YYYY-MM-DD. Дата выезда, YYYY-MM-DD",
                "examples": [
                  "2027-07-15"
                ]
              },
              "date_to": {
                "type": "string",
                "description": "Return date, YYYY-MM-DD, if known. Дата возвращения, YYYY-MM-DD, если известна",
                "examples": [
                  "2027-07-17"
                ]
              },
              "passengers": {
                "type": "string",
                "description": "Number of people, 1–60. Сколько человек (1–60)",
                "examples": [
                  "8"
                ]
              },
              "name": {
                "type": "string",
                "description": "Customer's name. Имя заказчика"
              },
              "phone": {
                "type": "string",
                "description": "Contact phone, required. Телефон для связи (обязателен)"
              },
              "carrier": {
                "type": "string",
                "description": "Carrier name or slug from search_transfers; not needed while there is one carrier. Перевозчик: название или slug из search_transfers. Не нужен, пока перевозчик один.",
                "examples": [
                  "shatun"
                ]
              },
              "comment": {
                "type": "string",
                "description": "Wishes: how many days the vehicle is needed, what to carry, pickup place. Пожелания: сколько дней нужна машина, что везти, откуда забирать"
              },
              "consent": {
                "type": "boolean",
                "description": "Explicit consent to process name and phone for this request; ask the person and pass true, otherwise the request is not created. Человек согласен на обработку своих персональных данных (имя, телефон) для связи по этой заявке. Спроси прямо и передай true. Без согласия заявка не создаётся.",
                "examples": [
                  true
                ]
              }
            },
            "required": [
              "destination",
              "date_from",
              "passengers",
              "name",
              "phone",
              "consent"
            ]
          }
        }
      },
      "A2ASendMessageRequest": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "object",
            "required": [
              "parts"
            ],
            "properties": {
              "messageId": {
                "type": "string",
                "maxLength": 128
              },
              "contextId": {
                "type": "string",
                "maxLength": 128,
                "description": "Контекст разговора: последние 10 реплик держатся час в памяти процесса"
              },
              "taskId": {
                "type": "string",
                "maxLength": 128,
                "description": "Только незавершённая задача; все задачи здесь завершаются в ответе, так что поле практически не нужно"
              },
              "role": {
                "type": "string",
                "description": "Не читается"
              },
              "parts": {
                "type": "array",
                "minItems": 1,
                "maxItems": 16,
                "items": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/A2ATextPart"
                    },
                    {
                      "$ref": "#/components/schemas/A2AToolCallPart"
                    }
                  ]
                }
              }
            }
          },
          "configuration": {
            "type": "object",
            "properties": {
              "historyLength": {
                "type": "integer"
              }
            }
          }
        }
      },
      "A2APart": {
        "oneOf": [
          {
            "type": "object",
            "required": [
              "text"
            ],
            "properties": {
              "kind": {
                "const": "text"
              },
              "text": {
                "type": "string"
              }
            }
          },
          {
            "type": "object",
            "required": [
              "data"
            ],
            "properties": {
              "kind": {
                "const": "data"
              },
              "data": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        ]
      },
      "A2AMessage": {
        "type": "object",
        "required": [
          "messageId",
          "role",
          "parts"
        ],
        "properties": {
          "kind": {
            "const": "message",
            "description": "Только в форме 0.3"
          },
          "messageId": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "ROLE_AGENT",
              "agent"
            ]
          },
          "parts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/A2APart"
            }
          },
          "contextId": {
            "type": "string"
          },
          "taskId": {
            "type": "string"
          }
        }
      },
      "A2ATask": {
        "type": "object",
        "description": "Задача завершается в ответе: состояния только completed (успех; есть артефакт), rejected (отказ по входу или лимит) и failed (наш сбой). Первая часть — текст; у вызова инструмента вторая, DataPart, — { tool, continue_url?, result? }. В history только ответ агента.",
        "required": [
          "id",
          "contextId",
          "status",
          "artifacts",
          "history"
        ],
        "properties": {
          "kind": {
            "const": "task",
            "description": "Только в форме 0.3"
          },
          "id": {
            "type": "string"
          },
          "contextId": {
            "type": "string"
          },
          "status": {
            "type": "object",
            "required": [
              "state"
            ],
            "properties": {
              "state": {
                "type": "string",
                "enum": [
                  "TASK_STATE_COMPLETED",
                  "TASK_STATE_REJECTED",
                  "TASK_STATE_FAILED",
                  "completed",
                  "rejected",
                  "failed"
                ]
              },
              "timestamp": {
                "type": "string"
              },
              "message": {
                "$ref": "#/components/schemas/A2AMessage"
              }
            }
          },
          "artifacts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "artifactId": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "parts": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/A2APart"
                  }
                }
              }
            }
          },
          "history": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/A2AMessage"
            }
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "A2ASendMessageResponse": {
        "description": "С заголовком A2A-Version: 1.0 — { task }; без заголовка или с 0.3 — Task как есть, с kind и строчными состояниями.",
        "oneOf": [
          {
            "type": "object",
            "required": [
              "task"
            ],
            "properties": {
              "task": {
                "$ref": "#/components/schemas/A2ATask"
              }
            }
          },
          {
            "$ref": "#/components/schemas/A2ATask"
          }
        ]
      },
      "A2AError": {
        "type": "object",
        "description": "google.rpc.Status с ErrorInfo. HTTP-код повторён в error.code.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "status",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "status": {
                "type": "string",
                "enum": [
                  "NOT_FOUND",
                  "FAILED_PRECONDITION",
                  "INVALID_ARGUMENT",
                  "INTERNAL"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "@type": {
                      "const": "type.googleapis.com/google.rpc.ErrorInfo"
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "TASK_NOT_FOUND",
                        "METHOD_NOT_FOUND",
                        "TASK_NOT_CANCELABLE",
                        "PUSH_NOTIFICATION_NOT_SUPPORTED",
                        "UNSUPPORTED_OPERATION",
                        "CONTENT_TYPE_NOT_SUPPORTED",
                        "VERSION_NOT_SUPPORTED",
                        "PARSE_ERROR",
                        "INVALID_REQUEST",
                        "INVALID_PARAMS",
                        "INTERNAL",
                        "INVALID_AGENT_RESPONSE"
                      ]
                    },
                    "domain": {
                      "const": "a2a-protocol.org"
                    },
                    "metadata": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Без id — уведомление: ответ 202 без тела"
          },
          "method": {
            "type": "string",
            "enum": [
              "initialize",
              "tools/list",
              "tools/call",
              "ping"
            ]
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true,
            "description": "tools/call: { content: [{ type: \"text\", text }], structuredContent?, isError? }"
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {}
            }
          }
        }
      },
      "McpServerInfo": {
        "type": "object",
        "required": [
          "name",
          "version",
          "tools"
        ],
        "properties": {
          "name": {
            "const": "vedar-mcp"
          },
          "title": {
            "type": "string"
          },
          "version": {
            "const": "2.4.0"
          },
          "description": {
            "type": "string"
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "required": [
                "name",
                "description",
                "inputSchema"
              ],
              "properties": {
                "name": {
                  "type": "string",
                  "enum": [
                    "get_tours",
                    "get_tour_details",
                    "get_guardian_context",
                    "get_place_info",
                    "get_weather",
                    "get_volcano_status",
                    "search_accommodations",
                    "search_transfers",
                    "search_gear",
                    "safety_status",
                    "make_trip_plan",
                    "edit_trip_plan",
                    "get_tour_availability",
                    "search",
                    "fetch",
                    "get_request_status",
                    "create_lead",
                    "create_booking_request",
                    "create_stay_request",
                    "request_charter"
                  ]
                }
              }
            }
          }
        }
      },
      "McpServerCard": {
        "type": "object",
        "required": [
          "$schema",
          "name",
          "version",
          "description",
          "remotes"
        ],
        "properties": {
          "$schema": {
            "type": "string"
          },
          "name": {
            "const": "ru.vedarai/mcp"
          },
          "version": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "websiteUrl": {
            "type": "string"
          },
          "remotes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "const": "streamable-http"
                },
                "url": {
                  "type": "string"
                },
                "supportedProtocolVersions": {
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "2025-06-18",
                      "2025-03-26",
                      "2024-11-05"
                    ]
                  }
                }
              }
            }
          }
        }
      },
      "AgentCard": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "name",
          "description",
          "skills"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "AiCatalog": {
        "type": "object",
        "required": [
          "specVersion",
          "entries"
        ],
        "properties": {
          "specVersion": {
            "type": "string"
          },
          "entries": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "required": [
                "identifier",
                "type",
                "url"
              ]
            }
          }
        }
      },
      "ApiCatalog": {
        "type": "object",
        "description": "Linkset по RFC 9264: link context objects с anchor и отношениями service-desc, service-doc, service-meta (RFC 8631).",
        "required": [
          "linkset"
        ],
        "properties": {
          "linkset": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "required": [
                "anchor"
              ],
              "properties": {
                "anchor": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}