fix(mcp): lift Authorization headers into bearer credentials on import

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yassin 2026-08-29 20:11:45 +00:00
parent 177463e9b0
commit 0557a95259
2 changed files with 64 additions and 4 deletions

View file

@ -119,7 +119,8 @@ def _convert_entry(name: str, entry: MCPConnectorEntry) -> ConvertedConnector |
return ConnectorConversionError(name=name, error=f"Unsupported connector type '{entry.type}'.")
transport: Final = MCPTransport.sse if entry_type in _SSE_TYPES else MCPTransport.http
credentials: Final = _bearer_credentials(entry.authorization_token)
token: Final = entry.authorization_token or _header_bearer_token(entry.headers)
static_headers: Final = entry.headers if entry.authorization_token else _non_auth_headers(entry.headers)
try:
remote_request: Final = NewMCPServerRequest(
server_name=sanitized_name,
@ -128,9 +129,9 @@ def _convert_entry(name: str, entry: MCPConnectorEntry) -> ConvertedConnector |
approval_status=MCPApprovalStatus.active,
transport=transport,
url=entry.url,
auth_type=MCPAuth.bearer_token if entry.authorization_token else MCPAuth.none,
credentials=credentials,
static_headers=dict(entry.headers) if entry.headers is not None else None,
auth_type=MCPAuth.bearer_token if token else MCPAuth.none,
credentials=_bearer_credentials(token),
static_headers=dict(static_headers) if static_headers is not None else None,
)
except ValidationError as e:
return ConnectorConversionError(name=name, error=_first_validation_message(e))
@ -144,6 +145,24 @@ def _bearer_credentials(token: str | None) -> MCPCredentials | None:
return credentials
_BEARER_PREFIX: Final = "bearer "
def _header_bearer_token(headers: Mapping[str, str] | None) -> str | None:
values: Final = tuple(value for key, value in (headers or {}).items() if key.lower() == "authorization")
if not values:
return None
value: Final = values[0]
return value[len(_BEARER_PREFIX) :] if value.lower().startswith(_BEARER_PREFIX) else value
def _non_auth_headers(headers: Mapping[str, str] | None) -> Mapping[str, str] | None:
if headers is None:
return None
remaining: Final = {key: value for key, value in headers.items() if key.lower() != "authorization"}
return remaining or None
def _first_validation_message(error: ValidationError) -> str:
messages: Final = tuple(str(detail.get("msg", "")) for detail in error.errors())
return messages[0] if messages else str(error)

View file

@ -55,6 +55,47 @@ class TestConvertMcpServersMapping:
assert result.request.static_headers == {"X-Env": "prod"}
assert result.request.description == "GitHub connector"
def test_authorization_header_becomes_bearer_credentials(self):
result = _single(
{
"mcpServers": {
"srv": {
"url": "https://x.example/mcp",
"headers": {"Authorization": "Bearer header-token", "X-Env": "prod"},
}
}
}
)
assert isinstance(result, ConvertedConnector)
assert result.request.auth_type == MCPAuth.bearer_token
assert result.request.credentials == {"auth_value": "header-token"}
assert result.request.static_headers == {"X-Env": "prod"}
def test_authorization_header_without_bearer_prefix(self):
result = _single(
{"mcpServers": {"srv": {"url": "https://x.example/mcp", "headers": {"authorization": "raw-token"}}}}
)
assert isinstance(result, ConvertedConnector)
assert result.request.auth_type == MCPAuth.bearer_token
assert result.request.credentials == {"auth_value": "raw-token"}
assert result.request.static_headers is None
def test_authorization_token_wins_over_authorization_header(self):
result = _single(
{
"mcpServers": {
"srv": {
"url": "https://x.example/mcp",
"authorization_token": "explicit-token",
"headers": {"Authorization": "Bearer header-token"},
}
}
}
)
assert isinstance(result, ConvertedConnector)
assert result.request.credentials == {"auth_value": "explicit-token"}
assert result.request.static_headers == {"Authorization": "Bearer header-token"}
def test_camel_case_authorization_token_alias(self):
result = _single(
{"mcpServers": {"srv": {"url": "https://x.example/mcp", "authorizationToken": "tok"}}}