-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
Description
According to the spec, “Authorization MUST be included in every HTTP request from client to server, even within the same logical session.” The current Python SDK only attaches Authorization when the transport is created with an auth provider; if auth is omitted (or a non-auth client is used), requests are sent without Authorization. This makes it easy for client implementations to violate the MUST requirement.
Evidence
src/mcp/client/streamable_http.py uses httpx client with the provided auth parameter; no guard/warning if auth is None.
async with httpx_client_factory(
headers=transport.request_headers,
timeout=httpx.Timeout(transport.timeout, read=transport.sse_read_timeout),
auth=transport.auth, # If auth is None, there are no guards/rejects.
) as client:
@asynccontextmanager
async def streamablehttp_client(
url: str,
headers: dict[str, str] | None = None,
timeout: float | timedelta = 30,
sse_read_timeout: float | timedelta = 60 * 5,
terminate_on_close: bool = True,
httpx_client_factory: McpHttpClientFactory = create_mcp_http_client,
auth: httpx.Auth | None = None, # Caller can give "none"
) -> AsyncGenerator[
tuple[
MemoryObjectReceiveStream[SessionMessage | Exception],
MemoryObjectSendStream[SessionMessage],
GetSessionIdCallback,
],
None,
]:
src/mcp/client/sse.py same pattern.
async with httpx_client_factory(
headers=headers, auth=auth, timeout=httpx.Timeout(timeout, read=sse_read_timeout)
) as client: # If auth is None, there are no guards/rejects.
src/mcp/client/auth.py adds Authorization only when tokens exist; there is no transport-level enforcement that all requests must go through this auth.
def _add_auth_header(self, request: httpx.Request) -> None:
"""Add authorization header to request if we have valid tokens."""
if self.context.current_tokens and self.context.current_tokens.access_token:
request.headers["Authorization"] = f"Bearer {self.context.current_tokens.access_token}"
Impact
Client implementations can inadvertently send unauthenticated HTTP requests, violating the spec’s MUST.
Proposed remediation
Enforce auth: if HTTP transport is used without an auth provider, fail fast or emit a strong warning.
Provide a secure default: default to OAuthClientProvider (or a no-op that still injects Authorization where possible) unless explicitly disabled.
Optionally add a runtime guard in post_writer/SSE paths that rejects sending requests when Authorization is absent (unless explicitly allowed for bootstrap endpoints).
I am not very confident with this finding. If one maintainer can make a double check and let me know if it's a real issue or not, I will be very appreciative!
Example Code
Python & MCP Python SDK
latest