Builders for Multi Round-Trip Request (MRTR) input requests.
In MCP 2026-07-28 a server no longer sends requests to the client.
Instead a tool call, resource read, or prompt get answers with an
input_required result carrying an inputRequests map — keys are
server-chosen identifiers, values are the maps these functions build — and
the client retries the original request with the matching
inputResponses. See
MRTR.
Each builder returns one InputRequest ("method" plus "params", no
"jsonrpc" or "id"):
%{
"approval" => ConduitMcp.MRTR.elicit("Approve deploy?", schema)
}Sampling and roots are deprecated in 2026-07-28; sample/2 and
list_roots/0 remain available but carry @deprecated markers.
Elicitation is not deprecated.
Returning input requests
handle_call_tool/3, handle_read_resource/2 and handle_get_prompt/3
(and the DSL and ConduitMcp.Component handlers behind them) return
{:input_required, input_requests, state} to ask for input. The library
checks every request against the client's declared capabilities
(missing_capabilities/2; a gap is answered with -32021 and
data.requiredCapabilities), seals state into requestState with
ConduitMcp.MRTR.State, and answers with an InputRequiredResult. On
the retry the callback finds the restored state and the client's
inputResponses in conn.assigns[:mcp_input]; see ConduitMcp.Server.
The state carried between rounds is sealed by ConduitMcp.MRTR.State,
which requires config :conduit_mcp, :mrtr_keys. MRTR exists only in the
modern era: a legacy-era request whose callback returns
{:input_required, ...} gets -32603.
Summary
Functions
Builds an elicitation/create input request (form mode).
Builds a roots/list input request.
Returns the client capabilities input_requests need that
client_capabilities does not declare, as a ClientCapabilities-shaped
map (%{} when every request can be sent).
Builds a sampling/createMessage input request.
Functions
Builds an elicitation/create input request (form mode).
requested_schema is the restricted JSON Schema the client renders as a
form: a flat "type" => "object" with primitive "properties".
Example
ConduitMcp.MRTR.elicit("Please provide your API key", %{
"type" => "object",
"properties" => %{"api_key" => %{"type" => "string"}},
"required" => ["api_key"]
})
@spec list_roots() :: map()
Builds a roots/list input request.
Returns the client capabilities input_requests need that
client_capabilities does not declare, as a ClientCapabilities-shaped
map (%{} when every request can be sent).
elicitation/createneedselicitation.urlfor"mode" => "url", otherwise form mode:elicitation.form, or anelicitationthat declares neither mode (the spec's backwards-compatible form-only declaration).sampling/createMessageneedssampling;sampling.toolswhen it carriestoolsortoolChoice;sampling.contextwhen itsincludeContextis anything but"none".roots/listneedsroots.
Other methods impose no requirement.
Example
iex> ConduitMcp.MRTR.missing_capabilities(
...> %{"approval" => ConduitMcp.MRTR.elicit("Approve?", %{"type" => "object"})},
...> %{"roots" => %{}}
...> )
%{"elicitation" => %{"form" => %{}}}
Builds a sampling/createMessage input request.
messages is a list of SamplingMessage maps.
Options
:max_tokens- required; the maximum tokens to sample:system_prompt- system prompt for the LLM:model_preferences- model selection preferences:temperature- sampling temperature:stop_sequences- list of stop sequences:tools- tools the LLM may call:tool_choice- tool selection map, e.g.%{"mode" => "auto"}
Raises KeyError when :max_tokens is missing, since the spec requires it.