Мой сервер MCP stdio работал отлично каждый раз, когда я его тестировал. Затем я неделю пользовался им от Claude Code и записывал каждый вызов: 212 вызовов инструментов, 41 сбой. Это 19% с сервера с шестью инструментами и без сложной логики. Ни один из 41 нас...
Мой сервер MCP stdio работал отлично каждый раз, когда я его тестировал. Затем я неделю пользовался им от Claude Code и записывал каждый вызов: 212 вызовов инструментов, 41 сбой. Это 19% с сервера с шестью инструментами и без сложной логики.
Ни один из 41 кода не содержал ошибок в моих инструментах. Все они были получены из байтов, попавших на стандартный вывод, которые не были JSON-RPC. Одним из них была отладочная печать(). Остальные 40 были более хитрыми, и именно поэтому я пишу это.
ТЛ;ДР
Сервер MCP stdio общается со своим клиентом через стандартный вывод. Каждое сообщение представляет собой одну строку JSON. Любой другой байт на стандартном выводе повреждает поток.
print(), console.log() и дочерние процессы, наследующие ваш стандартный вывод (subprocess.run(["git", "pull"])) — все пишут в этот канал.
print(..., end="") не разрывает собственную строку. Он приклеивается к следующему ответу JSON, поэтому действительный ответ отбрасывается, и вызов зависает до истечения времени ожидания.
Исправление: отправлять журналы в stderr, захватывать выходные данные подпроцесса и при запуске указывать дескриптор файла 1 на stderr, сохраняя при этом частный дескриптор протокола.
Добавьте дымовой тест, который утверждает, что каждая строка стандартного вывода анализируется как JSON. Он бы отразил все 41 сбой.
Что я строил?
Персональный MCP-сервер «второго мозга» на Python с использованием официальной лицензии.