startKeepAlive method

void startKeepAlive(
  1. Duration interval, {
  2. Duration timeout = const Duration(seconds: 10),
  3. int maxMissed = 1,
})

Ping the server every interval (basic/utilities/ping: implementations should check connection health periodically, at a configurable rate). A ping not answered within timeout is missed; maxMissed misses in a row are a connection failure: it is logged and the client disconnects with DisconnectReason.pingTimeout. An answered ping resets the count. Off unless started; revisions without ping (2026-07-28) refuse it.

Implementation

void startKeepAlive(
  Duration interval, {
  Duration timeout = const Duration(seconds: 10),
  int maxMissed = 1,
}) {
  if (_statelessMode) {
    throw McpError('ping is not part of protocol ${McpProtocol.v2026_07_28}',
        code: McpProtocol.errorMethodNotFound);
  }
  if (maxMissed < 1) throw ArgumentError.value(maxMissed, 'maxMissed', 'must be at least 1');
  stopKeepAlive();
  var missed = 0;
  _keepAlive = Timer.periodic(interval, (_) async {
    try {
      await ping(options: RequestOptions(timeout: timeout));
      missed = 0;
    } on McpError catch (e) {
      if (_transport == null) return;
      _logger.warning('Keep-alive ping failed (${++missed}/$maxMissed): ${e.message}');
      if (missed < maxMissed) return;
      final transport = _transport!;
      _transport = null;
      _disconnectStreamController.add(DisconnectReason.pingTimeout);
      transport.close();
      _onDisconnect();
    }
  });
}