Share the JSON-RPC request handling between the CE and EE MCP endpoints

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Part of #627825.

Why

lib/api/mcp/base.rb and ee/lib/api/orbit/mcp.rb each keep their own copy of the JSON-RPC version constant, the error table, method_not_found!, and format_jsonrpc_response. Reviewers asked for one shared helper on !253324 (merged) and !253329 (merged). The two copies also drift: the CE table holds a version_mismatch entry with code -32001 that nothing calls, in lib/, ee/lib/, spec/, or ee/spec/. An unsupported protocol version raises ArgumentError and comes back as -32602 instead. The 2026-07-28 spec now treats -32000 to -32019 as legacy and tells new implementations to stay out of that range, so the entry is dead code to delete.

This item comes first, because the four items after it all add fields to the same response path.

What to do

  • Extend lib/api/helpers/mcp/json_rpc.rb, the module !253329 (merged) adds. Depends on !253329 (merged).
  • Move the JSON-RPC version constant, the error table, method_not_found!, and format_jsonrpc_response into the module.
  • Drop the -32001 version_mismatch entry. Nothing uses it.
  • Keep -32603 internal_error in ee/lib/api/orbit/mcp.rb. The EE endpoint is the only one that raises it.
  • Do not add -32700. Workhorse answers 400 before a parse error reaches us, which the current comment in lib/api/mcp/base.rb records.
  • Keep the two format_jsonrpc_response bodies apart where they really differ. CE returns 202 with an empty precompiled body for a notification, EE calls body false. Pick one shape only if a spec proves the other is wrong, otherwise leave the difference behind a hook and say why in a comment.
  • Include the module in both endpoints.

Acceptance

  • lib/api/helpers/mcp/json_rpc.rb holds the version constant, the error table, method_not_found!, and format_jsonrpc_response.
  • -32001 is gone from the codebase.
  • -32603 stays in the EE endpoint.
  • Neither endpoint keeps its own copy of the moved code.
  • spec/requests/api/mcp/, spec/lib/api/helpers/mcp/json_rpc_spec.rb, and ee/spec/requests/api/orbit/mcp_spec.rb pass with no changes to the assertions. This is a refactor, so a spec that has to change is a signal that behaviour changed.
Edited by 🤖 GitLab Bot 🤖