mcp-server
Два MCP-сервера, один продукт, две ревизии протокола
Одна и та же корзина покупок, реализованная дважды: один раз на старой спецификации MCP с сохранением состояния (2025-11-25), второй — на новой, без сохранения состояния (2026-07-28). Запустите их рядом и посмотрите, как один из них падает.
Цель — не рабочий код, а понимание почему спецификация изменилась. Каждый эксперимент здесь устроен так, чтобы сбой был громким, а причина видна на проводе.
Что такое MCP? (три предложения)
MCP — Model Context Protocol — это стандартный способ для ИИ-приложения вызывать инструменты, написанные кем-то другим. Он заменяет N приложений × M интеграций на N + M, так же как Language Server Protocol заменил каждому редактору собственную поддержку TypeScript. Конкретно это сообщения JSON-RPC 2.0 с согласованными именами методов, передаваемые через stdio или HTTP.
Более длинная версия, если это пролетело слишком быстро: docs/01 — почему существует MCP.
Related MCP server: Online Boutique AI Assistant MCP Server
Что демонстрирует этот репозиторий
Пять инструментов — catalog_list, cart_create, cart_add_item, cart_view, cart_checkout — с одинаковыми именами в обоих серверах и одинаковой бизнес-логикой в общем пакете cart-core, который ничего не знает о MCP. Единственное различие между двумя серверами — уровень протокола, который и является предметом изучения.
Четыре вещи, за которыми можно наблюдать:
server-oldне может завершить собственное рукопожатие за обычным round-robin балансировщиком нагрузки.server-newдаже не замечает, что балансировщик существует.Перезапустите
server-oldв середине разговора — и корзина исчезнет навсегда, без какого-либо запроса, который клиент мог бы отправить для её восстановления.Вопрос «подтверждаете эту сумму?» обходится
server-oldв удержание открытого сокета на всё время человеческого размышления (измерено 1522 мс).server-newделает это двумя независимыми запросами, 4 мс + 15 мс, и может завершиться на другой машине, чем начался.Стабильный порядок списков и подсказки кэша — и арифметика, показывающая, почему отсутствующий
.sort()стоит около $4 200 в год.
Серверы намеренно не отрефакторины для совместного использования кода протокола. Дублирование между ними сделано специально, чтобы вы могли прочитать каждый насквозь и сравнить их.
Обязательно посмотрите на провод
Оба сервера печатают каждый запрос на уровне HTTP: метод, путь, все MCP-заголовки, метод и параметры JSON-RPC, какой экземпляр его обработал, и ответ, включая resultType. Ничего не скрыто за абстракциями SDK. Если во время эксперимента вы прочитаете только одно — читайте цветные строки лога.
Предварительные требования
Node.js 20 или новее (разработано на 25.5). Проверьте
node -v.Терминал, поддерживающий ANSI-цвета — логи сильно на них полагаются.
Порты 3000–3002, 3011, 3012 свободны.
Никакой базы данных, никакого Docker, никакого облачного аккаунта. Общее состояние — это JSON-файл.
Никакого Python в этом репозитории.
Установка
git clone <this repo>
cd mcp-server
npm install
npm run typecheck # should print nothing and exit 0npm install настраивает npm-воркспейс, содержащий два поколения MCP SDK одновременно. У них разные имена пакетов, поэтому они сосуществуют без трюков с алиасами:
Пакет | Версия | Используется |
| 1.30.0 |
|
| 2.0.0 |
|
Четыре эксперимента по порядку
Каждый — одна команда. Каждый запускает и останавливает свои собственные серверы — второй терминал не нужен. Прочитайте связанную статью после запуска; каждая объясняет, что вы только что увидели и почему.
Порядок | Команда | Чему учит |
1 |
| Два экземпляра за балансировщиком нагрузки — старый сервер не может даже закончить приветствие; новый не обеспокоен. Начните здесь. |
2 |
| Перезапуск в середине разговора — где на самом деле жила корзина и почему «просто добавьте Redis» работает лишь наполовину. |
3 |
| Подтверждение перед оформлением — 1522 мс удержания сокета против двух запросов по 4 мс, и почему старый способ никогда не сможет работать на serverless. |
4 |
| Подсказки кэша и стабильный порядок — доказательство попаданий в кэш счётчиком, а не секундомером, и денежный аргумент за |
Затем прочитайте архитектурные документы, которые связывают все четыре вместе:
01 — почему существует MCP — проблема N×M и что такое MCP, а что нет. Читайте первым, если вы новичок в MCP.
02 — старая архитектура — рукопожатие, идентификатор сессии и каждая операционная боль, прослеженная до её причины.
03 — новая архитектура — хэндлы, MRTR, подсказки кэша и что вы теряете.
04 — бок о бок — каждое изменение в релизе, где его найти здесь, и честный список того, что этот репозиторий не покрывает.
Управление вручную
Стоит сделать хотя бы раз, потому что вы выбираете темп и можете читать каждую строку лога по мере её появления.
# Old server (port 3001)
npm run old:server
npm run client -- --target old --scenario basic
npm run client -- --target old --scenario checkout
npm run client -- --target old --scenario checkout --decline
# New server (port 3002)
npm run new:server
npm run client -- --target new --scenario basic
npm run client -- --target new --scenario checkout
npm run client -- --target new --scenario discover # server/discover — new spec onlyДва экземпляра плюс балансировщик нагрузки, вручную:
PORT=3002 INSTANCE_ID=A npm run new:server
PORT=3012 INSTANCE_ID=B npm run new:server
PORT=3000 TARGETS=http://localhost:3002,http://localhost:3012 npm run lb
npm run client -- --target new --url http://localhost:3000/mcp --scenario basicСмотрите на оба терминала серверов: один и тот же идентификатор корзины появляется в запросах, обработанных каждым, и никому нет дела.
Эксперименты с curl
Самый прямой способ почувствовать, насколько самодокументируемым является запрос новой спецификации. Запустите npm run new:server, затем:
# A complete, valid request — note how much has to be in it
curl -s -X POST http://localhost:3002/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-H 'mcp-protocol-version: 2026-07-28' \
-H 'mcp-method: tools/call' \
-H 'mcp-name: catalog_list' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"catalog_list","arguments":{},
"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientInfo":{"name":"curl","version":"1"},
"io.modelcontextprotocol/clientCapabilities":{}}}}'Теперь ломайте его по частям и наблюдайте, как меняется ошибка:
Изменение | Ожидаемый результат |
|
|
|
|
уберите заголовок |
|
уберите блок |
|
|
|
| 405 — конечная точка GET исчезла |
Проделайте то же самое со старым сервером — и вам скажут сначала выполнить initialize.
Структура репозитория
packages/
cart-core/ the actual product. zero MCP knowledge. shared by both servers.
server-old/ MCP 2025-11-25. sessions, handshake, held-open streams.
server-new/ MCP 2026-07-28. stateless, handles, MRTR, cache hints.
client-demo/ both clients — one per SDK generation.
round-robin/ ~50-line load balancer. no stickiness, on purpose.
experiments/ four runnable scripts + a write-up each.
docs/ the four architecture notes.
.cart-store/ server-new's shared state. a JSON file. delete it freely.Порядок чтения кода: cart-core/src/cart.ts (что делает продукт) → server-old/src/index.ts → server-new/src/index.ts. Код уровня протокола в обоих серверах прокомментирован построчно; обвязка — нет.
npm run clean удаляет результаты сборки и .cart-store.
Глоссарий
Термины, используемые повсюду, в порядке, в котором они вас укусят.
Балансировщик нагрузки — устройство перед несколькими идентичными копиями вашего сервера, которое распределяет входящие запросы между ними. Политика по умолчанию — round-robin: отправлять каждый запрос следующей копии в списке. Он предполагает, что любая копия может ответить на любой запрос, — и именно это предположение старая спецификация MCP нарушила. Здесь это packages/round-robin, около 50 строк.
Сессия — серверная память о клиенте, охватывающая несколько запросов. В 2025-11-25 сервер выпускал Mcp-Session-Id во время рукопожатия, клиент повторял его в каждом запросе, а сервер использовал его как ключ в карте в памяти. Идентификатор сессии — это указатель в кучу одного процесса, и именно отсюда берутся все проблемы.
Без сохранения состояния — сервер ничего не хранит между запросами. Каждый запрос несёт всё необходимое для его обслуживания. Обратите внимание, что это не означает: корзина всё ещё есть, и она всё ещё хранится. Исчезло состояние, удерживаемое в конкретном процессе, неявно, по ключу соединения. Состояние приложения в общей базе данных полностью совместимо с протоколом без сохранения состояния.
Липкая сессия (привязка сессии) — настройка балансировщика нагрузки так, чтобы все запросы от одного клиента возвращались к одной и той же копии сервера, обычно путём хеширования cookie или заголовка. Стандартный обходной путь для протокола с сохранением состояния. Он работает, но стоит вам равномерного распределения нагрузки, безболезненных развёртываний, полезного автомасштабирования и балансировщика, которому не нужно понимать ваш прикладной протокол. Список затрат в docs/02.
Элиситация — сервер задаёт конечному пользователю вопрос в середине операции («сумма $180.36, подтвердить?»). В старой спецификации сервер отправлял собственный запрос клиенту через удерживаемый открытый поток и блокировался внутри обработчика инструмента, пока человек думал. Эта единственная функция требовала живого процесса, открытого сокета и гарантированной маршрутизации обратно на ту же машину.
MRTR (Multi Round-Trip Requests) — как 2026-07-28 делает элиситацию вместо этого. Сервер возвращает обычный 200 с resultType: "input_required", вопросы в inputRequests и непрозрачный подписанный requestState. Этот запрос завершён — ничего не удерживается. Клиент собирает ответы и отправляет новый запрос (новый идентификатор JSON-RPC) с inputResponses и тем же requestState. Состояние в полёте путешествовало через клиента, а не сидело в процессе, поэтому второй раунд может обслужить совершенно другая машина.
Хэндл — идентификатор, выпущенный сервером, возвращаемый как обычный вывод инструмента, а затем передаваемый обратно как обычный аргумент. cart_create возвращает cartId; cart_add_item принимает его. Так 2026-07-28 заменяет состояние сессии, и разница со старым дизайном в том, кто держит ключ: транспорт, невидимо, против клиента, в значении, которое модель может прочитать и передать дальше. Оговорка: хэндл сам по себе — это токен-носитель; его нужно ограничить аутентифицированным пользователем, что docs/04 честно освещает.
Кэширование подсказок — LLM-провайдеры кэшируют префикс подсказки: отправьте те же начальные байты снова, и провайдер переиспользует своё вычисленное состояние вместо повторной обработки этих токенов, примерно за десятую часть цены ввода. Два свойства делают его хрупким: совпадение по точным байтам и позиционность от начала. Поэтому если ваш список инструментов или каталог находится в префиксе и две записи меняются местами, вы теряете скидку на каждый токен после перестановки. Вот почему 2026-07-28 говорит, что серверы ДОЛЖНЫ возвращать списки в детерминированном порядке, и почему listProducts() сортирует по уникальному id, а не по имени или цене — уникальный ключ даёт полный порядок без связей, которые сортировка могла бы разрешить по-разному. Рабочий пример с ценами: эксперимент 04.
Если запомнить только три вещи
«Без сохранения состояния» не означает «без состояния» — это означает отсутствие состояния, привязанного к процессу. Корзина всё ещё существует. Она переехала туда, куда может добраться любой экземпляр.
Липкие сессии были настоящим исправлением с реальными затратами, и одна из этих затрат — необходимость заставить вашу инфраструктуру разбирать ваш прикладной протокол.
Именно MRTR, а не отсутствие состояния, открыло дорогу serverless. Отсутствие состояния вывело MCP за балансировщик нагрузки. Элиситация всё ещё требовала, чтобы процесс оставался живым, пока человек читает диалог — и именно это serverless устранил.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hosted MCP for e-commerce: live product catalog, stock, and pricing for AI agents.
Remote MCP for Living Stack offer discovery and buyer-authorized checkout preparation.
Remote MCP for Universal Cart merchant readiness MCP, structured receipts, audit logs, and reviewer-
Agent-native commerce with trusted catalog, durable carts, and Stripe Checkout via MCP and UCP.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that enables AI assistants to interact with a complete e-commerce application, providing authentication, product browsing, and shopping cart management through standardized MCP tools.
- AlicenseNot gradedqualityDmaintenanceMCP server for Online Boutique AI Assistant that exposes 18 e-commerce microservice functions via the Model Context Protocol, enabling any MCP client to manage products, carts, checkout, payments, and shipping.MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage products, shopping carts, and orders in an online store through a well-defined MCP API.
- AlicenseAqualityCmaintenanceA UCP-compliant MCP storefront server that exposes product catalog operations (search, cart, checkout) as MCP tools, following UCP schema version 2026-04-08.5MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ritik913553/mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server