ExMCP.Client.RequestHandler (ex_mcp v1.0.0-rc.8)

Copy Markdown View Source

Request/response processing for ExMCP client.

This module handles all request processing, batch operations, message parsing, and response handling for MCP clients.

Summary

Functions

Handles batch MCP requests.

Handles a batch of responses from the transport.

Handles a notification to be sent to the server.

Routes a legacy server-to-client request to the appropriate handler callback.

Handles a single response from the transport.

Parses a message from the transport.

Encodes and sends a message via the transport.

Sends the era-appropriate liveness request for the client's idle health check: legacy ping, or an uncached modern server/discover.

Functions

handle_batch_request(requests, from, state)

Handles batch MCP requests.

Processes multiple MCP requests in a single batch operation.

handle_batch_response(responses, state)

Handles a batch of responses from the transport.

handle_cast_notification(method, params, state)

Handles a notification to be sent to the server.

handle_request(method, params, from, state, meta \\ %{timeout: :caller_enforced})

Handles individual MCP requests.

Processes a single MCP request and returns the appropriate GenServer response.

The optional meta map controls request timeout enforcement:

  • %{timeout: nil} - the caller did not specify a timeout, so the client process enforces its own default_timeout by scheduling a {:request_timeout, id} message for pending requests
  • %{timeout: integer} - the caller enforces the timeout on its side (via the GenServer.call/3 timeout), so no timer is scheduled
  • %{timeout: :caller_enforced} - legacy {:request, method, params} calls; no timer is scheduled

handle_server_request(method, params, request_id, state)

Routes a legacy server-to-client request to the appropriate handler callback.

Modern MCP 2026-07-28 supplies client input through MRTR result envelopes; it does not deliver these as independent JSON-RPC requests on the stream.

handle_single_response(other, state)

Handles a single response from the transport.

parse_transport_message(message, state)

Parses a message from the transport.

This function is intended to be called from the client's handle_info/2 callback. It decodes the message and delegates to the appropriate response handler.

send_message(message, state)

Encodes and sends a message via the transport.

send_ping(state)

@spec send_ping(map()) :: {:ok, term() | nil, map()} | {:error, any()}

Sends the era-appropriate liveness request for the client's idle health check: legacy ping, or an uncached modern server/discover.

The ping is deliberately kept out of pending_requests: it has no caller to reply to and must not show up in ExMCP.Client.get_pending_requests/1.

Returns:

  • {:ok, request_id, state} - ping sent, the pong will arrive asynchronously
  • {:ok, nil, state} - a synchronous transport answered inline, so the connection is already proven alive
  • {:error, reason} - the ping could not be sent