fix(lsp): omit optional Content-Type header from outgoing messages (#1442)

Per the LSP spec, Content-Type is optional and defaults to
application/vscode-jsonrpc; charset=utf-8 (the exact value we were
sending). Spec-compliant servers behave identically with or without it.

In practice some servers have stricter parsers. Notably, Godot's
GDScript LSP (LSPeer::handle_data in
modules/gdscript/language_server/gdscript_language_protocol.cpp)
extracts the body length via header.substr(16).to_int() and silently
drops messages that contain any header beyond Content-Length.

Sending only Content-Length is interoperable across the spec-compliant
servers we use today and unblocks Godot's LSP. Also tightens the type
signature of create_message from tuple[bytes, bytes, bytes] to
tuple[bytes, bytes] now that there is no Content-Type element.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael PanchenkoandClaude Opus 4.7 authored and GitHub committed 2026-05-04 11:43:04 +02:00
commit 024d31ba22
1 file changed
+6 -3
+6 -3
View File
@@ -131,11 +131,14 @@ class StopLoopException(Exception):
pass
def create_message(payload: PayloadLike) -> tuple[bytes, bytes, bytes]:
def create_message(payload: PayloadLike) -> tuple[bytes, bytes]:
body = json.dumps(payload, check_circular=False, ensure_ascii=False, separators=(",", ":")).encode(ENCODING)
# NOTE: only Content-Length is sent. Content-Type is optional per the LSP
# spec (default: application/vscode-jsonrpc; charset=utf-8), and Godot's
# GDScript LSP parser only handles Content-Length — any additional header
# makes it silently drop the message.
return (
f"Content-Length: {len(body)}\r\n".encode(ENCODING),
"Content-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n".encode(ENCODING),
f"Content-Length: {len(body)}\r\n\r\n".encode(ENCODING),
body,
)