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

  1. Set type explicitly to 'sse' or 'streamableHttp' (most modern servers use streamableHttp)
  2. Provide a proper http(s) URL so the transport can be inferred correctly
  3. 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

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.