requestClientElicitation method

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

Server-initiated request: ask the connected client to elicit input from the user (spec 2025-06-18 elicitation/create).

params follows the spec ElicitRequest.params shape: message (string) + requestedSchema (restricted JSON Schema — flat object, primitive properties only).

Returns the spec ElicitResult map: action (accept / decline / cancel) plus content when accepted.

Client must advertise the elicitation capability.

Implementation

Future<Map<String, dynamic>> requestClientElicitation(
  String sessionId,
  Map<String, dynamic> params, {
  Duration timeout = const Duration(seconds: 120),
}) async {
  final session = _sessions[sessionId];
  if (session == null) {
    throw StateError('Unknown sessionId: $sessionId');
  }
  final elicitation = session.capabilities?['elicitation'];
  if (elicitation == null) {
    throw McpError(
      'Client does not advertise the `elicitation` capability',
      code: ErrorCode.methodNotFound,
    );
  }
  // Only modes the client declared (an elicitation object naming no mode
  // means form); every request carries what its mode requires.
  final mode = params['mode'] ?? 'form';
  final modes = elicitation is Map ? elicitation : const {};
  final supportsUrl = modes['url'] is Map;
  final supportsForm = modes['form'] is Map || !supportsUrl;
  if ((mode == 'url' && !supportsUrl) || (mode == 'form' && !supportsForm)) {
    throw McpError(
      'Client does not support $mode mode elicitation',
      code: ErrorCode.invalidParams,
    );
  }
  final problem = elicitationRequestProblem(params);
  if (problem != null) throw ArgumentError.value(params, 'params', problem);

  final result = await _sendRequestToClient(
    sessionId,
    'elicitation/create',
    params,
    timeout: timeout,
  );
  final map =
      result is Map<String, dynamic>
          ? result
          : Map<String, dynamic>.from(result as Map);
  if (mode == 'url') {
    _urlElicitations
        .putIfAbsent(sessionId, () => {})
        .add(params['elicitationId'] as String);
  } else if (map['action'] == 'accept') {
    // Servers should validate the data they receive.
    final check = JsonSchemaValidator(
      params['requestedSchema'],
    ).validate(map['content'] ?? const {});
    if (!check.valid) {
      throw McpError(
        'Elicitation response does not match requestedSchema: ${check.errors.join('; ')}',
        code: ErrorCode.invalidParams,
      );
    }
  }
  return map;
}