Skip to content

Commit 912fc2f

Browse files
DX-119753: clean up transport log header parsing
1 parent 78914d5 commit 912fc2f

2 files changed

Lines changed: 42 additions & 12 deletions

File tree

src/dremioai/servers/mcp.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from uuid import uuid4
2424
from enum import StrEnum, auto
2525
from functools import reduce, wraps
26+
from http import HTTPStatus
2627
from json import dump as jdump
2728
from json import load
2829
from operator import ior
@@ -54,6 +55,7 @@
5455
from pydantic.networks import AnyUrl
5556
from rich import console, table
5657
from rich import print as pp
58+
from starlette.datastructures import Headers
5759
from starlette.middleware.authentication import AuthenticationMiddleware
5860
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
5961
from starlette.requests import Request
@@ -78,6 +80,7 @@
7880

7981
class MCPTransportLoggingMiddleware:
8082
logger = log.logger("MCPTransportLoggingMiddleware")
83+
status_to_log = HTTPStatus.MULTIPLE_CHOICES # log 300 and above
8184
max_error_body_log_bytes = 2048
8285

8386
def __init__(self, app: ASGIApp):
@@ -102,7 +105,7 @@ async def send_wrapper(message: Message):
102105
elif (
103106
message["type"] == "http.response.body"
104107
and status_code is not None
105-
and status_code >= 400
108+
and status_code >= self.status_to_log
106109
):
107110
body = message.get("body", b"")
108111
remaining = self.max_error_body_log_bytes - len(captured_body)
@@ -122,7 +125,7 @@ async def send_wrapper(message: Message):
122125
)
123126
raise
124127

125-
if status_code is not None and status_code >= 400:
128+
if status_code is not None and status_code >= self.status_to_log:
126129
response_body = (
127130
captured_body.decode("utf-8", errors="replace").strip()
128131
if captured_body
@@ -133,20 +136,12 @@ async def send_wrapper(message: Message):
133136
status_code=status_code,
134137
response_body=response_body,
135138
response_body_truncated=response_body_truncated,
136-
response_mcp_session_id=self._header(
137-
response_headers, MCP_SESSION_ID_HEADER
139+
response_mcp_session_id=Headers(raw=response_headers).get(
140+
MCP_SESSION_ID_HEADER
138141
),
139142
**self._request_log_context(request),
140143
)
141144

142-
@staticmethod
143-
def _header(headers: List[Tuple[bytes, bytes]], name: str) -> str | None:
144-
expected = name.lower().encode()
145-
for key, value in headers:
146-
if key.lower() == expected:
147-
return value.decode("utf-8", errors="replace")
148-
return None
149-
150145
@staticmethod
151146
def _request_log_context(request: Request) -> Dict[str, Any]:
152147
context = {

tests/servers/test_jwks_verifier.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,41 @@ async def send(message):
331331
assert "203.0.113.10" in logged
332332
assert "secret-token" not in logged
333333

334+
@pytest.mark.asyncio
335+
async def test_logs_redirects(self, caplog):
336+
async def app(scope, receive, send):
337+
response = Response(status_code=307, headers={"location": "/mcp/new"})
338+
await response(scope, receive, send)
339+
340+
scope = {
341+
"type": "http",
342+
"method": "GET",
343+
"path": "/mcp/project-123",
344+
"headers": [],
345+
"client": ("203.0.113.10", 4321),
346+
"server": ("testserver", 80),
347+
"scheme": "http",
348+
"query_string": b"",
349+
}
350+
351+
async def receive():
352+
return {"type": "http.request", "body": b"", "more_body": False}
353+
354+
async def send(_message):
355+
pass
356+
357+
middleware = MCPTransportLoggingMiddleware(app)
358+
with caplog.at_level(logging.WARNING):
359+
await middleware(scope, receive, send)
360+
361+
warning_messages = [
362+
str(r.message) for r in caplog.records if r.levelno >= logging.WARNING
363+
]
364+
assert any(
365+
"MCP transport request failed" in msg and "307" in msg
366+
for msg in warning_messages
367+
)
368+
334369

335370
class TestStreamableHttpInit:
336371
def test_streamable_http_transport_is_stateless(self):

0 commit comments

Comments
 (0)