From eadcade73b51a2a83210233187ed4f061e0221e4 Mon Sep 17 00:00:00 2001 From: Lothnic Date: Thu, 2 Jul 2026 16:57:01 +0530 Subject: [PATCH 1/2] fix(agentgateway): log correlation-id on mcp tool call failure --- src/sap_cloud_sdk/agentgateway/_customer.py | 58 +++++++++++++-------- src/sap_cloud_sdk/agentgateway/_lob.py | 57 +++++++++++++------- 2 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/sap_cloud_sdk/agentgateway/_customer.py b/src/sap_cloud_sdk/agentgateway/_customer.py index be5019ea..57939f44 100644 --- a/src/sap_cloud_sdk/agentgateway/_customer.py +++ b/src/sap_cloud_sdk/agentgateway/_customer.py @@ -551,26 +551,42 @@ async def call_mcp_tool_customer( Tool execution result as string. """ logger.info("Calling tool '%s' on server '%s'", tool.name, tool.server_name) + correlation_id: str | None = None - async with httpx.AsyncClient( - headers={ - "Authorization": f"Bearer {auth_token}", - "x-correlation-id": str(uuid.uuid4()), - }, - timeout=timeout, - ) as http_client: - async with streamable_http_client(tool.url, http_client=http_client) as ( - read, - write, - _, - ): - async with ClientSession(read, write) as session: - await session.initialize() - result = await session.call_tool(tool.name, kwargs) + async def _capture_correlation_id(response: httpx.Response) -> None: + nonlocal correlation_id + cid = response.headers.get("x-correlation-id") + if cid: + correlation_id = cid - if not result.content: - logger.warning("Tool '%s' returned empty content", tool.name) - return "" - - first = result.content[0] - return str(getattr(first, "text", "")) + try: + async with httpx.AsyncClient( + headers={ + "Authorization": f"Bearer {auth_token}", + "x-correlation-id": str(uuid.uuid4()), + }, + timeout=timeout, + event_hooks={"response": [_capture_correlation_id]}, + ) as http_client: + async with streamable_http_client(tool.url, http_client=http_client) as ( + read, + write, + _, + ): + async with ClientSession(read, write) as session: + await session.initialize() + result = await session.call_tool(tool.name, kwargs) + + if not result.content: + logger.warning("Tool '%s' returned empty content", tool.name) + return "" + + first = result.content[0] + return str(getattr(first, "text", "")) + except Exception: + logger.error( + "MCP tool call failed for '%s' (x-correlation-id: %s)", + tool.name, + correlation_id or "unknown", + ) + raise diff --git a/src/sap_cloud_sdk/agentgateway/_lob.py b/src/sap_cloud_sdk/agentgateway/_lob.py index 0ada5b63..b7734f14 100644 --- a/src/sap_cloud_sdk/agentgateway/_lob.py +++ b/src/sap_cloud_sdk/agentgateway/_lob.py @@ -383,26 +383,43 @@ async def call_mcp_tool_lob( Returns: Tool execution result as string. """ - async with httpx.AsyncClient( - headers={ - "Authorization": f"Bearer {user_auth_token}", - "x-correlation-id": str(uuid.uuid4()), - }, - timeout=timeout, - ) as http_client: - async with streamable_http_client(tool.url, http_client=http_client) as ( - read, - write, - _, - ): - async with ClientSession(read, write) as session: - await session.initialize() - result = await session.call_tool(tool.name, kwargs) - if not result.content: - logger.warning("Tool '%s' returned empty content", tool.name) - return "" - first = result.content[0] - return str(getattr(first, "text", "")) + correlation_id: str | None = None + + async def _capture_correlation_id(response: httpx.Response) -> None: + nonlocal correlation_id + cid = response.headers.get("x-correlation-id") + if cid: + correlation_id = cid + + try: + async with httpx.AsyncClient( + headers={ + "Authorization": f"Bearer {user_auth_token}", + "x-correlation-id": str(uuid.uuid4()), + }, + timeout=timeout, + event_hooks={"response": [_capture_correlation_id]}, + ) as http_client: + async with streamable_http_client(tool.url, http_client=http_client) as ( + read, + write, + _, + ): + async with ClientSession(read, write) as session: + await session.initialize() + result = await session.call_tool(tool.name, kwargs) + if not result.content: + logger.warning("Tool '%s' returned empty content", tool.name) + return "" + first = result.content[0] + return str(getattr(first, "text", "")) + except Exception: + logger.error( + "MCP tool call failed for '%s' (x-correlation-id: %s)", + tool.name, + correlation_id or "unknown", + ) + raise async def _fetch_agent_card( From 92e5c6681202524a3eb6901081b9c260b7550682 Mon Sep 17 00:00:00 2001 From: Mayank Joshi Date: Thu, 2 Jul 2026 17:41:08 +0530 Subject: [PATCH 2/2] Using `logger.exception(...)` to preserve the correlation-id message and include the traceback for debugging. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/sap_cloud_sdk/agentgateway/_customer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sap_cloud_sdk/agentgateway/_customer.py b/src/sap_cloud_sdk/agentgateway/_customer.py index 57939f44..e7386c1c 100644 --- a/src/sap_cloud_sdk/agentgateway/_customer.py +++ b/src/sap_cloud_sdk/agentgateway/_customer.py @@ -584,7 +584,7 @@ async def _capture_correlation_id(response: httpx.Response) -> None: first = result.content[0] return str(getattr(first, "text", "")) except Exception: - logger.error( + logger.exception( "MCP tool call failed for '%s' (x-correlation-id: %s)", tool.name, correlation_id or "unknown",