Linux
Как запускать MCP-сервер на Linux - stdio запускает клиент, Streamable HTTP работает как служба systemd за обратным прокси, и что из этого требует сам протокол
описана редакция 2026-07-28, сверено со спецификацией и документацией systemd и nginx 4 октября 2026
Сервер stdio запускает клиент
Заголовок раздела «Сервер stdio запускает клиент»По странице stdio клиент запускает сервер как дочерний процесс и общается с ним через stdin и stdout. Отсюда три следствия для Linux.
- Службу systemd для сервера stdio создавать не нужно. Запущенный без клиента, такой процесс ждёт сообщений на
stdin, которых никто не пришлёт. - Команду запуска вы указываете в настройках клиента. Где они лежат, смотрите на странице Клиенты MCP.
- Журнал сервера идёт в
stderr. Вstdoutсервер не должен писать ничего, кроме сообщений MCP.
Завершение тоже ведёт клиент. Ему следует закрыть stdin сервера, подождать выхода и только потом завершить процесс принудительно. Спецификация отмечает, что в POSIX это обычно SIGTERM, затем SIGKILL. Серверу следует выходить сразу, как только stdin закрыт.
Что протокол требует от сервера Streamable HTTP
Заголовок раздела «Что протокол требует от сервера Streamable HTTP»По странице Streamable HTTP:
| Требование | Сила |
|---|---|
| Один адрес, принимающий POST | обязан |
Проверка заголовка Origin у всех входящих соединений | обязан |
Ответ 403 Forbidden, если Origin есть и он недопустим | обязан |
При локальном запуске слушать только 127.0.0.1, а не 0.0.0.0 | следует |
| Проверка подлинности всех соединений | следует |
Заголовок X-Accel-Buffering: no при открытии потока SSE | следует |
Спецификация объясняет первые меры так: без них сайт в браузере может через подмену DNS обратиться к MCP-серверу на вашей машине.
Проверку Origin выполняет сам сервер. Обратный прокси её не отменяет: для сервера за прокси требование остаётся тем же. Подробнее - на странице Безопасность сервера.
Что изменилось по сравнению с Legacy
Заголовок раздела «Что изменилось по сравнению с Legacy»- В Modern нет сессий протокола и нет потока по GET. Серверу только для Modern следует отвечать на GET и DELETE кодом
405 Method Not Allowed, а заголовокMcp-Session-Idне читать. - Ответ на запрос приходит либо одним объектом JSON, либо потоком SSE, привязанным к этому запросу. Долгий поток остаётся только у запроса
subscriptions/listen. - Транспорта на WebSocket в спецификации нет. Заголовки
Upgradeв настройке прокси для MCP не нужны.
Практика, не правило MCP
Заголовок раздела «Практика, не правило MCP»Серверу Streamable HTTP нужна машина с постоянным адресом. Виртуальный сервер для него можно арендовать у FirstVDS или Aéza.
Всё ниже взято из документации systemd и nginx. Спецификация MCP этого не требует.
Служба systemd
Заголовок раздела «Служба systemd»[Unit]Description=MCP server (Streamable HTTP)After=network-online.targetWants=network-online.target
[Service]# Команду запуска и рабочий каталог подставьте своиExecStart=/opt/mcp-server/bin/startWorkingDirectory=/opt/mcp-serverUser=mcpGroup=mcpRestart=on-failure
# Ограничения из systemd.execNoNewPrivileges=trueProtectSystem=strictProtectHome=truePrivateTmp=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действует между двумя последовательными чтениями, а не на весь ответ. Если сервер ничего не передал за это время, соединение закрывается.
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.