MCP server returns 404 for ping and unhandled notifications such as notifications/cancelled

Summary

The main MCP endpoint, POST /api/v4/mcp, only routes four methods: initialize, notifications/initialized, tools/list and tools/call. Every other method falls through to method_not_found! in lib/api/mcp/base.rb, which answers HTTP 404 with JSON-RPC error -32601.

That includes two messages that compliant clients send during normal use:

In the Streamable HTTP transport, a 404 means the session was terminated, so clients treat it as fatal.

Why this matters

The same fall-through on the Orbit endpoint made GitLab Duo CLI drop the server after its first tool approval, because the CLI sends notifications/cancelled. See #631580 (moved). That issue notes that lib/api/mcp/base.rb "probably behaves the same way" but could not verify it. This issue tracks the main endpoint. #628350 (closed) covers a related Orbit-only notification status bug.

Steps to reproduce

curl -s -w " -> HTTP %{http_code}\n" -X POST https://gitlab.com/api/v4/mcp \
  -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"ping"}'

curl -s -w " -> HTTP %{http_code}\n" -X POST https://gitlab.com/api/v4/mcp \
  -H "Authorization: Bearer $MCP_TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"notifications/cancelled","params":{"requestId":1}}'

Based on the code on master, both are expected to return -32601 Method not found with HTTP 404.

Proposed fix

  • Add a ping handler that returns an empty result {}.
  • In invoke_basic_handler, accept a message that has no id (a JSON-RPC notification) and no handler, returning 202 with an empty body through the existing format_jsonrpc_response path, instead of calling method_not_found!.
  • Leave unknown requests (messages with an id) unchanged in this fix.
  • Add request specs for ping and for an unknown notification.

Acceptance criteria

  • ping returns HTTP 200 with result: {} and the request id.
  • notifications/cancelled and other unhandled notifications return HTTP 202 with an empty body.
  • Unknown requests with an id still return -32601.
Edited by 🤖 GitLab Bot 🤖