MCP Server | Multi Round-Trip Requests

In the MCP protocol version 2026-07-28 the server cannot send requests to the client (elicitation, sampling or roots) in the middle of a tool call, because there is no session. Instead, the server answers the request with resultType input_required, listing the inputs it needs. The client collects them and repeats the same request with the answers in inputResponses. This is called a Multi Round-Trip Request (MRTR) and is supported by tools/call, prompts/get and resources/read.

 

Asking for input

Inside OnMCPRequestTool, OnMCPRequestPrompt or OnMCPRequestResource, add the inputs you need to aResponse.InputRequired and exit the handler. Each input has a key, which is used later to read the answer.

 

Use aResponse.InputRequired.RequestState to store your own application state (for example the step of a wizard). The server signs it with HMAC-SHA256 and sends it to the client as requestState. When the client repeats the request, the state is verified (signature, expiration, method, name and principal) before your handler is called, and it is available in aRequest.Params.RequestState. A state that fails the verification is rejected with -32602 "Invalid requestState".

 

Reading the answers

When the client repeats the request, aRequest.HasInputResponse(aKey) returns True for every answered input and aRequest.InputResponse(aKey) returns the answer as raw JSON text (an empty string if there is no answer for that key).


procedure TMainForm.MCPServerMCPRequestTool(Sender: TObject;
  const aSession: TsgcAI_MCP_Session; const aRequest: TsgcAI_MCP_Request_ToolsCall;
  const aResponse: TsgcAI_MCP_Response_ToolsCall);
var
  oJSON: TsgcJSON;
begin
  if aRequest.Params.Name <> 'delete_file' then
    exit;
  // ... first round: ask the user to confirm
  if not aRequest.HasInputResponse('confirm') then
  begin
    aResponse.InputRequired.AddElicitation('confirm', 'Delete the file?',
      '{"type":"object","properties":{"confirm":{"type":"boolean"}},"required":["confirm"]}');
    aResponse.InputRequired.RequestState := 'step=1';
    exit;
  end;
  // ... second round: aRequest.Params.RequestState = 'step=1'
  oJSON := TsgcJSON.Create(nil);
  Try
    oJSON.Read(aRequest.InputResponse('confirm'));
    if oJSON.Node['action'].Value = 'accept' then
      aResponse.Result.Content.AddText('File deleted')
    else
      aResponse.Result.Content.AddText('Operation cancelled');
  Finally
    oJSON.Free;
  End;
end;

 

Capabilities

Before sending input_required, the server checks that the client declared the needed capabilities in the request _meta: elicitation (and elicitation url for URL mode), sampling or roots. If a capability is missing, the client receives error -32021.

 

MRTR options

 

The request state is bound to a principal returned by the protected virtual method DoGetRequestPrincipal(aSession) of the MCP server engine (TsgcAI_MCP_Server). By default it returns an empty string; override it to return the authenticated user, so a state created for one user cannot be reused by another.

 

Legacy clients

Multi round-trip requests only work with 2026-07-28 clients. If a handler adds inputs while serving a legacy client, the server answers with error -32603 "input_required needs protocol 2026-07-28". To support both eras, check aSession.Request.Era and use the classic server requests (Elicitation, Sampling, Roots) for legacy sessions.


if aSession.Request.Era = aimcpeModern then
  aResponse.InputRequired.AddRoots('roots')
else
  MCPServer.RequestRootsList(aSession.Id);