HKUDS/DeepTutor · error · UserMcpError
mcp.no_transport
mcp.no_transport
Error message
Provide an http(s) URL for the server
What it means
After excluding stdio, the user-configured server's transport must be one of the remote types 'sse' or 'streamableHttp'. Any other resolved transport (or an empty/unrecognized type) means no usable remote URL was supplied, so the config is rejected.
Source
Thrown at deeptutor/services/mcp/user_config.py:185
*,
validate_url: bool = False,
) -> None:
if not _SERVER_NAME_RE.match(name):
raise UserMcpError("mcp.invalid_name", f"Invalid server name {name!r}")
if name.startswith(_RESERVED_NAME_PREFIXES):
raise UserMcpError(
"mcp.name_reserved",
f"{name!r} starts with a reserved tool-name prefix",
)
transport = cfg.resolved_type()
if transport == "stdio" or cfg.command:
raise UserMcpError(
"mcp.stdio_not_allowed",
"A server you configure yourself must be a remote URL: a stdio "
"server runs a command on the host and stays administrator-only.",
)
if transport not in ("sse", "streamableHttp"):
raise UserMcpError("mcp.no_transport", "Provide an http(s) URL for the server")
if validate_url:
ok, error = validate_mcp_url(cfg.url, strict=True)
if not ok:
raise UserMcpError("mcp.blocked_url", error)
def _read_raw(owner_id: str) -> MCPConfig:
"""The file as stored, *without* the connectability filtering.
Writes must preserve entries this deployment refuses to connect (a stdio
entry left over from a hand edit), or saving one server would silently
delete another.
"""
path = user_mcp_path(owner_id)
if not path.exists():
return MCPConfig()
try:
return MCPConfig.model_validate(json.loads(path.read_text(encoding="utf-8")))View on GitHub (pinned to 3e82f13042)
Solutions
- Set type explicitly to 'sse' or 'streamableHttp' (most modern servers use streamableHttp)
- Provide a proper http(s) URL so the transport can be inferred correctly
- Validate the config against the current MCP config schema after upgrading DeepTutor
Example fix
# before cfg = McpServerConfig(url="https://mcp.example.com/mcp", type="http") # after cfg = McpServerConfig(url="https://mcp.example.com/mcp", type="streamableHttp")
Defensive patterns
Strategy: validation
Validate before calling
ALLOWED_TRANSPORTS = {"sse", "streamableHttp"}
def has_valid_transport(cfg) -> bool:
return cfg.resolved_type() in ALLOWED_TRANSPORTS Try / catch
try:
await save_user_server(user_id, name, cfg)
except UserMcpError as e:
if e.code == "mcp.no_transport":
cfg.type = "streamableHttp" # sensible default for http(s) URLs
await save_user_server(user_id, name, cfg)
else:
raise Prevention
- Always set type explicitly when constructing server configs
- Restrict the transport field in forms to a dropdown of sse/streamableHttp
When it happens
Trigger: Saving or loading a user MCP server whose resolved_type() returns something other than 'stdio' but also not 'sse' or 'streamableHttp' — e.g. type is None, misspelled ('http' instead of 'streamableHttp'), or unset with no URL to infer from.
Common situations: Omitting the type field and the URL inference logic can't classify it; typos in the transport field like 'streamable_http' or 'HTTP'; schema drift after upgrading the config format.
Related errors
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/9dafce540b4c8bb7.
Report an issue: GitHub.