requestClientSampling method
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);
}