Вайбцех

MCP: что это и как работает stateless на 3 инструментах заметок в 2026

Опубликовано 10 мин чтенияБазовый
Автор статьи показывает схему MCP, рядом удивлённый кот и карточки с ролями модели, клиента и сервера.
Что узнаете
  • простую схему MCP-клиента, MCP-сервера и модели
  • понятное сравнение stateful и stateless-взаимодействия
  • план локального примера с одним endpoint и тремя инструментами
  • способ хранить состояние приложения через явный note_id
Применить за 30 мин
Базовый
4просмотров
Что в инструкции
  1. Что такое MCP и зачем он нужен?
  2. Кто за что отвечает в связке MCP-клиент и MCP-сервер?
  3. Почему модель не вызывает инструмент напрямую?
  4. Что изменилось при переходе от сессии к stateless?
  5. Как сделать локальный MCP-вызов stateless по шагам?
  6. Что делать, если приложению всё ещё нужно состояние?
  7. Что ломается после перехода на stateless?
  8. Вопросы и ответы

Что такое MCP и зачем он нужен?

Без MCP модель остаётся советчиком. Она может написать инструкцию, предложить код или объяснить ошибку. Но сама по себе она не знает содержимое базы заметок и не умеет выполнить действие в ней.

MCP добавляет прослойку между моделью и внешней системой. Такой системой может быть локальный файл, база данных или отдельное приложение. Сервер описывает доступные инструменты. Модель получает эти описания и решает, какой инструмент нужен для текущего запроса.

Главная граница здесь простая: инструмент делает конкретное действие. Доступ ограничен отдельными операциями: «создай заметку», «добавь текст», «прочитай заметку». Такой набор возможностей проще проверять и контролировать, чем свободный shell-доступ и произвольные команды.

Например, пользователь пишет: «Создай заметку о встрече и добавь туда три пункта». Модель не открывает файл напрямую. Она выбирает инструмент создания заметки, получает идентификатор, затем вызывает инструмент добавления текста.

Для читателя это выглядит как один разговор. Внутри проходит несколько отдельных действий.

MCP даёт модели заранее определённые рычаги - и не более того. Чем точнее эти рычаги, тем проще понять, что именно произошло, когда результат оказался неправильным.

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

- Anthropic, Introducing the Model Context Protocol

Кто за что отвечает в связке MCP-клиент и MCP-сервер?

Разложу роли без документации:

  • Модель читает сообщение пользователя и выбирает действие. Она видит описание доступных инструментов: название, назначение и аргументы.
  • MCP-клиент связывает модель с сервером. Он получает решение модели, оформляет вызов инструмента и отправляет его дальше. Поэтому mcp client - не само приложение с данными и не модель.
  • MCP-сервер принимает вызов. Он проверяет аргументы, выполняет конкретное действие и возвращает результат.
  • Внешний источник хранит или отдаёт данные. В локальном примере это SQLite или JSON-файл.

Путь запроса выглядит так:

  1. Ты пишешь: «Добавь текст в заметку».
  2. Модель выбирает append_to_note.
  3. MCP-клиент передаёт серверу имя инструмента и аргументы.
  4. MCP-сервер добавляет текст в хранилище.
  5. Сервер возвращает результат клиенту.
  6. Модель показывает итог в чате.

Модель не обязана знать файл и способ записи: это зона ответственности сервера. Клиент не лезет в содержимое базы, его задача - передать вызов.

Такое разделение полезно именно в вайб-кодинге. Когда агент переписал часть приложения, проще искать поломку по границе: модель выбрала не тот инструмент, клиент передал неверные данные или сервер неправильно обработал аргументы.

Почему модель не вызывает инструмент напрямую?

Представь три слоя:

Модель отвечает на вопрос: «Что надо сделать?» Она выбирает инструмент и заполняет его аргументы. Например, передаёт note_id и текст, который нужно добавить.

Клиент отвечает на вопрос: «Куда и в каком формате отправить вызов?» Он знает, к какому MCP-серверу подключаться, и передаёт вызов дальше.

Сервер отвечает на вопрос: «Как выполнить действие?» Он открывает SQLite или JSON-файл, меняет данные и отдаёт результат.

