Skip to content

Commit c99b497

Browse files
committed
fix: handle notifications/initialized and ignore unknown notifications
Codex (via rmcp 0.15.0) sends "notifications/initialized" rather than "initialized" after the handshake. The server was returning a -32601 error for this unknown method, which caused rmcp to close the transport before tools/list could complete. Also silently ignore any other unknown notifications (messages without an id) per the MCP spec, instead of returning an error response.
1 parent e38bf9b commit c99b497

2 files changed

Lines changed: 19 additions & 3 deletions

File tree

internal/mcp/server.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ func (s *server) handleMessage(data []byte) *jsonrpcResponse {
179179
switch req.Method {
180180
case "initialize":
181181
return s.handleInitialize(req)
182-
case "initialized":
182+
case "initialized", "notifications/initialized":
183183
return nil // notification, no response
184184
case "ping":
185185
return resultResponse(req.ID, map[string]any{})
@@ -188,6 +188,10 @@ func (s *server) handleMessage(data []byte) *jsonrpcResponse {
188188
case "tools/call":
189189
return s.handleToolsCall(req)
190190
default:
191+
// Notifications have no id; silently ignore unknown ones per spec.
192+
if req.ID == nil {
193+
return nil
194+
}
191195
return errorResponse(req.ID, -32601, "method not found: "+req.Method)
192196
}
193197
}

internal/mcp/server_test.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,21 @@ func TestHandleInitialize_VersionNegotiation(t *testing.T) {
124124

125125
func TestHandleInitialized_NoResponse(t *testing.T) {
126126
s := testServer(t)
127-
resp := s.handleMessage([]byte(`{"jsonrpc":"2.0","method":"initialized"}`))
127+
for _, method := range []string{"initialized", "notifications/initialized"} {
128+
msg := `{"jsonrpc":"2.0","method":"` + method + `"}`
129+
resp := s.handleMessage([]byte(msg))
130+
if resp != nil {
131+
t.Errorf("notification %q should return nil, got %v", method, resp)
132+
}
133+
}
134+
}
135+
136+
func TestUnknownNotification_NoResponse(t *testing.T) {
137+
s := testServer(t)
138+
// Unknown notifications (no id) must be silently ignored per MCP spec.
139+
resp := s.handleMessage([]byte(`{"jsonrpc":"2.0","method":"notifications/unknown"}`))
128140
if resp != nil {
129-
t.Error("initialized notification should return nil")
141+
t.Errorf("unknown notification should return nil, got %v", resp)
130142
}
131143
}
132144

0 commit comments

Comments
 (0)