@@ -222,16 +222,16 @@ def _get_tool_type(self) -> Optional[ToolType]:
222222 return None
223223 return None
224224
225- def _parse_protocol_spec_mcp_url (self ) -> Tuple [str , str ]:
226- """从 protocol_spec 解析 MCP 服务器 URL 和 session_affinity / Parse MCP server URL and session_affinity from protocol_spec
225+ def _parse_protocol_spec_mcp_url (self ) -> Tuple [str , str , Dict [ str , str ] ]:
226+ """从 protocol_spec 解析 MCP 服务器 URL、session_affinity 和 headers / Parse MCP server URL, session_affinity and headers from protocol_spec
227227
228228 用于 MCP_REMOTE + proxy_enabled=false 场景,从 protocol_spec JSON 中提取
229- 第一个 mcpServers entry 的 url 和 transportType 。
230- Used for MCP_REMOTE + proxy_enabled=false scenario, extracts url and
231- transportType from the first mcpServers entry in protocol_spec JSON.
229+ 第一个 mcpServers entry 的 url、transportType 和 headers 。
230+ Used for MCP_REMOTE + proxy_enabled=false scenario, extracts url,
231+ transportType and headers from the first mcpServers entry in protocol_spec JSON.
232232
233233 Returns:
234- Tuple[str, str] : (mcp_url, session_affinity)
234+ Tuple[str, str, Dict[str, str]] : (mcp_url, session_affinity, headers )
235235
236236 Raises:
237237 ValueError: protocol_spec 为空、格式不合法或缺少必要字段时抛出
@@ -278,20 +278,26 @@ def _parse_protocol_spec_mcp_url(self) -> Tuple[str, str]:
278278 else :
279279 session_affinity = "MCP_SSE"
280280
281- return url , session_affinity
281+ # 解析 headers(可选字段)/ Parse headers (optional field)
282+ raw_headers = first_server .get ("headers" )
283+ spec_headers : Dict [str , str ] = {}
284+ if raw_headers and isinstance (raw_headers , dict ):
285+ spec_headers = {str (k ): str (v ) for k , v in raw_headers .items ()}
286+
287+ return url , session_affinity , spec_headers
282288
283289 def _get_mcp_endpoint (
284290 self , config : Optional [Config ] = None
285- ) -> Optional [Tuple [str , str ]]:
286- """获取 MCP 数据链路 URL 和 session_affinity / Get MCP data endpoint URL and session_affinity
291+ ) -> Optional [Tuple [str , str , Dict [ str , str ] ]]:
292+ """获取 MCP 数据链路 URL、session_affinity 和 spec headers / Get MCP data endpoint URL, session_affinity and spec headers
287293
288- MCP_REMOTE + proxy_enabled=false 时从 protocol_spec 解析 URL 和 session_affinity 。
289- 其他场景使用 data_endpoint 拼接,session_affinity 从 mcp_config 获取。
290- For MCP_REMOTE with proxy disabled, parses URL and session_affinity from protocol_spec.
291- Otherwise constructs URL from data_endpoint and gets session_affinity from mcp_config.
294+ MCP_REMOTE + proxy_enabled=false 时从 protocol_spec 解析 URL、session_affinity 和 headers 。
295+ 其他场景使用 data_endpoint 拼接,session_affinity 从 mcp_config 获取,headers 为空 。
296+ For MCP_REMOTE with proxy disabled, parses URL, session_affinity and headers from protocol_spec.
297+ Otherwise constructs URL from data_endpoint and gets session_affinity from mcp_config, headers empty .
292298
293299 Returns:
294- Optional[Tuple[str, str]] : (endpoint_url, session_affinity) 或 None
300+ Optional[Tuple[str, str, Dict[str, str]]] : (endpoint_url, session_affinity, spec_headers ) 或 None
295301 """
296302 is_mcp_remote_without_proxy = (
297303 self .create_method == "MCP_REMOTE"
@@ -317,8 +323,13 @@ def _get_mcp_endpoint(
317323 return (
318324 f"{ data_endpoint } /tools/{ effective_name } /mcp" ,
319325 session_affinity ,
326+ {},
320327 )
321- return f"{ data_endpoint } /tools/{ effective_name } /sse" , session_affinity
328+ return (
329+ f"{ data_endpoint } /tools/{ effective_name } /sse" ,
330+ session_affinity ,
331+ {},
332+ )
322333
323334 async def list_tools_async (
324335 self , config : Optional [Config ] = None
@@ -345,7 +356,7 @@ async def list_tools_async(
345356 )
346357 return []
347358
348- mcp_endpoint , session_affinity = endpoint_result
359+ mcp_endpoint , session_affinity , spec_headers = endpoint_result
349360
350361 # MCP_REMOTE + proxy_enabled=false 时直连外部服务,不走 RAM 鉴权
351362 # Only skip RAM auth for MCP_REMOTE with proxy disabled (direct external connection)
@@ -354,11 +365,15 @@ async def list_tools_async(
354365 and not pydash .get (self , "mcp_config.proxy_enabled" , False )
355366 )
356367
368+ # 合并 headers:protocol_spec 中的 headers 优先级更高
369+ # Merge headers: protocol_spec headers take precedence
357370 cfg = Config .with_configs (config )
371+ merged_headers = {** (cfg .get_headers () or {}), ** spec_headers }
372+
358373 session = ToolMCPSession (
359374 endpoint = mcp_endpoint ,
360375 session_affinity = session_affinity ,
361- headers = cfg . get_headers () ,
376+ headers = merged_headers ,
362377 config = cfg ,
363378 use_ram_auth = not is_mcp_remote_without_proxy ,
364379 )
@@ -405,7 +420,7 @@ def list_tools(self, config: Optional[Config] = None) -> List[ToolInfo]:
405420 )
406421 return []
407422
408- mcp_endpoint , session_affinity = endpoint_result
423+ mcp_endpoint , session_affinity , spec_headers = endpoint_result
409424
410425 # MCP_REMOTE + proxy_enabled=false 时直连外部服务,不走 RAM 鉴权
411426 # Only skip RAM auth for MCP_REMOTE with proxy disabled (direct external connection)
@@ -414,11 +429,15 @@ def list_tools(self, config: Optional[Config] = None) -> List[ToolInfo]:
414429 and not pydash .get (self , "mcp_config.proxy_enabled" , False )
415430 )
416431
432+ # 合并 headers:protocol_spec 中的 headers 优先级更高
433+ # Merge headers: protocol_spec headers take precedence
417434 cfg = Config .with_configs (config )
435+ merged_headers = {** (cfg .get_headers () or {}), ** spec_headers }
436+
418437 session = ToolMCPSession (
419438 endpoint = mcp_endpoint ,
420439 session_affinity = session_affinity ,
421- headers = cfg . get_headers () ,
440+ headers = merged_headers ,
422441 config = cfg ,
423442 use_ram_auth = not is_mcp_remote_without_proxy ,
424443 )
@@ -471,7 +490,7 @@ async def call_tool_async(
471490 f"MCP endpoint not available for tool { self .name } "
472491 )
473492
474- mcp_endpoint , session_affinity = endpoint_result
493+ mcp_endpoint , session_affinity , spec_headers = endpoint_result
475494
476495 # MCP_REMOTE + proxy_enabled=false 时直连外部服务,不走 RAM 鉴权
477496 # Only skip RAM auth for MCP_REMOTE with proxy disabled (direct external connection)
@@ -480,11 +499,15 @@ async def call_tool_async(
480499 and not pydash .get (self , "mcp_config.proxy_enabled" , False )
481500 )
482501
502+ # 合并 headers:protocol_spec 中的 headers 优先级更高
503+ # Merge headers: protocol_spec headers take precedence
483504 cfg = Config .with_configs (config )
505+ merged_headers = {** (cfg .get_headers () or {}), ** spec_headers }
506+
484507 session = ToolMCPSession (
485508 endpoint = mcp_endpoint ,
486509 session_affinity = session_affinity ,
487- headers = cfg . get_headers () ,
510+ headers = merged_headers ,
488511 config = cfg ,
489512 use_ram_auth = not is_mcp_remote_without_proxy ,
490513 )
@@ -542,7 +565,7 @@ def call_tool(
542565 f"MCP endpoint not available for tool { self .name } "
543566 )
544567
545- mcp_endpoint , session_affinity = endpoint_result
568+ mcp_endpoint , session_affinity , spec_headers = endpoint_result
546569
547570 # MCP_REMOTE + proxy_enabled=false 时直连外部服务,不走 RAM 鉴权
548571 # Only skip RAM auth for MCP_REMOTE with proxy disabled (direct external connection)
@@ -551,11 +574,15 @@ def call_tool(
551574 and not pydash .get (self , "mcp_config.proxy_enabled" , False )
552575 )
553576
577+ # 合并 headers:protocol_spec 中的 headers 优先级更高
578+ # Merge headers: protocol_spec headers take precedence
554579 cfg = Config .with_configs (config )
580+ merged_headers = {** (cfg .get_headers () or {}), ** spec_headers }
581+
555582 session = ToolMCPSession (
556583 endpoint = mcp_endpoint ,
557584 session_affinity = session_affinity ,
558- headers = cfg . get_headers () ,
585+ headers = merged_headers ,
559586 config = cfg ,
560587 use_ram_auth = not is_mcp_remote_without_proxy ,
561588 )
0 commit comments