MCP-сервер редко «падает» с понятной ошибкой. Чаще всё выглядит так: клиент подключился, но инструментов нет; инструмент вызывается, но возвращает пустоту; или сервер вообще не стартует, а в интерфейсе — короткое «failed to connect» без деталей. Отладка MCP осложняется тем, что сервер работает не сам по себе, а внутри чужого процесса (Claude Desktop, Claude Code, IDE), который забирает его stdin/stdout под протокол. Хорошая новость: у экосистемы есть штатные инструменты, которые снимают почти всю боль, — интерактивный MCP Inspector, логи через stderr и журналы клиента. Разберём по порядку, как ими пользоваться и какие ошибки встречаются чаще всего.
Если вы только начинаете и ещё не написали свой сервер, сначала посмотрите разбор что такое MCP простыми словами и практический гайд по тому, как создать свой MCP-сервер. Здесь же речь именно про отладку уже существующего кода.
Три уровня, на которых что-то ломается
Прежде чем хвататься за инструменты, полезно понимать, где именно проблема. У MCP-сервера три слоя, и на каждом свои симптомы.
Первый — транспорт и подключение: сервер не запускается, процесс сразу умирает, клиент не видит его вовсе. Второй — протокол: соединение установилось, но согласование возможностей (capabilities) прошло не так, инструменты не отдаются или отдаются с неверной схемой. Третий — логика инструмента: всё подключилось, инструмент виден, но при вызове возвращает ошибку или не то, что вы ждёте. Дальше мы идём именно в этом порядке: сначала убеждаемся, что сервер вообще поднимается, потом что он корректно говорит на языке протокола, и только затем ловим баги в самих хендлерах.
MCP Inspector — первый инструмент, который стоит открыть
MCP Inspector — это официальная утилита для тестирования и отладки серверов. Она поставляется одним пакетом @modelcontextprotocol/inspector и запускается через npx без установки. Требуется Node.js версии 22.19.0 или новее. Ключевая идея: Inspector сам выступает MCP-клиентом, подключается к вашему серверу напрямую и позволяет вручную дёргать инструменты, ресурсы и промпты — в отрыве от модели. Это отсекает половину вопросов вида «баг в сервере или в том, как его вызвал ИИ?».
Внутри одного бинарника живут три клиента. Web — полноценный графический интерфейс в браузере, самый богатый вариант и режим по умолчанию. CLI — скриптовый, машиночитаемый клиент для CI, шелл-пайплайнов и кодовых агентов. TUI — интерактивный терминальный интерфейс, когда браузер недоступен или не нужен. Все три построены на общем ядре, так что ведут себя одинаково.
Запуск веб-версии на локальный stdio-сервер выглядит так:
# поднять веб-интерфейс и подключиться к локальному серверу
npx @modelcontextprotocol/inspector node path/to/server/index.js
# или запустить без цели и добавить серверы уже из интерфейса
npx @modelcontextprotocol/inspector
Команда напечатает URL с одноразовым токеном сессии — его нужно открыть в браузере. Если сервер опубликован как npm- или PyPI-пакет, просто передайте команду его запуска как аргументы Inspector:
npx -y @modelcontextprotocol/inspector npx @modelcontextprotocol/server-filesystem ~/Desktop
npx @modelcontextprotocol/inspector uvx mcp-server-git --repository ~/code/mcp/servers.git
Для удалённого сервера по HTTP укажите адрес и транспорт явно:
npx @modelcontextprotocol/inspector --server-url https://api.example.com/mcp --transport http
CLI-режим особенно удобен, когда нужно быстро проверить одну вещь или встроить проверку в скрипт. Например, получить список инструментов или вызвать конкретный инструмент и передать результат в jq:
# список инструментов сервера
npx @modelcontextprotocol/inspector --cli node path/to/server/index.js --method tools/list
# вызов инструмента с аргументом
npx @modelcontextprotocol/inspector --cli https://api.example.com/mcp --transport http \
--method tools/call --tool-name get_weather --tool-arg city=Boston --format json | jq .result
В веб-интерфейсе есть боковая панель мониторинга, которую можно закрепить: она показывает живой поток протокольных сообщений, пока вы работаете. Это лучший способ увидеть, что на самом деле уходит и приходит по проводу, — например, убедиться, что при инициализации обе стороны объявили ожидаемые возможности.
Логирование: пишите в stderr, а не в stdout
Это правило номер один для stdio-серверов, и на нём спотыкаются чаще всего. При локальном stdio-транспорте stdin и stdout заняты под протокол JSON-RPC. Всё, что вы напечатаете в stdout (обычный print в Python, console.log в Node), попадёт прямо в поток протокола и сломает его — клиент получит мусор вместо валидного JSON-RPC и, скорее всего, молча отвалится. Поэтому любые отладочные сообщения нужно писать в stderr: host-приложение автоматически их подхватывает, а протокол остаётся чистым. В Python используйте print(..., file=sys.stderr) или логгер, настроенный на stderr; в Node — console.error.
Для транспорта Streamable HTTP всё иначе: stderr клиентом не захватывается. Тут в дело идут либо ваша собственная серверная агрегация логов, либо стандартный HTTP-инструментарий — curl, панель Network в DevTools браузера, — чтобы смотреть запросы, заголовки Mcp-Session-Id и SSE-потоки.
Есть и универсальный способ, работающий на любом транспорте, — отправлять клиенту лог-уведомление прямо из кода:
// TypeScript
await server.sendLoggingMessage({
level: "info",
data: "Server started successfully",
});
# Python
await ctx.session.send_log_message(
level="info",
data="Server started successfully",
)
MCP определяет восемь уровней важности по стандарту RFC 5424 — от debug до emergency. Клиент может на лету поднять или опустить минимальный уровень запросом logging/setLevel. Логировать по-хорошему стоит ключевые события: шаги инициализации, доступ к ресурсам, выполнение инструментов, ошибочные ситуации и метрики производительности. И обязательно санируйте логи — не давайте ключам, токенам и персональным данным утекать в журнал.
Где смотреть логи клиента
Когда сервер запускается внутри клиента, полезно читать журнал самого клиента — там видно события подключения, ошибки конфигурации и обмен сообщениями. В Claude Desktop лог-файлы лежат здесь:
# macOS
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
# Windows
type "%APPDATA%\Claude\logs\mcp*.log"
Флаг -F в tail держит файл открытым и показывает новые строки в реальном времени — удобно перезапустить сервер и сразу увидеть, что произошло. Важный нюанс: чтобы изменения подхватились, клиент нужно перезапустить. Для изменений в конфигурации достаточно рестарта клиента; при правках кода сервера Claude Desktop нужно полностью закрыть и открыть заново — просто закрыть окно недостаточно.
Типичные ошибки и как их чинить
Рабочая директория не та, что вы думаете. Когда клиент запускает stdio-сервер, рабочая директория может быть неопределённой (например, / на macOS), потому что сам клиент мог быть запущен откуда угодно. Из-за этого относительные пути к файлам, базам, .env ломаются. Решение простое: везде — в конфиге и в коде — используйте абсолютные пути. Когда вы тестируете сервер напрямую из терминала, рабочая директория будет там, где вы запустили команду, поэтому в терминале всё работает, а внутри клиента — нет. Это классическая ловушка.
Переменные окружения не наследуются. Серверы, запущенные по stdio, наследуют лишь ограниченный, зависящий от платформы набор переменных окружения. Если сервер полагается на API_KEY из вашего шелла, внутри клиента его может не оказаться. Передавайте нужные переменные явно через ключ env в конфигурации клиента:
{
"mcpServers": {
"myserver": {
"command": "mcp-server-myapp",
"env": {
"MYAPP_API_KEY": "some_key"
}
}
}
}
Сервер не инициализируется. Самые частые причины — проблемы с путями (неверный путь к исполняемому файлу, отсутствие нужных файлов, права доступа; помогает абсолютный путь в command), ошибки конфигурации (невалидный JSON, пропущенные обязательные поля, несовпадение типов) и проблемы окружения (отсутствующие или неверные переменные, ограничения прав).
Соединение рвётся или инструменты не появляются. Пройдите по чек-листу: проверьте логи клиента, убедитесь, что процесс сервера жив, протестируйте сервер отдельно через Inspector, сверьте совместимость версий протокола и — важный пункт — проверьте согласование возможностей. Ошибка -32602 (стандартный JSON-RPC «Invalid params») возникает во многих контекстах; одна из частых причин — сервер шлёт запросы sampling или elicitation клиенту, который эту возможность не объявлял. Посмотрите обмен initialize в мониторе Inspector и убедитесь, что обе стороны объявили ровно то, что вы ожидаете.
Рабочий цикл отладки
Сложив всё вместе, получаем несложный, но надёжный порядок действий. На этапе разработки держите Inspector открытым и проверяйте каждую новую функцию вручную сразу после того, как написали хендлер, — так баг в логике инструмента ловится за секунды, а не всплывает потом внутри диалога с моделью. Добавляйте точки логирования в ключевых местах и пишите их в stderr. Когда базовая функциональность работает, переходите к интеграционному тесту в целевом клиенте: запускайте сервер там, где он будет жить, следите за mcp*.log и отдельно проверяйте обработку ошибок. При любой правке кода не забывайте про полный перезапуск клиента, иначе будете отлаживать старую версию.
Хорошая привычка — относиться к Inspector как к «быстрой итерации», а к клиенту как к «финальной проверке». Большинство проблем видно уже на первом уровне: если сервер корректно отвечает Inspector'у, но не работает в Claude Desktop, дело почти всегда в окружении, путях или в том, что клиент не перезапустили. Разобраться, какой сервер вообще ставить под задачу и чем они отличаются по транспорту, помогает обзор MCP-серверов.
Отладка MCP перестаёт быть гаданием, как только у вас появляется правильная оптика: Inspector показывает, что уходит по проводу, stderr и лог-уведомления рассказывают, что происходит внутри сервера, а журнал клиента ловит проблемы окружения. Начинайте с транспорта, поднимайтесь к протоколу, заканчивайте логикой инструмента — и большинство «загадочных» сбоев оказываются вполне понятными абсолютными путями, забытыми переменными окружения или случайным print в stdout.
Частые вопросы
Inspector подключается к серверу напрямую и позволяет вручную вызывать инструменты, ресурсы и промпты в отрыве от модели, а также видеть живой поток протокольных сообщений. Это сразу отделяет баги самого сервера от того, как его вызвал ИИ, и даёт быструю итерацию без перезапуска клиента.
Чаще всего дело в рабочей директории и переменных окружения. Клиент запускает stdio-сервер с неопределённой рабочей директорией и наследует лишь ограниченный набор переменных окружения, поэтому относительные пути и переменные из вашего шелла ломаются. Используйте абсолютные пути и задавайте нужные переменные через ключ env в конфигурации.
У stdio-сервера stdout занят под протокол JSON-RPC. Любой вывод в stdout попадёт прямо в поток протокола и сломает его — клиент получит невалидный JSON и отвалится. Пишите отладку в stderr (print в sys.stderr, console.error) или отправляйте лог-уведомления через API — они работают на любом транспорте.
Источники
- 1.MCP Inspector — официальная документация Model Context Protocolhttps://modelcontextprotocol.io/legacy/tools/inspector
- 2.Debugging — руководство по отладке MCP (modelcontextprotocol.io)https://modelcontextprotocol.io/docs/tools/debugging



