Skip to content

Commit df28ae2

Browse files
DX-120403 Log auth 401s in transport middleware
1 parent 592317f commit df28ae2

2 files changed

Lines changed: 32 additions & 2 deletions

File tree

src/dremioai/servers/mcp.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,19 @@ def streamable_http_app(self):
299299
else:
300300
token_verifier = FastMCPServerWithAuthToken.DelegatingTokenVerifier()
301301
app = super().streamable_http_app()
302-
app.add_middleware(MCPTransportLoggingMiddleware)
303302
app.add_middleware(RequireAuthWithWWWAuthenticateMiddleware)
304303
app.add_middleware(AuthContextMiddleware)
305304
app.add_middleware(
306305
AuthenticationMiddleware, backend=BearerAuthBackend(token_verifier)
307306
)
308-
# Add middleware in reverse order (last added = first executed)
307+
# Starlette inserts middleware at the front, so the last added middleware
308+
# runs first. Keep transport logging outermost so it observes auth 401s.
309309
if self.support_project_id_endpoints:
310310
# this means, dynamically allow endpoints
311311
# like ../mcp/{project_id}/.. and extract that project id as
312312
# context var
313313
app.add_middleware(ProjectIdMiddleware)
314+
app.add_middleware(MCPTransportLoggingMiddleware)
314315

315316
# Metrics are now served on a separate port, not mounted here
316317
return app

tests/servers/test_jwks_verifier.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import structlog
2424
from unittest.mock import patch, MagicMock, AsyncMock
2525

26+
import httpx
2627
import jwt as pyjwt
2728
from jwt import PyJWKClient, PyJWKClientError, ExpiredSignatureError
2829
from mcp.server.lowlevel.server import request_ctx
@@ -423,6 +424,34 @@ def test_streamable_http_transport_is_stateless(self):
423424

424425
assert mcp.settings.stateless_http is True
425426

427+
@pytest.mark.asyncio
428+
async def test_transport_logging_wraps_unauthorized_responses(self, caplog):
429+
with patch("dremioai.servers.mcp.tools.get_tools", return_value=[]), patch(
430+
"dremioai.servers.mcp.tools.get_resources", return_value=[]
431+
):
432+
mcp = init(
433+
mode=None,
434+
transport=Transports.streamable_http,
435+
host="127.0.0.1",
436+
port=8000,
437+
mock=True,
438+
)
439+
440+
app = mcp.streamable_http_app()
441+
transport = httpx.ASGITransport(app=app)
442+
async with httpx.AsyncClient(
443+
transport=transport, base_url="http://testserver"
444+
) as client:
445+
with caplog.at_level(logging.INFO):
446+
response = await client.post("/mcp")
447+
448+
assert response.status_code == 401
449+
messages = [str(r.message) for r in caplog.records if r.levelno >= logging.INFO]
450+
assert any("Unauthorized request rejected" in msg for msg in messages)
451+
assert any(
452+
"MCP transport request failed" in msg and "401" in msg for msg in messages
453+
)
454+
426455

427456
class TestMakeLoggedInvoke:
428457
"""Tests for make_logged_invoke WARNING logging on tool exceptions."""

0 commit comments

Comments
 (0)