requestClientSampling method

Future<Map<String, dynamic>> requestClientSampling(
  1. String sessionId,
  2. Map<String, dynamic> params, {
  3. Duration timeout = const Duration(seconds: 60),
})

Server-initiated request: ask the connected client's LLM to generate a completion (spec sampling/createMessage).

params is the request's params, as CreateMessageRequestParams writes them (CreateMessageRequestParams(...).toJson()): messages and maxTokens, plus modelPreferences, systemPrompt, includeContext, temperature, stopSequences, metadata, and from 2025-11-25 tools and toolChoice.

Returns the spec CreateMessageResult map (role, content, model, optional stopReason).

The client must advertise the sampling capability during initialize; otherwise this throws McpError with methodNotFound.

Implementation

Future<Map<String, dynamic>> requestClientSampling(
  String sessionId,
  Map<String, dynamic> params, {
  Duration timeout = const Duration(seconds: 60),
}) async {
  final session = _sessions[sessionId];
  if (session == null) {
    throw StateError('Unknown sessionId: $sessionId');
  }
  final sampling = session.capabilities?['sampling'];
  if (sampling == null) {
    throw McpError(
      'Client does not advertise the `sampling` capability',
      code: ErrorCode.methodNotFound,
    );
  }
  // Tool use only with `sampling.tools`; including context only with
  // `sampling.context` (2025-11-25).
  final usesTools = params['tools'] != null || params['toolChoice'] != null;
  if (usesTools && (sampling is! Map || sampling['tools'] is! Map)) {
    throw McpError(
      'Client does not advertise `sampling.tools`; tool-enabled sampling is not allowed',
      code: ErrorCode.invalidParams,
    );
  }
  final context = params['includeContext'];
  if ((context == 'thisServer' || context == 'allServers') &&
      (sampling is! Map || sampling['context'] is! Map)) {
    throw McpError(
      'Client does not advertise `sampling.context`; includeContext "$context" is not allowed',
      code: ErrorCode.invalidParams,
    );
  }
  final messageProblem = samplingMessagesProblem(params['messages']);
  if (messageProblem != null) {
    throw ArgumentError.value(params['messages'], 'messages', messageProblem);
  }
  final result = await _sendRequestToClient(
    sessionId,
    'sampling/createMessage',
    params,
    timeout: timeout,
  );
  return result is Map<String, dynamic>
      ? result
      : Map<String, dynamic>.from(result as Map);
}