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.
Handles individual MCP requests.
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
Handles batch MCP requests.
Processes multiple MCP requests in a single batch operation.
Handles a batch of responses from the transport.
Handles a notification to be sent to the server.
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 owndefault_timeoutby scheduling a{:request_timeout, id}message for pending requests%{timeout: integer}- the caller enforces the timeout on its side (via theGenServer.call/3timeout), so no timer is scheduled%{timeout: :caller_enforced}- legacy{:request, method, params}calls; no timer is scheduled
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.
Handles a single response from the transport.
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.
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.
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