Если убрать клиент и сервер, модели пришлось бы дать свободный доступ к окружению. Тогда она сама решала бы, какой файл открыть, какую команду запустить и куда отправить данные. Такой доступ сложнее ограничить и проверить.

MCP оставляет модели выбор инструмента, но не отдаёт ей весь набор системных возможностей. Для каждой функции есть отдельная граница и понятные аргументы. Правильный выбор инструмента ещё не гарантирует правильный результат, зато область возможной ошибки становится меньше.

Практикум «Старт»

Три дня живой практики: от идеи до работающего проекта по ссылке

2 000 ₽старт 5 августа, 18:00 МСК

Что изменилось при переходе от сессии к stateless?

Кот показывает переход от stateful-сессии к самостоятельному stateless-запросу.

В старой схеме клиент проходил обязательное начало соединения:

  1. Отправлял initialize.
  2. Получал Mcp-Session-Id.
  3. Передавал этот идентификатор в следующем запросе.
  4. Вызывал инструмент внутри созданной сессии.

У нового варианта другая логика. Один вызов инструмента укладывается в один HTTP-запрос. В нём передаётся версия протокола MCP-Protocol-Version, а имя метода и инструмента дублируется в заголовках Mcp-Method и Mcp-Name.

Серверу больше не требуется хранить ID сессии и направлять запросы на тот же backend через sticky routing. Любой запрос должен быть понятен сам по себе.

ХарактеристикаStateful (старая схема)Stateless (новая схема)
Начало соединенияОбязательный initializeНе требуется
Идентификатор сессииMcp-Session-IdОтсутствует
Вызов инструментаВнутри созданной сессииСамостоятельный HTTP-запрос
ЗаголовкиЗависит от реализацииMCP-Protocol-Version, Mcp-Method, Mcp-Name
Sticky routingТребуетсяНе требуется
Состояние приложенияЧасто путали с сессиейЯвный note_id или другой ID

На этом месте я останавливаюсь на важной границе. Stateless относится к протокольному уровню MCP. Он не означает, что приложение обязано забывать все данные после каждого запроса.

Практический пример у Simon Willison показывает масштаб работы модели: один вопрос к Datasette привёл к 7 отдельным SQL-запросам. В другом примере MCP-инструмент вернул число заметок 151. За разговором пользователя стояла цепочка вызовов, несколько последовательных операций.

Новая спецификация MCP 2026-07-28 убрала обязательные initialize, initialized, Mcp-Session-Id и зависимость от sticky routing. Состояние приложения при этом остаётся задачей самого приложения.

MCP преобразуется из двустороннего протокола с состоянием в протокол запросов и ответов без состояния.

- Model Context Protocol, The 2026-07-28 MCP Specification Release

Переход к stateless нужен не ради нового названия. Он убирает лишнюю транспортную сессию. Состояние заметки, корзины или задачи переносится в явный идентификатор.

Как сделать локальный MCP-вызов stateless по шагам?

