Model Context Protocol (MCP) быстро стал стандартом для подключения инструментов к Claude Desktop, Cursor и другим клиентам. Но если вы пишете MCP-серверы, то наверняка сталкивались с тем, что ошибки в них проявляются не сразу и не очевидно. Случайный вывод в stdout, отсутствие аннотаций безопасности или скрытые инструкции в описаниях инструментов могут привести к поломке клиента или уязвимостям. В этой статье я расскажу, как создал линтер для MCP, какие проблемы он помогает найти и какие баги обнаружились даже в официальных серверах.
Почему MCP-серверы нуждаются в линтинге
MCP использует JSON-RPC поверх stdio или HTTP. Любое нарушение протокола — например, лишний вывод в stdout — ломает поток сообщений, и клиент перестаёт отвечать. Кроме того, инструменты MCP могут выполнять опасные действия: удаление файлов, запись в базы данных, отправку запросов. Если для такого инструмента не указана аннотация destructiveHint, агент может выполнить его без подтверждения пользователя. Ещё одна проблема — prompt injection: в описании инструмента можно спрятать инструкцию, которая заставит модель раскрыть контекст или выполнить нежелательное действие. Всё это трудно отловить вручную, особенно когда серверов много.
Какие проверки реализованы в линтере
Я написал mcp-linter на чистом Node.js/TypeScript без сторонних зависимостей. Он анализирует код сервера и конфигурацию, применяя 34 правила, разделённые на категории:
- Протокол: проверка на наличие вывода в stdout, корректность JSON-RPC, соответствие версии MCP, обработка ошибок.
- Безопасность: наличие аннотаций destructiveHint для опасных инструментов, проверка описаний на подозрительные паттерны (prompt injection), ограничение прав доступа.
- Качество кода: использование устаревших методов, отсутствие валидации входных параметров, неинформативные сообщения об ошибках.
- Производительность: избыточные вызовы, блокирующие операции.
Каждое правило имеет вес, по сумме баллов сервер получает оценку здоровья от A+ до F (0–100). Это помогает быстро понять общее состояние проекта.
Как линтер помогает исправлять ошибки
Помимо диагностики, mcp-linter умеет автоматически исправлять некоторые проблемы. Флаг --fix применяет безопасные правки: удаляет лишние console.log, добавляет недостающие аннотации, форматирует описания. Автоисправления не затрагивают логику работы сервера, поэтому их можно запускать в CI. Для интеграции с GitHub Security линтер экспортирует отчёт в формате SARIF v2.1.0. Это позволяет видеть предупреждения прямо в интерфейсе GitHub и блокировать merge при критических ошибках. Готовый GitHub Action можно добавить в workflow за пару строк.
Что показала проверка официальных серверов
Самый интересный результат — запуск линтера на официальных MCP-серверах от Anthropic. Оказалось, что даже в них встречаются недочёты. Например, в некоторых серверах отсутствовали аннотации destructiveHint для инструментов, которые изменяют состояние (запись в память, удаление сущностей). Это значит, что агент мог выполнить их без дополнительного подтверждения. Также нашлись описания инструментов с конструкциями, похожими на prompt injection, хотя и не обязательно вредоносными. Были и мелкие нарушения протокола: вывод отладочной информации в stdout в определённых условиях. Эти находки подтверждают, что автоматическая проверка полезна даже для зрелых проектов.
Как начать использовать линтер
Самый простой способ — запустить через npx без установки:
- npx mcp-linter -- npx -y @modelcontextprotocol/server-memory — проверит сервер памяти из официального репозитория.
- Для своего сервера укажите команду запуска или путь к файлу конфигурации.
- Добавьте флаг --fix для автоисправления.
- Для экспорта в SARIF используйте --format sarif --output report.sarif.
Линтер не заменяет ручной аудит, но помогает поймать типовые ошибки на раннем этапе. Если вы разрабатываете MCP-сервер, добавьте его в свой CI-пайплайн — это займёт немного времени, но снизит риск неприятных сюрпризов в продакшене.
Типичные ошибки и как их избежать
Вот несколько рекомендаций, которые я вывел из своего опыта и результатов линтинга:
- Никогда не пишите в stdout — используйте stderr для логов или специальные механизмы MCP.
- Всегда указывайте аннотации для инструментов, которые могут изменить данные или выполнить опасные действия. Это не только безопасность, но и предсказуемость для пользователя.
- Проверяйте описания инструментов на наличие скрытых инструкций. Лучше избегать конструкций, которые могут быть интерпретированы моделью как команды.
- Валидируйте входные параметры — это предотвращает неожиданное поведение и атаки.
- Используйте линтер в CI — автоматическая проверка экономит время и нервы.
Создание линтера было полезным упражнением: я лучше понял протокол MCP и его слабые места. Надеюсь, что инструмент поможет сообществу писать более надёжные и безопасные серверы.