Skip to content

LSP не стартует в VS Code: сервер пишет лог в stdout и ломает протокол (plain LSP без MCP) #4228

Description

@regniws

Версия

  • bsl-language-server: v1.0.2
  • Клиент: расширение VS Code 1c-syntax.language-1c-bsl 2.1.0
  • ОС: macOS (arm64), native-app сборка с bundled JRE
  • Режим запуска: классический LSP по stdio, MCP выключен (дефолт расширения)

Что происходит

При запуске сервера в режиме «голый LSP по stdio» (без --mcp) в stdout попадают строки лога Spring Boot. Канал stdio занят протоколом LSP, поэтому клиент получает не JSON-RPC, а текст лога и падает:

Header must provide a Content-Length property.
{... DEBUG ... o.s.boot.SpringApplication : Loading source class ...BSLLSPLauncher}
...
Server process exited with signal SIGKILL.
The BSL Language Server server crashed 5 times in the last 3 minutes. The server will not be restarted.

После 5 крашей подряд VS Code перестаёт перезапускать сервер — LSP не работает совсем.

Причина

В BOOT-INF/classes/logback-spring.xml цель консольного аппендера уводится в System.err только для профилей mcp-stdio/lsp-mcp:

<springProfile name="mcp-stdio | lsp-mcp">
    <property name="CONSOLE_TARGET" value="System.err"/>
</springProfile>
<springProfile name="!(mcp-stdio | lsp-mcp)">
    <property name="CONSOLE_TARGET" value="System.out"/>
</springProfile>

В режиме чистого LSP по stdio (MCP off) ни один из этих профилей не активен → CONSOLE_TARGET = System.out. Но в LSP-stdio именно System.out — это транспорт протокола. Стартовые логи (до того как поднимется LANGUAGE_CLIENT_AWARE-аппендер и начнёт слать через window/logMessage) бьют прямо в канал и ломают кадрирование.

Воспроизведение

  1. VS Code + расширение language-1c-bsl 2.1.0, MCP выключен (дефолт).
  2. Открыть любой .bsl.
  3. Сервер падает с Header must provide a Content-Length property, после 5 раз — окончательно.

Запуск бинаря руками (для сравнения каналов):

BIN=".../bsl-language-server.app/Contents/MacOS/bsl-language-server"

# plain LSP-stdio — stdout периодически загрязняется логом (гонка на старте)
"$BIN"            >out.txt 2>err.txt

# с --mcp (профиль lsp-mcp) — stdout чистый, только Content-Length-кадры
"$BIN" --mcp --server.port=8025  >out.txt 2>err.txt

В режиме --mcp stdout содержит только корректные Content-Length-кадры (window/logMessage и пр.) — подтверждает, что дело в выборе CONSOLE_TARGET по профилю.

Нюанс (плавающесть)

В чистом терминале plain-режим иногда даёт пустой stdout (никто не шлёт initialize, процесс быстро убивается). Под реальным LSP-хендшейком в VS Code стартовые строки Spring успевают попасть в stdout — отсюда «плавающесть» бага.

Обходной путь

Включить MCP — профиль становится lsp-mcp, лог уходит в System.err, канал LSP остаётся чистым:

"language-1c-bsl.languageServerMcpEnabled": true,
"language-1c-bsl.languageServerMcpPort": "8025"

Предлагаемое решение

Любой из вариантов:

  1. На стороне сервера: распространить CONSOLE_TARGET = System.err на ЛЮБОЙ stdio-режим (включая чистый LSP без MCP) — в LSP-stdio System.out нельзя использовать для логов в принципе. Достаточно сделать System.err дефолтом, а System.out оставить только для режимов, где stdout свободен (например, websocket-mcp).
  2. На стороне расширения: при запуске LSP по stdio всегда активировать профиль с System.err (или передавать соответствующий флаг/-Dspring.profiles.active).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions