MCP Server | Sampling

Sampling lets the server ask the client to run an LLM generation on its behalf. Requests describe a conversation history, optional system prompt, model preferences and token budgets. The client keeps control of which provider is used, performs any human-in-the-loop reviews and finally returns the approved completion.

Clients must declare the sampling capability during initialize; otherwise a sampling attempt is rejected with a capability error. The specification encourages user approval and allows text, image or audio content blocks inside the conversational history.

Issuing a sampling request

TsgcWSAPIServer_MCP streamlines the sampling/createMessage flow with a helper and a response event:

Client replies and protocol eras

The reply of the client is matched with the pending request and raises OnMCPResponseSamplingCreateMessage. Over HTTP the client posts the reply to the MCP endpoint and the server answers 204 without body. A client that has no handler for the request answers with the JSON-RPC error -32601 (Method not found). An error reply also resolves the pending request: the server answers 204 and raises the same OnMCPResponseSamplingCreateMessage event with aResponse.IsError set to True. Read ErrorCode, ErrorMessage and ErrorData of the response to know why the request failed, and check IsError before reading the result.

procedure TFRMMCPServer.MCPServerSamplingResponse(Sender: TObject;
  const aSession: TsgcAI_MCP_Session;
  const aRequest: TsgcAI_MCP_Request_SamplingCreateMessage;
  const aResponse: TsgcAI_MCP_Response_SamplingCreateMessage);
begin
  if aResponse.IsError then
  begin
    MemoLog.Lines.Add(Format('sampling/createMessage failed: %d %s',
      [aResponse.ErrorCode, aResponse.ErrorMessage]));
    exit;
  end;
  // ... read the result
end;

This request only exists in the legacy era (2025-11-25 and older). Clients of the protocol version 2026-07-28 have no session, so ask them for the same input from the tool, prompt or resource handler with aResponse.InputRequired.AddSampling. See Multi Round-Trip Requests.

Sample code

The snippets below request a short summary from the client and print the assistant reply.

procedure TFRMMCPServer.FormCreate(Sender: TObject);
begin
  MCPServer.OnMCPResponseSamplingCreateMessage := MCPServerSamplingResponse;
end;
procedure TFRMMCPServer.RequestTicketSummary(
  const aSession: TsgcAI_MCP_Session; const aTicketText: string);
var
  LRequest: TsgcAI_MCP_Request_SamplingCreateMessage;
begin
  if not aSession.ClientCapabilities.Sampling.Enabled then
    Exit;
  LRequest := TsgcAI_MCP_Request_SamplingCreateMessage.Create;
  try
    LRequest.Params.Messages.AddTextMessage('user',
      'Summarise the following ticket: ' + aTicketText);
    LRequest.Params.SystemPrompt := 'You are a concise support assistant.';
    LRequest.Params.ModelPreferences.Hints.AddHint('claude-3-sonnet');
    LRequest.Params.ModelPreferences.SpeedPriority := 0.6;
    LRequest.Params.ModelPreferences.IntelligencePriority := 0.8;
    LRequest.Params.HasMaxTokens := True;
    LRequest.Params.MaxTokens := 200;
    MemoLog.Lines.Add('sampling/createMessage id ' +
      MCPServer.RequestSamplingCreateMessage(aSession, LRequest));
  finally
    LRequest.Free;
  end;
end;
procedure TFRMMCPServer.MCPServerSamplingResponse(Sender: TObject;
  const aSession: TsgcAI_MCP_Session;
  const aRequest: TsgcAI_MCP_Request_SamplingCreateMessage;
  const aResponse: TsgcAI_MCP_Response_SamplingCreateMessage);
var
  LText: TsgcAI_MCP_Response_Result_Content_Text;
begin
  if aResponse.Content is TsgcAI_MCP_Response_Result_Content_Text then
  begin
    LText := TsgcAI_MCP_Response_Result_Content_Text(aResponse.Content);
    MemoLog.Lines.Add('assistant: ' + LText.Text);
  end;
  MemoLog.Lines.Add('model: ' + aResponse.Model +
    ' reason: ' + aResponse.StopReason);
end;