Версия
- 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) бьют прямо в канал и ломают кадрирование.
Воспроизведение
- VS Code + расширение
language-1c-bsl 2.1.0, MCP выключен (дефолт).
- Открыть любой
.bsl.
- Сервер падает с
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 остаётся чистым:
Предлагаемое решение
Любой из вариантов:
- На стороне сервера: распространить
CONSOLE_TARGET = System.err на ЛЮБОЙ stdio-режим (включая чистый LSP без MCP) — в LSP-stdio System.out нельзя использовать для логов в принципе. Достаточно сделать System.err дефолтом, а System.out оставить только для режимов, где stdout свободен (например, websocket-mcp).
- На стороне расширения: при запуске LSP по stdio всегда активировать профиль с
System.err (или передавать соответствующий флаг/-Dspring.profiles.active).
Версия
1c-syntax.language-1c-bsl2.1.0Что происходит
При запуске сервера в режиме «голый LSP по stdio» (без
--mcp) в stdout попадают строки лога Spring Boot. Канал stdio занят протоколом LSP, поэтому клиент получает не JSON-RPC, а текст лога и падает:После 5 крашей подряд VS Code перестаёт перезапускать сервер — LSP не работает совсем.
Причина
В
BOOT-INF/classes/logback-spring.xmlцель консольного аппендера уводится вSystem.errтолько для профилейmcp-stdio/lsp-mcp:В режиме чистого LSP по stdio (MCP off) ни один из этих профилей не активен →
CONSOLE_TARGET = System.out. Но в LSP-stdio именноSystem.out— это транспорт протокола. Стартовые логи (до того как подниметсяLANGUAGE_CLIENT_AWARE-аппендер и начнёт слать черезwindow/logMessage) бьют прямо в канал и ломают кадрирование.Воспроизведение
language-1c-bsl2.1.0, MCP выключен (дефолт)..bsl.Header must provide a Content-Length property, после 5 раз — окончательно.Запуск бинаря руками (для сравнения каналов):
В режиме
--mcpstdout содержит только корректныеContent-Length-кадры (window/logMessageи пр.) — подтверждает, что дело в выбореCONSOLE_TARGETпо профилю.Нюанс (плавающесть)
В чистом терминале plain-режим иногда даёт пустой stdout (никто не шлёт
initialize, процесс быстро убивается). Под реальным LSP-хендшейком в VS Code стартовые строки Spring успевают попасть в stdout — отсюда «плавающесть» бага.Обходной путь
Включить MCP — профиль становится
lsp-mcp, лог уходит вSystem.err, канал LSP остаётся чистым:Предлагаемое решение
Любой из вариантов:
CONSOLE_TARGET = System.errна ЛЮБОЙ stdio-режим (включая чистый LSP без MCP) — в LSP-stdioSystem.outнельзя использовать для логов в принципе. Достаточно сделатьSystem.errдефолтом, аSystem.outоставить только для режимов, где stdout свободен (например,websocket-mcp).System.err(или передавать соответствующий флаг/-Dspring.profiles.active).