PhoenixKit.API.MCP.Rpc (phoenix_kit v2.63.0)

Copy Markdown View Source

The JSON-RPC 2.0 envelope of the MCP transport: classifying a decoded request body and building and sending answers.

classify/1 takes conn.body_params as PhoenixKit.API.BodyGuard (or Plug.Parsers) left it: a map, where a JSON array or scalar is wrapped as %{"_json" => value}, and a request with no body at all is %Plug.Conn.Unfetched{} or %{}. It returns:

  • {:request, id, method, params}: an object with "jsonrpc": "2.0", a string method and an id that is a string or an integer. params is whatever the client sent (nil when absent);
  • {:notification, method}: the same without an id. Whatever the method: a notification gets no answer and must not run anything;
  • :response: a result or error with an id, which a client sends back to a server request (this server sends none);
  • {:invalid, id_or_nil, text}: everything else, among it a batch (MCP revision 2025-06-18 removed batching), a bare scalar, an empty object, a wrong jsonrpc, a null, float or boolean id. The id is echoed when the message had a usable one.

It never raises.

Summary

Functions

202 Accepted with no body: the answer to a notification or a response.

Classifies a decoded request body, see the moduledoc.

The JSON-RPC error code of name (:parse_error, :invalid_request, :method_not_found, :invalid_params, :internal_error).

The error envelope. id is nil when the request had no usable id.

The success envelope.

Sends a JSON-RPC error with HTTP status and halts. name is one of the atoms of code/1.

Sends body as JSON with status. Not halted.

Types

id()

@type id() :: String.t() | integer()

message()

@type message() ::
  {:request, id(), String.t(), term()}
  | {:notification, String.t()}
  | :response
  | {:invalid, id() | nil, String.t()}

Functions

accepted(conn)

@spec accepted(Plug.Conn.t()) :: Plug.Conn.t()

202 Accepted with no body: the answer to a notification or a response.

classify(map)

@spec classify(term()) :: message()

Classifies a decoded request body, see the moduledoc.

code(name)

@spec code(atom()) :: integer()

The JSON-RPC error code of name (:parse_error, :invalid_request, :method_not_found, :invalid_params, :internal_error).

error_envelope(id, code, message)

@spec error_envelope(id() | nil, integer(), String.t()) :: map()

The error envelope. id is nil when the request had no usable id.

result_envelope(id, result)

@spec result_envelope(id(), map()) :: map()

The success envelope.

send_error(conn, status, id, name, message)

@spec send_error(Plug.Conn.t(), pos_integer(), id() | nil, atom(), String.t()) ::
  Plug.Conn.t()

Sends a JSON-RPC error with HTTP status and halts. name is one of the atoms of code/1.

send_json(conn, status, body)

@spec send_json(Plug.Conn.t(), pos_integer(), map()) :: Plug.Conn.t()

Sends body as JSON with status. Not halted.