Scaffold MCP-сервера: структура проекта и зависимости
Уроки курсаScaffold MCP-сервера: структура проекта и зависимости
Типичные ошибки при запуске и их устранение
Даже когда структура проекта правильная и код точки входа написан верно, первый запуск нередко встречает вас сообщением об ошибке. Три из них встречаются особенно часто и при этом не имеют очевидного объяснения в документации SDK. Ошибка 1: «Package subpath not found» при импорте SDK
Это происходит, когда импорт написан без указания подпути к конкретному модулю:
// Неправильно — вызовет ошибку «Package subpath not found»
import { Server } from '@modelcontextprotocol/sdk';
Пакет @modelcontextprotocol/sdk не экспортирует всё из корня — его API разбит на подмодули. Правильный импорт выглядит так:
// Правильно
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
Обратите внимание на расширение .js в путях — оно обязательно даже в TypeScript-проекте, потому что Node.js резолвит модули по расширению файла после компиляции. ---
Ошибка 2: сервер запускается и сразу завершается
Если процесс стартует и тут же выходит без каких-либо сообщений об ошибке, скорее всего, потерян await у server.connect():
// Неправильно — connect() запускается, но Node.js не ждёт результата
server.connect(transport);
console.error('Server running on stdio');
server.connect() — асинхронная операция. Без await Node.js вызывает её и немедленно продолжает выполнение до конца скрипта, после чего процесс завершается. Сервер даже не успевает начать слушать stdio.
// Правильно
await server.connect(transport);
console.error('Server running on stdio');
Этот вызов должен находиться внутри async-функции или на верхнем уровне модуля с поддержкой top-level await (для этого нужен "type": "module" в package.json или TypeScript с соответствующим module-таргетом). ---
Ошибка 3: конфликт CommonJS и ESM
Это самая коварная из трёх ошибок, потому что симптомы могут быть разными: от SyntaxError: Cannot use import statement до ERR_REQUIRE_ESM или молчаливых сбоев при резолве путей. Причина — несогласованность между двумя файлами конфигурации. В tsconfig.json параметр module определяет, во что TypeScript компилирует import/export. В package.json параметр "type" определяет, как Node.js трактует .js-файлы — как CommonJS или ESM. Если они рассогласованы, скомпилированный код и рантайм «говорят» на разных диалектах:
// tsconfig.json — настроен на ESNext
{
"compilerOptions": {
"module": "ESNext"
}
}
// package.json — без "type": "module"
// Node.js будет трактовать .js как CommonJS
// → конфликт: ESM-синтаксис в CommonJS-контексте
Есть два согласованных варианта. Первый — CommonJS-стек (проще для старта):
// tsconfig.json
{ "compilerOptions": { "module": "commonjs", "target": "ES2020" } }
// package.json — "type" не указан (или "commonjs")
Второй — ESM-стек:
// tsconfig.json
{ "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext" } }
// package.json
{ "type": "module" }
Для первого scaffold-проекта рекомендуется CommonJS: меньше нюансов с резолвом путей и совместимостью с ts-node без дополнительных флагов.
