discoverHttpAuthClient static method

Future<ConnectanumHttpAuthClient> discoverHttpAuthClient(
  1. Uri endpoint, {
  2. required String realm,
  3. HttpClient? httpClient,
  4. Map<String, String> headers = const <String, String>{},
  5. Duration requestTimeout = defaultRequestTimeout,
  6. int maxResponseBytes = defaultMaxResponseBytes,
  7. bool closeHttpClient = false,
})

Discovers a same-origin HTTP auth bridge advertised by a protected MCP endpoint.

The probe uses a fresh transport, is sessionless, and never sends caller credentials. Discovery succeeds only when the endpoint returns HTTP 401 with a Bearer challenge for realm that includes a safe auth_path parameter.

Default headers are applied only to the returned auth client. They are never sent by the discovery probe.

When httpClient is omitted, the returned auth client owns the internally created transport. A supplied client remains caller-owned unless closeHttpClient is true.

Implementation

static Future<ConnectanumHttpAuthClient> discoverHttpAuthClient(
  Uri endpoint, {
  required String realm,
  HttpClient? httpClient,
  Map<String, String> headers = const <String, String>{},
  Duration requestTimeout = defaultRequestTimeout,
  int maxResponseBytes = defaultMaxResponseBytes,
  bool closeHttpClient = false,
}) async {
  final scheme = endpoint.scheme.toLowerCase();
  if (!endpoint.isAbsolute ||
      (scheme != 'http' && scheme != 'https') ||
      endpoint.host.isEmpty ||
      endpoint.userInfo.isNotEmpty ||
      endpoint.hasFragment) {
    throw const ConnectanumHttpAuthProtocolException(
      'MCP endpoint must be an absolute credential-free HTTP(S) URI',
    );
  }
  if (realm.isEmpty || containsMcpWhitespaceOrControl(realm)) {
    throw ArgumentError.value(
      realm,
      'realm',
      'realm must be non-empty and contain no whitespace or control characters.',
    );
  }

  final probe = McpStreamableHttpClient.stateless(
    endpoint,
    clientInfo: const <String, Object?>{
      'name': 'connectanum-http-auth-discovery',
      'version': '3.0.0-beta.5',
    },
    requestTimeout: requestTimeout,
    maxResponseBytes: maxResponseBytes,
  );
  var succeeded = false;
  try {
    try {
      await probe.pingDirect(id: 'http-auth-discovery');
    } on McpStreamableHttpException catch (error) {
      if (error.statusCode != HttpStatus.unauthorized) {
        throw ConnectanumHttpAuthProtocolException(
          'HTTP auth discovery returned HTTP ${error.statusCode}; '
          'expected ${HttpStatus.unauthorized}.',
        );
      }
      for (final challenge in error.bearerChallenges) {
        if (challenge.realm == realm && challenge.authPath != null) {
          final client = ConnectanumHttpAuthClient.fromMcpBearerChallenge(
            endpoint,
            challenge,
            httpClient: httpClient,
            headers: headers,
            requestTimeout: requestTimeout,
            maxResponseBytes: maxResponseBytes,
            closeHttpClient: closeHttpClient,
          );
          succeeded = true;
          return client;
        }
      }
      throw const ConnectanumHttpAuthProtocolException(
        'HTTP auth discovery did not receive a compatible Bearer challenge '
        'with auth_path for the requested realm.',
      );
    }
    throw const ConnectanumHttpAuthProtocolException(
      'HTTP auth discovery expected the MCP endpoint to require Bearer '
      'authentication.',
    );
  } finally {
    probe.close(force: true);
    if (!succeeded && httpClient != null && closeHttpClient) {
      httpClient.close(force: true);
    }
  }
}