Skip to content

Commit 00c9ad1

Browse files
committed
Append MCP headers to explicit tools
1 parent 9ef5d2e commit 00c9ad1

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

src/utils/responses.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,68 @@ async def get_mcp_tools(
729729
return tools
730730

731731

732+
def apply_mcp_headers_to_explicit_tools(
733+
tools: list[InputTool],
734+
token: Optional[str] = None,
735+
mcp_headers: Optional[McpHeaders] = None,
736+
request_headers: Optional[Mapping[str, str]] = None,
737+
) -> list[InputTool]:
738+
"""Merge resolved MCP headers into explicit request MCP tools.
739+
740+
Args:
741+
tools: Tools from the request after BYOK translation.
742+
token: Optional bearer token for kubernetes MCP auth.
743+
mcp_headers: Per-request MCP-HEADERS map keyed by server name.
744+
request_headers: Incoming HTTP headers for allowlist propagation.
745+
746+
Returns:
747+
New tool list with MCP entries updated or omitted.
748+
"""
749+
if not tools:
750+
return tools
751+
752+
complete_headers = build_mcp_headers(
753+
configuration, mcp_headers or {}, request_headers, token
754+
)
755+
servers_by_name = {s.name: s for s in configuration.mcp_servers}
756+
757+
out: list[InputTool] = []
758+
for tool in tools:
759+
if tool.type != "mcp":
760+
out.append(tool)
761+
continue
762+
763+
mcp_tool = cast(InputToolMCP, tool)
764+
mcp_server = servers_by_name.get(mcp_tool.server_label)
765+
if mcp_server is None:
766+
out.append(tool)
767+
continue
768+
769+
headers: dict[str, str] = dict(complete_headers.get(mcp_server.name, {}))
770+
unresolved = find_unresolved_auth_headers(
771+
mcp_server.authorization_headers, headers
772+
)
773+
if unresolved:
774+
logger.warning(
775+
"Skipping explicit MCP tool %s: required %d auth headers but only resolved %d",
776+
mcp_server.name,
777+
len(mcp_server.authorization_headers),
778+
len(mcp_server.authorization_headers) - len(unresolved),
779+
)
780+
continue
781+
782+
authorization = headers.pop("Authorization", None)
783+
out.append(
784+
mcp_tool.model_copy(
785+
update={
786+
"headers": headers if headers else None,
787+
"authorization": authorization,
788+
}
789+
)
790+
)
791+
return out
792+
793+
732794
def parse_referenced_documents( # pylint: disable=too-many-locals
733795
response: Optional[ResponseObject],
734796
vector_store_ids: Optional[list[str]] = None,
@@ -1553,6 +1615,9 @@ async def resolve_tool_choice(
15531615
# Pass tools explicitly configured for this request
15541616
byok_rags = configuration.configuration.byok_rag
15551617
prepared_tools = translate_tools_vector_store_ids(tools, byok_rags)
1618+
prepared_tools = apply_mcp_headers_to_explicit_tools(
1619+
prepared_tools, token, mcp_headers, request_headers
1620+
)
15561621

15571622
if isinstance(tool_choice, AllowedTools):
15581623
# Apply filters to tools if specified and overwrite tool choice mode

0 commit comments

Comments
 (0)