connect method

Future<void> connect(
  1. ClientTransport transport, {
  2. bool statelessMode = false,
})

Connect the client to a transport.

When statelessMode is true, the client speaks the 2026-07-28 stateless core: it skips the initialize handshake, marks the transport to stamp MCP-Protocol-Version: 2026-07-28 on every request, and attaches the reverse-DNS _meta keys (client info + per-request capabilities) to each outbound request. Server capabilities are fetched on demand via discover. Default false (dormant) — the handshake path is unchanged.

Implementation

Future<void> connect(
  ClientTransport transport, {
  bool statelessMode = false,
}) async {
  if (_transport != null) {
    throw McpError('Client is already connected to a transport');
  }

  if (_connecting) {
    throw McpError('Client is already connecting to a transport');
  }

  _connecting = true;
  _statelessMode = statelessMode;
  _transport = transport;
  _transport!.onMessage.listen(_handleMessage);
  _transport!.onClose
      .then((_) {
        // Only send disconnect event if we're still connected
        if (_transport != null) {
          _disconnectStreamController.add(DisconnectReason.transportClosed);
          _onDisconnect();
        }
      })
      .catchError((error) {
        // Only handle error if we're still connected
        if (_transport != null) {
          _errorStreamController.add(McpError('Transport error: $error'));
          _disconnectStreamController.add(DisconnectReason.transportError);
          _onDisconnect();
        }
      });

  // Set up message handling
  _messageController.stream.listen((message) async {
    try {
      await _processMessage(message);
    } catch (e) {
      _logger.debug('Error processing message: $e');
      _errorStreamController.add(McpError('Error processing message: $e'));
    }
  });

  // Initialize the connection
  try {
    if (_statelessMode) {
      // Stateless core: no handshake. Record the version so the HTTP
      // transport stamps `MCP-Protocol-Version: 2026-07-28`, and mark the
      // client ready to send requests immediately. Server capabilities are
      // fetched on demand via [discover].
      _negotiatedProtocolVersion = McpProtocol.v2026_07_28;
      final tx = _transport;
      if (tx is StreamableHttpClientTransport) {
        tx.setProtocolVersion(McpProtocol.v2026_07_28);
      }
      _initialized = true;
    } else {
      await initialize();
    }
    _connecting = false;

    // Emit connection event after successful initialization
    if (_initialized && _serverInfo != null && _serverCapabilities != null) {
      _connectStreamController.add(
        ServerInfo(
          name: _serverInfo!['name'] as String? ?? 'Unknown',
          version: _serverInfo!['version'] as String? ?? 'Unknown',
          capabilities: _serverCapabilities!.toJson(),
          protocolVersion: protocolVersion,
        ),
      );
    }
  } catch (e) {
    _connecting = false;
    _errorStreamController.add(McpError('Initialization error: $e'));
    disconnect();
    rethrow;
  }
}