Перейти к содержимому
Выберите тему

Linux

Как запускать MCP-сервер на Linux - stdio запускает клиент, Streamable HTTP работает как служба systemd за обратным прокси, и что из этого требует сам протокол

описана редакция 2026-07-28, сверено со спецификацией и документацией systemd и nginx 4 октября 2026

По странице stdio клиент запускает сервер как дочерний процесс и общается с ним через stdin и stdout. Отсюда три следствия для Linux.

  • Службу systemd для сервера stdio создавать не нужно. Запущенный без клиента, такой процесс ждёт сообщений на stdin, которых никто не пришлёт.
  • Команду запуска вы указываете в настройках клиента. Где они лежат, смотрите на странице Клиенты MCP.
  • Журнал сервера идёт в stderr. В stdout сервер не должен писать ничего, кроме сообщений MCP.

Завершение тоже ведёт клиент. Ему следует закрыть stdin сервера, подождать выхода и только потом завершить процесс принудительно. Спецификация отмечает, что в POSIX это обычно SIGTERM, затем SIGKILL. Серверу следует выходить сразу, как только stdin закрыт.

По странице Streamable HTTP:

Требование Сила
Один адрес, принимающий POST обязан
Проверка заголовка Origin у всех входящих соединений обязан
Ответ 403 Forbidden, если Origin есть и он недопустим обязан
При локальном запуске слушать только 127.0.0.1, а не 0.0.0.0 следует
Проверка подлинности всех соединений следует
Заголовок X-Accel-Buffering: no при открытии потока SSE следует

Спецификация объясняет первые меры так: без них сайт в браузере может через подмену DNS обратиться к MCP-серверу на вашей машине.

Проверку Origin выполняет сам сервер. Обратный прокси её не отменяет: для сервера за прокси требование остаётся тем же. Подробнее - на странице Безопасность сервера.

  • В Modern нет сессий протокола и нет потока по GET. Серверу только для Modern следует отвечать на GET и DELETE кодом 405 Method Not Allowed, а заголовок Mcp-Session-Id не читать.
  • Ответ на запрос приходит либо одним объектом JSON, либо потоком SSE, привязанным к этому запросу. Долгий поток остаётся только у запроса subscriptions/listen.
  • Транспорта на WebSocket в спецификации нет. Заголовки Upgrade в настройке прокси для MCP не нужны.

Серверу Streamable HTTP нужна машина с постоянным адресом. Виртуальный сервер для него можно арендовать у FirstVDS или Aéza.

Всё ниже взято из документации systemd и nginx. Спецификация MCP этого не требует.

/etc/systemd/system/mcp-server.service, схема
[Unit]
Description=MCP server (Streamable HTTP)
After=network-online.target
Wants=network-online.target
[Service]
# Команду запуска и рабочий каталог подставьте свои
ExecStart=/opt/mcp-server/bin/start
WorkingDirectory=/opt/mcp-server
User=mcp
Group=mcp
Restart=on-failure
# Ограничения из systemd.exec
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target

Пример схематичный, составлен по справочным страницам systemd и здесь не запускался. Путь /opt/mcp-server/bin/start, имя службы и пользователь mcp условные.

Что означают директивы, по справочной странице systemd.exec и странице systemd.service:

Директива Что делает
User=, Group= задают пользователя и группу, от имени которых работает процесс
Restart= определяет, запускать ли службу заново, когда процесс вышел, был убит или истекло время ожидания
NoNewPrivileges=true процесс и его потомки не могут получить новые привилегии через execve()
ProtectSystem=strict вся файловая система доступна только для чтения, кроме /dev/, /proc/ и /sys/
ProtectHome=true каталоги /home/, /root и /run/user недоступны и выглядят пустыми
PrivateTmp=true у службы свои /tmp/ и /var/tmp/, не общие с другими процессами

Пользователя можно не создавать заранее: DynamicUser= выделяет пару пользователя и группы на время работы службы. Подходит ли это вашему серверу, зависит от того, какие файлы ему нужны.

По странице systemd.exec стандартный вывод службы по умолчанию направляется туда, куда указывает DefaultStandardOutput=, а его значение по умолчанию - journal. Отдельно настраивать файлы журнала не нужно.

Читает журнал команда journalctl. По её справочной странице параметр -u показывает сообщения одной службы:

Журнал службы
journalctl -u mcp-server.service

Команда взята из справочной страницы journalctl и здесь не запускалась.

Протокольное журналирование через notifications/message в редакции 2026-07-28 объявлено устаревшим. Журнал процесса в journal от него не зависит.

Сервер слушает 127.0.0.1, а снаружи его видит прокси, который принимает TLS. Главное требование к прокси - не задерживать потоковые ответы.

По документации модуля proxy в nginx:

  • proxy_buffering по умолчанию включена. При включённой буферизации nginx сначала собирает ответ сервера в буферы. При выключенной ответ передаётся клиенту сразу по мере получения.
  • Буферизацию можно включить или выключить для одного ответа, передав yes или no в заголовке X-Accel-Buffering. Именно этот заголовок спецификация MCP рекомендует серверу отправлять. Способность можно отключить директивой proxy_ignore_headers, поэтому проверьте, что в вашей настройке её нет для этого заголовка.
  • proxy_read_timeout действует между двумя последовательными чтениями, а не на весь ответ. Если сервер ничего не передал за это время, соединение закрывается.
Фрагмент настройки nginx, схема
location /mcp {
proxy_pass http://127.0.0.1:ВАШ_ПОРТ;
proxy_buffering off;
}

Пример схематичный, составлен по документации nginx и здесь не запускался. Блок server, TLS и остальные директивы опущены.

Последний пункт связан с примечанием в спецификации: для долгих потоков, прежде всего у subscriptions/listen, серверу предлагается время от времени отправлять строку-комментарий SSE. Это не требование, а совет, и он как раз не даёт посреднику закрыть тихое соединение. Сколько именно ждать, задаёт ваша настройка прокси. Спецификация чисел не называет.

  • Правила межсетевого экрана, AppArmor, SELinux и Fail2ban не приводятся: готовых проверенных образцов для MCP в первоисточниках нет.
  • Пути к файлам настроек клиентов на Linux здесь не повторяются, они на страницах клиентов.
  • Числа - размеры буферов, пределы соединений, время ожидания - не приводятся. Их нет в спецификации, и подбирать их нужно по измерениям на вашем сервере.
  • Какой обратный прокси лучше, страница не оценивает. nginx взят потому, что его прямо называет спецификация в рекомендации про X-Accel-Buffering.