Bug: MCP transport autodetection treats uppercase URL schemes as stdio
Describe the bug
MCPClientManager.convert_configs_to_langchain_format performs case-sensitive URL-prefix checks when automatically selecting the transport for a remote MCP server.
URI scheme names are case-insensitive. However, remote URLs using uppercase or mixed-case schemes are not recognized.
For example, this configuration:
{
"name": "remote",
"connection_url": (
"HTTPS://mcp.example.com/service"
),
"connection_headers": {
"Authorization": "Bearer test-token",
},
}is converted into:
{
"transport": "stdio",
}instead of:
{
"transport": "streamable_http",
"url": "HTTPS://mcp.example.com/service",
"headers": {
"Authorization": "Bearer test-token",
},
}The same behavior affects uppercase HTTP, WS, and WSS schemes.
The remote configuration is therefore reclassified as a local stdio configuration, and both its URL and connection headers are omitted.
To Reproduce
- Check out GPT Researcher
mainat commit:
6f998577d547b1e54ec662dac63583aa11e3b84b- Install the project and test dependencies:
python -m pip install -e ".[test]"- Create
tests/test_mcp_client_uppercase_url_schemes.py:
import pytest
from gpt_researcher.mcp.client import MCPClientManager
@pytest.mark.parametrize(
("url", "transport"),
[
(
"HTTPS://mcp.example.com/service",
"streamable_http",
),
(
"HTTP://mcp.example.com/service",
"streamable_http",
),
(
"WSS://mcp.example.com/service",
"websocket",
),
(
"WS://mcp.example.com/service",
"websocket",
),
],
)
def test_uppercase_url_scheme_selects_remote_transport(
url,
transport,
):
headers = {
"Authorization": "Bearer test-token",
}
result = MCPClientManager(
[
{
"name": "remote",
"connection_url": url,
"connection_headers": headers,
}
]
).convert_configs_to_langchain_format()
assert result["remote"] == {
"transport": transport,
"url": url,
"headers": headers,
}- Run:
python -m pytest \
tests/test_mcp_client_uppercase_url_schemes.py \
-q- Observe that all four parameterized cases fail.
Representative failure:
Expected:
{
"transport": "streamable_http",
"url": "HTTPS://mcp.example.com/service",
"headers": {
"Authorization": "Bearer test-token",
},
}
Received:
{
"transport": "stdio",
}Test summary:
4 failedExpected behavior
Transport autodetection should treat URI scheme names case-insensitively.
The following schemes should select the HTTP transport:
http
HTTP
https
HTTPSThe following schemes should select the WebSocket transport:
ws
WS
wss
WSSMixed-case equivalents should behave the same way.
The original connection_url should remain available in the converted configuration, and valid connection_headers should be forwarded.
This follows the URI scheme requirement in RFC 3986 section 3.1:
https://www.rfc-editor.org/rfc/rfc3986.html#section-3.1
Actual behavior
The implementation recognizes only lowercase scheme prefixes.
Each uppercase URL in the reproduction is converted to:
{
"transport": "stdio",
}The converted configuration omits both:
url
headersThe resulting configuration no longer identifies the remote MCP endpoint.
Screenshots
Not applicable. This is a deterministic configuration-conversion reproduction without a browser, model, provider request, or live MCP server.
Desktop (please complete the following information):
- OS: macOS 15.7.3, arm64
- Browser: Not applicable
- GPT Researcher version: 0.14.7
- Revision:
main@6f998577d547b1e54ec662dac63583aa11e3b84b - Python: 3.12.13
- Installation: Source checkout
Smartphone (please complete the following information):
Not applicable.
Additional context
Transport selection currently uses case-sensitive prefix comparisons:
connection_url = config.get(
"connection_url"
)
if connection_url:
if connection_url.startswith(
("wss://", "ws://")
):
server_config["transport"] = (
"websocket"
)
server_config["url"] = connection_url
elif connection_url.startswith(
("https://", "http://")
):
server_config["transport"] = (
"streamable_http"
)
server_config["url"] = connection_url
else:
connection_type = config.get(
"connection_type",
"stdio",
)
server_config["transport"] = (
connection_type
)For an uppercase scheme such as:
HTTPS://mcp.example.com/serviceneither recognized prefix matches. Since no explicit connection_type is present, the fallback assigns:
"transport": "stdio"The URL is not added because the fallback only preserves it for an explicitly selected remote transport:
if connection_type in [
"websocket",
"streamable_http",
"http",
]:
server_config["url"] = connection_urlConnection headers are subsequently forwarded only when the selected transport is remote:
if server_config.get("transport") in [
"streamable_http",
"http",
"websocket",
]:
connection_headers = config.get(
"connection_headers"
)
if (
connection_headers
and isinstance(
connection_headers,
dict,
)
):
server_config["headers"] = (
connection_headers
)Because the uppercase URL was misclassified as stdio, the headers branch is also skipped.
A possible fix is to parse and normalize only the scheme while preserving the original URL:
from urllib.parse import urlsplit
connection_url = config.get(
"connection_url"
)
if connection_url:
scheme = urlsplit(
connection_url
).scheme.lower()
if scheme in {"ws", "wss"}:
server_config["transport"] = (
"websocket"
)
server_config["url"] = connection_url
elif scheme in {"http", "https"}:
server_config["transport"] = (
"streamable_http"
)
server_config["url"] = connection_urlRegression coverage should include:
- lowercase
http,https,ws, andwss; - uppercase versions of all four schemes;
- mixed-case scheme names;
- preservation of the original URL;
- preservation of connection headers;
- explicit remote
connection_typefallback; - unknown URL schemes;
- local stdio configurations without a URL.
Targeted issue and pull-request searches found no existing report for this case-sensitive transport-autodetection root.
Source: assafelovic/gpt-researcher