Собака одобряет схему endpoint с тремя инструментами заметок и явным идентификатором.
  1. Определи минимальный endpoint.

    Сделай один локальный HTTP endpoint /mcp. Не добавляй сразу авторизацию, десятки инструментов и сложную бизнес-логику: фактура не содержит готовой настройки конкретного клиента или команды запуска.

    Важно разделить две вещи. Endpoint принимает MCP-запрос. Хранилище держит заметки. Сам endpoint не должен связывать вызовы через скрытый Mcp-Session-Id.

    Минимальная схема выглядит так:

    /mcp
    ├── create_note() -> note_id
    ├── append_to_note(note_id, text)
    └── get_note(note_id)
  2. Создай заметку с идентификатором.

    Инструмент create_note создаёт запись и возвращает note_id. Этот ID становится явной связью между будущими вызовами.

    Сервер может хранить запись в SQLite или JSON-файле. Точная схема хранения, конкурентный доступ и обработка ошибок в фактуре не описаны, поэтому я не буду выдавать выдуманный код за готовую реализацию.

    Правило для инструмента простое: связь должна быть видна снаружи. Верни идентификатор наружу.

    json
    {
      "tool": "create_note",
      "result": {
        "note_id": "созданный сервером идентификатор"
      }
    }
  3. Добавь текст по `note_id`.

    Инструмент append_to_note получает note_id и text. Сервер находит запись по этому ID и добавляет текст в SQLite или JSON-файл.

    Следующий вызов не должен рассчитывать на память предыдущего HTTP-запроса. Клиент передаёт note_id явно.

    json
    {
      "tool": "append_to_note",
      "arguments": {
        "note_id": "идентификатор из предыдущего результата",
        "text": "Первый пункт заметки"
      }
    }
  4. Прочитай заметку отдельным вызовом.

    Инструмент get_note получает тот же note_id и возвращает сохранённый текст. Так проверяется состояние приложения поверх stateless-протокола.

    json
    {
      "tool": "get_note",
      "arguments": {
        "note_id": "тот же идентификатор"
      }
    }
  5. Проверь два независимых HTTP-запроса.

    Сначала отправь вызов создания заметки. Получи note_id. Затем отдельным запросом вызови добавление текста или чтение заметки.

    В обоих запросах используй endpoint /mcp. Не передавай Mcp-Session-Id. Для нового stateless-вызова фактура фиксирует заголовки MCP-Protocol-Version, Mcp-Method и Mcp-Name.

    http
    POST /mcp
    MCP-Protocol-Version: 2026-07-28
    Mcp-Method: tools/call
    Mcp-Name: create_note
    http
    POST /mcp
    MCP-Protocol-Version: 2026-07-28
    Mcp-Method: tools/call
    Mcp-Name: get_note

    Это схема проверки, а не законченный JSON-RPC payload: фактура не содержит полного формата тела и всех обязательных заголовков. Я не подставляю недостающие поля из головы.

  6. Проверь промптом границы инструмента.

    Передай ИИ-агенту короткое требование. Оно помогает не смешать транспортную сессию и состояние заметки.

    Проверка stateless-схемы заметок
    Собери минимальный локальный MCP-артефакт с endpoint /mcp и тремя инструментами:
    create_note, append_to_note и get_note.
    
    Состояние заметок храни в SQLite или JSON-файле.
    create_note должен возвращать явный note_id.
    append_to_note и get_note должны принимать note_id в аргументах.
    Не используй Mcp-Session-Id для связи вызовов.
    Покажи отдельно, какие данные передаются в первом HTTP-запросе и какие во втором.
    Не добавляй другие инструменты, авторизацию и сложную бизнес-логику.
    Если точного JSON-RPC payload или команды запуска не хватает в исходных данных, укажи это явно и не выдумывай.
  7. Проверь результат в хранилище.

    После вызова append_to_note вызови get_note с тем же note_id. Текст должен прийти из SQLite или JSON-файла, а не из памяти протокольной сессии.

    Если сервер перезапустился, память одного процесса не должна считаться надёжным хранилищем. Для локального примера фактура разрешает SQLite или JSON-файл, но не задаёт точную реализацию восстановления и конкурентной записи. Это место надо проверять отдельно.

Практикум «Старт»

Три дня живой практики: от идеи до работающего проекта по ссылке

2 000 ₽старт 5 августа, 18:00 МСК

Что делать, если приложению всё ещё нужно состояние?

Старая сессия смешивала несколько смыслов. Она могла означать соединение, пользователя, чат или последовательность вызовов. Из-за этого один и тот же ID не всегда совпадал с тем, что человек считал одной рабочей сессией.

В stateless-схеме смысл задаёт приложение:

  • note_id указывает на заметку;
  • basket_id указывает на корзину;
  • job_id указывает на длительную задачу.

Сервер сам создаёт такой идентификатор и возвращает его в результате. Клиент сохраняет значение и передаёт его дальше. Инструменты получают состояние явно и не достают его из памяти MCP-соединения.

Например, create_note возвращает note_id. Затем append_to_note(note_id, text) меняет конкретную заметку. get_note(note_id) читает её. Протокол при этом остаётся stateless, а поведение приложения остаётся stateful.

Такой подход требует аккуратнее проектировать аргументы инструментов. Зато из вызова видно, с какой сущностью идёт работа. Это проще проверять в логах и при повторном запросе.

Что ломается после перехода на stateless?

Мужчина закрывает лицо лапой рядом с перечёркнутыми проблемами stateless-перехода.

