@@ -70,6 +70,38 @@ def _validate_environment_variables(self, server_name: str, required_env: List[s
7070 f"Please set these variables in your environment or .env file."
7171 )
7272
73+ def _process_headers (self , headers : Dict [str , str ]) -> Dict [str , str ]:
74+ """Process headers by substituting environment variables.
75+
76+ Supports environment variable substitution in the format:
77+ - ${ENV_VAR} or $ENV_VAR for environment variables
78+ - Raw strings are passed through unchanged
79+
80+ Example:
81+ {"Authorization": "Bearer ${API_KEY}"}
82+ -> {"Authorization": "Bearer abc123"} (if API_KEY=abc123)
83+ """
84+ import re
85+
86+ processed_headers = {}
87+ for key , value in headers .items ():
88+ # Match ${VAR} or $VAR patterns
89+ def replace_env_var (match ):
90+ var_name = match .group (1 ) or match .group (2 )
91+ env_value = os .environ .get (var_name )
92+ if env_value is None :
93+ raise ValueError (
94+ f"Environment variable '{ var_name } ' referenced in header '{ key } ' "
95+ f"is not set. Please set it in your environment or .env file."
96+ )
97+ return env_value
98+
99+ # Replace ${VAR} or $VAR with environment variable value
100+ processed_value = re .sub (r"\$\{([^}]+)\}|\$([A-Za-z_][A-Za-z0-9_]*)" , replace_env_var , value )
101+ processed_headers [key ] = processed_value
102+
103+ return processed_headers
104+
73105 async def connect_to_servers (self ):
74106 """Connect to all configured MCP servers"""
75107 if not self .config .mcpServers :
@@ -111,8 +143,17 @@ async def _connect_to_server(
111143 if not url :
112144 raise ValueError (f"Server '{ server_name } ' must have a 'url' specified" )
113145
114- # Connect using streamable HTTP client - manage resources manually
115- http_transport = await self .exit_stack .enter_async_context (streamablehttp_client (url ))
146+ # Build headers only from the authorization field (Responses-style)
147+ processed_headers : Dict [str , str ] = {}
148+ auth_token = getattr (server_config , "authorization" , None )
149+ if auth_token :
150+ # Support env substitution in the authorization value as well
151+ processed_headers = self ._process_headers ({"Authorization" : auth_token })
152+
153+ # Connect using streamable HTTP client with auth headers
154+ http_transport = await self .exit_stack .enter_async_context (
155+ streamablehttp_client (url , headers = processed_headers )
156+ )
116157 read_stream , write_stream , get_session_id = http_transport
117158 session = await self .exit_stack .enter_async_context (ClientSession (read_stream , write_stream ))
118159 else :
0 commit comments