Разместите удалённый MCP-сервер
Разверните MCP-сервер как HTTP-приложение, когда клиентам нужен удалённый URL. Этот пример обслуживает один арифметический инструмент, валидирует bearer-токен и предоставляет эндпоинт здоровья. Он использует Streamable HTTP; локальный сервер stdio сам по себе не может обслуживать удалённых клиентов.
Прежде чем начать
Вам понадобятся Node.js 22, Lizard CLI, проект, в который можно сделать деплой, и MCP-клиент, принимающий настроенный bearer-токен. В примере используется @modelcontextprotocol/sdk 1.30.0 в режиме без сохранения состояния. Он не предоставляет OAuth-авторизацию, доступ из браузера или провайдера идентификации.
Исполняемые файлы находятся в remote-mcp-node. Используйте зафиксированный lockfile. Локальный дымовый тест проверяет инициализацию, обнаружение инструментов, вызов инструмента и отклонение без валидного токена. Проверка деплоя также должна подтвердить работу публичного прокси и TLS-пути.
Запуск локально
Из директории примера:
npm ci
npm test
node issue-token.mjs
export MCP_PUBLIC_KEY="$(cat .mcp-public-key.pem)"
export MCP_ALLOWED_HOSTS=127.0.0.1,localhost
npm startСгенерированный токен истекает через один час. Приватный ключ подписи не сохраняется. Используйте свой собственный процесс выпуска и ротации токенов для постоянного деплоя; держите его приватный ключ вне сервера.
В другом терминале:
export MCP_URL=http://127.0.0.1:8000/mcp
export MCP_TOKEN="$(cat .mcp-token)"
node client.mjsКлиент проверяет инициализацию, обнаружение инструментов и результат 5, затем печатает MCP initialize, tools/list and tools/call passed: 5. /health возвращает ok; запрос к /mcp без валидного токена возвращает 401.
Деплой приложения
Сохраните Dockerfile и lockfile примера. Из директории, содержащей их:
lizard init --name mcp-example
lizard add --service mcp
lizard domain --service mcp --jsonВыполните вход через lizard login, если команда сообщает, что требуется аутентификация. init связывает проект; add создаёт именованный сервис. Команда domain назначает его хостнейм перед деплоем. Используйте возвращённый hostname ниже, без https:// или пути:
lizard secrets set MCP_PUBLIC_KEY="$(cat .mcp-public-key.pem)" --service mcp
lizard secrets set MCP_ALLOWED_HOSTS=YOUR_SERVICE_HOSTNAME --service mcpЗадайте оба значения перед первым деплоем. Затем запустите:
lizard up --service mcp --port 8000
lizard logs --build --service mcp --json
lizard logs --service mcp --json
lizard ps --jsonНа macOS с Lizard CLI 0.3.92 используйте COPYFILE_DISABLE=1 lizard up --service mcp --port 8000, чтобы исключить метаданные AppleDouble из архива. Более поздний релиз CLI может включать исправление архива. Проверяйте финальное событие деплоя и публичный эндпоинт; не полагайтесь только на код выхода этой версии CLI после неудачной сборки. server.mjs слушает на 0.0.0.0 и читает PORT, с 8000 в качестве значения по умолчанию. Команда деплоя устанавливает порт сервиса в 8000. Настройте публичный ключ как многострочное значение переменной окружения; не загружайте приватный ключ подписи или файл токена.
Проверьте публичный эндпоинт
Установите MCP_URL в https://YOUR_SERVICE_HOSTNAME/mcp, сохраните валидный токен в окружении клиента и запустите node client.mjs. Проверьте все три результата:
/healthвозвращает200по HTTPS./mcpотклоняет клиента без валидного токена.- Аутентифицированный клиент перечисляет инструменты и вызывает
add, возвращая5.
Здоровый процесс сам по себе не доказывает, что MCP-рукопожатие или стриминговый ответ работают через публичный прокси.
Устранение неполадок
| Результат | Проверка |
|---|---|
| Процесс завершается при запуске | MCP_PUBLIC_KEY должен содержать публичный PEM-ключ; MCP_ALLOWED_HOSTS должен содержать хостнейм сервиса. |
401 | Токен должен использовать RS256, соответствовать issuer и audience mcp-example и не должен быть истёкшим. |
403 | Сопоставьте хостнейм запроса с MCP_ALLOWED_HOSTS. Браузерные источники в этом примере не включены. |
405 с валидным токеном | Этот stateless MCP-эндпоинт принимает протоколные запросы через POST. Используйте MCP-клиент. Браузерный GET без токена сначала возвращает 401. |
| Локальный тест проходит, но удалённый вызов не работает | Проверьте порт, HTTPS, стриминг ответа и таймауты прокси. |
Ограничения и стоимость
Этот пример не хранит пользовательские сессии или постоянные файлы в памяти сервера. Добавьте базу данных для долговременного состояния приложения и проверяйте доступ по пользователю перед раскрытием приватных инструментов. Для клиентов, требующих OAuth-обнаружение или интерактивный вход, добавьте поддерживаемого OAuth-провайдера вместо распространения этого тестового токена.
HTTP-процесс может оставаться активным между вызовами. Проверьте цены, лимиты и измеренные CPU/память; пустая очередь запросов не означает отсутствие расходов.
Следующие шаги
См. результаты сценарийных тестов для проверенных версий, облачных результатов и оставшихся лимитов.