Крайние случаи начинаются с совместимости. Клиент или middleware может по-прежнему отправлять initialize и ожидать Mcp-Session-Id. Новый сервер такой сценарий не обязан поддерживать.

Дальше идут функции, которым нужно обратиться к клиенту после вызова. В stateless-режиме отключается часть сценариев, связанных с unsolicited notifications и server-to-client requests. Client sampling, elicitation и roots тоже могут быть недоступны в legacy stateless-режиме.

Ломается и внутренняя диагностика. Раньше счётчик можно было привязать к sessionId. После удаления ID несколько клиентов с одинаковой ошибкой могут выглядеть как один поток событий. Для корреляции нужен другой ключ: явный идентификатор операции, failure fingerprint или внешняя телеметрия.

Авторизация тоже не исчезает вместе с сессией. Каждый запрос должен сам нести или получать из middleware credential, identity, права доступа и контекст аудита. Использовать старый ID как доказательство личности больше нельзя.

Есть и инфраструктурная ловушка. Любой запрос может попасть на другой экземпляр сервера. Поэтому память одного процесса не подходит для надёжного хранения счётчиков, задач и состояния. Данные надо вынести в SQLite, JSON-файл или другое внешнее хранилище с учётом ограничений конкретной реализации.

Поддержка новой схемы пока неоднородна: правильная по новой спецификации схема может не заработать в старой обвязке.

Вопросы и ответы

Вопросы и ответы

Что такое MCP-сервер?

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

Как устроены MCP-подключения?

В старой схеме клиент сначала отправлял initialize, получал Mcp-Session-Id, а затем вызывал инструменты. В новом stateless-варианте вызов оформляется самостоятельным HTTP-запросом.

Какой MCP protocol используется?

Финальная спецификация перехода называется MCP 2026-07-28. Она переводит базовый протокольный слой к stateless-взаимодействию.

Зачем MCP использует JSON?

JSON передаёт имя инструмента, аргументы и результат в структурированном виде. Так клиент и сервер обмениваются данными без привязки к человеческому тексту.

Можно ли работать с MCP через CLI?

Фактура не содержит отдельной инструкции по MCP CLI. Из неё можно утверждать только схему HTTP-вызова к endpoint /mcp, но не конкретную команду запуска через терминал.

Чем MCP-клиент отличается от сервера?

Клиент получает вызов от модели и передаёт его серверу. Сервер предоставляет инструменты, выполняет действие и возвращает результат.

Как модель участвует в MCP?

Модель получает описание доступных инструментов, выбирает нужный инструмент и формирует его вызов. Само действие выполняет MCP-сервер.

Как работает MCP?

Пользователь отправляет сообщение, модель выбирает инструмент, клиент передаёт вызов серверу, сервер работает с данными и возвращает результат модели. Я проверял эту цепочку на локальном примере с заметками.

Какие бывают MCP-примеры?

Я показываю минимальный пример с заметками: create_note возвращает note_id, append_to_note добавляет текст, а get_note читает запись.

Как работает MCP в stateless-схеме?

Каждый HTTP-запрос сам содержит данные, необходимые для обработки. Скрытая транспортная сессия не связывает вызовы, а состояние приложения передаётся явным идентификатором.

Как использовать MCP локально?

Собери endpoint /mcp, добавь инструменты заметок, выбери SQLite или JSON-файл для хранения и передавай note_id в каждом последующем вызове.

Как выглядит минимальный MCP-пример?

Минимальная схема состоит из одного endpoint и трёх инструментов: create_note, append_to_note и get_note. Первый инструмент создаёт ID, два других используют его явно.

Что такое MCP-серверы и чем они отличаются от клиентов?

MCP-серверы реализуют конкретные действия и доступ к данным. Со стороны клиента модель соединяется с этими серверами, а клиент передаёт выбранные моделью вызовы.

Источники

Практикум «Старт»

Три дня живой практики: от идеи до работающего проекта по ссылке

2 000 ₽старт 5 августа, 18:00 МСК

Материал был полезен?
Сергей Мазур
Автор
Сергей Мазур
Основатель Вайбцеха

Собираю продукты с ИИ-агентами и рассказываю, как это делать без программиста.

Читайте также

Термины из инструкции