@@ -417,6 +417,10 @@ def compute_msa(
417417 msa_dir : Path ,
418418 msa_server_url : str ,
419419 msa_pairing_strategy : str ,
420+ msa_server_username : Optional [str ] = None ,
421+ msa_server_password : Optional [str ] = None ,
422+ api_key_header : Optional [str ] = None ,
423+ api_key_value : Optional [str ] = None ,
420424) -> None :
421425 """Compute the MSA for the input data.
422426
@@ -432,8 +436,35 @@ def compute_msa(
432436 The MSA server URL.
433437 msa_pairing_strategy : str
434438 The MSA pairing strategy.
439+ msa_server_username : str, optional
440+ Username for basic authentication with MSA server.
441+ msa_server_password : str, optional
442+ Password for basic authentication with MSA server.
443+ api_key_header : str, optional
444+ Custom header key for API key authentication (default: X-API-Key).
445+ api_key_value : str, optional
446+ Custom header value for API key authentication (overrides --api_key if set).
435447
436448 """
449+ click .echo (f"Calling MSA server for target { target_id } with { len (data )} sequences" )
450+ click .echo (f"MSA server URL: { msa_server_url } " )
451+ click .echo (f"MSA pairing strategy: { msa_pairing_strategy } " )
452+
453+ # Construct auth headers if API key header/value is provided
454+ auth_headers = None
455+ if api_key_value :
456+ key = api_key_header if api_key_header else "X-API-Key"
457+ value = api_key_value
458+ auth_headers = {
459+ "Content-Type" : "application/json" ,
460+ key : value
461+ }
462+ click .echo (f"Using API key authentication for MSA server (header: { key } )" )
463+ elif msa_server_username and msa_server_password :
464+ click .echo ("Using basic authentication for MSA server" )
465+ else :
466+ click .echo ("No authentication provided for MSA server" )
467+
437468 if len (data ) > 1 :
438469 paired_msas = run_mmseqs2 (
439470 list (data .values ()),
@@ -442,6 +473,9 @@ def compute_msa(
442473 use_pairing = True ,
443474 host_url = msa_server_url ,
444475 pairing_strategy = msa_pairing_strategy ,
476+ msa_server_username = msa_server_username ,
477+ msa_server_password = msa_server_password ,
478+ auth_headers = auth_headers ,
445479 )
446480 else :
447481 paired_msas = ["" ] * len (data )
@@ -453,6 +487,9 @@ def compute_msa(
453487 use_pairing = False ,
454488 host_url = msa_server_url ,
455489 pairing_strategy = msa_pairing_strategy ,
490+ msa_server_username = msa_server_username ,
491+ msa_server_password = msa_server_password ,
492+ auth_headers = auth_headers ,
456493 )
457494
458495 for idx , name in enumerate (data ):
@@ -493,6 +530,10 @@ def process_input( # noqa: C901, PLR0912, PLR0915, D103
493530 use_msa_server : bool ,
494531 msa_server_url : str ,
495532 msa_pairing_strategy : str ,
533+ msa_server_username : Optional [str ],
534+ msa_server_password : Optional [str ],
535+ api_key_header : Optional [str ],
536+ api_key_value : Optional [str ],
496537 max_msa_seqs : int ,
497538 processed_msa_dir : Path ,
498539 processed_constraints_dir : Path ,
@@ -549,6 +590,10 @@ def process_input( # noqa: C901, PLR0912, PLR0915, D103
549590 msa_dir = msa_dir ,
550591 msa_server_url = msa_server_url ,
551592 msa_pairing_strategy = msa_pairing_strategy ,
593+ msa_server_username = msa_server_username ,
594+ msa_server_password = msa_server_password ,
595+ api_key_header = api_key_header ,
596+ api_key_value = api_key_value ,
552597 )
553598
554599 # Parse MSA data
@@ -625,6 +670,10 @@ def process_inputs(
625670 msa_pairing_strategy : str ,
626671 max_msa_seqs : int = 8192 ,
627672 use_msa_server : bool = False ,
673+ msa_server_username : Optional [str ] = None ,
674+ msa_server_password : Optional [str ] = None ,
675+ api_key_header : Optional [str ] = None ,
676+ api_key_value : Optional [str ] = None ,
628677 boltz2 : bool = False ,
629678 preprocessing_threads : int = 1 ,
630679) -> Manifest :
@@ -642,6 +691,14 @@ def process_inputs(
642691 Max number of MSA sequences, by default 4096.
643692 use_msa_server : bool, optional
644693 Whether to use the MMSeqs2 server for MSA generation, by default False.
694+ msa_server_username : str, optional
695+ Username for basic authentication with MSA server, by default None.
696+ msa_server_password : str, optional
697+ Password for basic authentication with MSA server, by default None.
698+ api_key_header : str, optional
699+ Custom header key for API key authentication (default: X-API-Key).
700+ api_key_value : str, optional
701+ Custom header value for API key authentication (overrides --api_key if set).
645702 boltz2: bool, optional
646703 Whether to use Boltz2, by default False.
647704 preprocessing_threads: int, optional
@@ -653,6 +710,16 @@ def process_inputs(
653710 The manifest of the processed input data.
654711
655712 """
713+ # Validate mutually exclusive authentication methods
714+ has_basic_auth = msa_server_username and msa_server_password
715+ has_api_key = api_key_value is not None
716+
717+ if has_basic_auth and has_api_key :
718+ raise ValueError (
719+ "Cannot use both basic authentication (--msa_server_username/--msa_server_password) "
720+ "and API key authentication (--api_key_header/--api_key_value). Please use only one authentication method."
721+ )
722+
656723 # Check if records exist at output path
657724 records_dir = out_dir / "processed" / "records"
658725 if records_dir .exists ():
@@ -710,6 +777,10 @@ def process_inputs(
710777 use_msa_server = use_msa_server ,
711778 msa_server_url = msa_server_url ,
712779 msa_pairing_strategy = msa_pairing_strategy ,
780+ msa_server_username = msa_server_username ,
781+ msa_server_password = msa_server_password ,
782+ api_key_header = api_key_header ,
783+ api_key_value = api_key_value ,
713784 max_msa_seqs = max_msa_seqs ,
714785 processed_msa_dir = processed_msa_dir ,
715786 processed_constraints_dir = processed_constraints_dir ,
@@ -869,6 +940,30 @@ def cli() -> None:
869940 ),
870941 default = "greedy" ,
871942)
943+ @click .option (
944+ "--msa_server_username" ,
945+ type = str ,
946+ help = "MSA server username for basic auth. Used only if --use_msa_server is set. Can also be set via BOLTZ_MSA_USERNAME environment variable." ,
947+ default = None ,
948+ )
949+ @click .option (
950+ "--msa_server_password" ,
951+ type = str ,
952+ help = "MSA server password for basic auth. Used only if --use_msa_server is set. Can also be set via BOLTZ_MSA_PASSWORD environment variable." ,
953+ default = None ,
954+ )
955+ @click .option (
956+ "--api_key_header" ,
957+ type = str ,
958+ help = "Custom header key for API key authentication (default: X-API-Key)." ,
959+ default = None ,
960+ )
961+ @click .option (
962+ "--api_key_value" ,
963+ type = str ,
964+ help = "Custom header value for API key authentication." ,
965+ default = None ,
966+ )
872967@click .option (
873968 "--use_potentials" ,
874969 is_flag = True ,
@@ -967,6 +1062,10 @@ def predict( # noqa: C901, PLR0915, PLR0912
9671062 use_msa_server : bool = False ,
9681063 msa_server_url : str = "https://api.colabfold.com" ,
9691064 msa_pairing_strategy : str = "greedy" ,
1065+ msa_server_username : Optional [str ] = None ,
1066+ msa_server_password : Optional [str ] = None ,
1067+ api_key_header : Optional [str ] = None ,
1068+ api_key_value : Optional [str ] = None ,
9701069 use_potentials : bool = False ,
9711070 model : Literal ["boltz1" , "boltz2" ] = "boltz2" ,
9721071 method : Optional [str ] = None ,
@@ -1011,6 +1110,23 @@ def predict( # noqa: C901, PLR0915, PLR0912
10111110 cache = Path (cache ).expanduser ()
10121111 cache .mkdir (parents = True , exist_ok = True )
10131112
1113+ # Get MSA server credentials from environment variables if not provided
1114+ if use_msa_server :
1115+ if msa_server_username is None :
1116+ msa_server_username = os .environ .get ("BOLTZ_MSA_USERNAME" )
1117+ if msa_server_password is None :
1118+ msa_server_password = os .environ .get ("BOLTZ_MSA_PASSWORD" )
1119+ if api_key_value is None :
1120+ api_key_value = os .environ .get ("MSA_API_KEY_VALUE" )
1121+
1122+ click .echo (f"MSA server enabled: { msa_server_url } " )
1123+ if api_key_value :
1124+ click .echo ("MSA server authentication: using API key header" )
1125+ elif msa_server_username and msa_server_password :
1126+ click .echo ("MSA server authentication: using basic auth" )
1127+ else :
1128+ click .echo ("MSA server authentication: no credentials provided" )
1129+
10141130 # Create output directories
10151131 data = Path (data ).expanduser ()
10161132 out_dir = Path (out_dir ).expanduser ()
@@ -1050,6 +1166,10 @@ def predict( # noqa: C901, PLR0915, PLR0912
10501166 use_msa_server = use_msa_server ,
10511167 msa_server_url = msa_server_url ,
10521168 msa_pairing_strategy = msa_pairing_strategy ,
1169+ msa_server_username = msa_server_username ,
1170+ msa_server_password = msa_server_password ,
1171+ api_key_header = api_key_header ,
1172+ api_key_value = api_key_value ,
10531173 boltz2 = model == "boltz2" ,
10541174 preprocessing_threads = preprocessing_threads ,
10551175 max_msa_seqs = max_msa_seqs ,
0 commit comments