diff --git a/apps/language_server/lib/language_server/mcp/request_handler.ex b/apps/language_server/lib/language_server/mcp/request_handler.ex index 78cd6a75c..59b7c46dd 100644 --- a/apps/language_server/lib/language_server/mcp/request_handler.ex +++ b/apps/language_server/lib/language_server/mcp/request_handler.ex @@ -160,6 +160,11 @@ defmodule ElixirLS.LanguageServer.MCP.RequestHandler do "id" => id } + %{"method" => _} -> + # JSON-RPC notification (no "id" field). Per spec, the server must + # not reply to notifications, even for unknown methods. + nil + _ -> %{ "jsonrpc" => "2.0", diff --git a/apps/language_server/test/mcp/request_handler_test.exs b/apps/language_server/test/mcp/request_handler_test.exs index de1e5e5cb..a4aac884c 100644 --- a/apps/language_server/test/mcp/request_handler_test.exs +++ b/apps/language_server/test/mcp/request_handler_test.exs @@ -374,6 +374,27 @@ defmodule ElixirLS.LanguageServer.MCP.RequestHandlerTest do assert response == nil end + + test "initialized notification does not get response" do + # MCP clients (e.g. Codex) send this notification after initialize. + # Per JSON-RPC 2.0 spec, notifications (no "id") must not receive a reply. + request = %{ + "jsonrpc" => "2.0", + "method" => "initialized" + } + + assert RequestHandler.handle_request(request) == nil + end + + test "unknown notification (no id) does not get response" do + request = %{ + "jsonrpc" => "2.0", + "method" => "notifications/something_unknown", + "params" => %{} + } + + assert RequestHandler.handle_request(request) == nil + end end describe "integration with actual modules" do