odysseus-dev/odysseus · error · HTTPException

url is required for HTTP transport

Error message

url is required for HTTP transport

What it means

Same registration endpoint as the SSE check: transport="http" (streamable HTTP transport) requires a url. The validation runs after require_admin, so it also implies you are authenticated as an admin; a missing url yields 400 before the server record is created.

Source

Thrown at routes/mcp/mcp_routes.py:182

        args: str = Form("[]"),
        env: str = Form("{}"),
        url: str = Form(None),
        oauth_file: str = Form(None),
        oauth_config: str = Form(None),
    ):
        """Add a new MCP server config and attempt connection. Admin-only:
        registering a stdio server is equivalent to executing arbitrary
        binaries on the host."""
        require_admin(request)
        server_id = str(uuid.uuid4())[:8]

        # Validate
        if transport == "stdio" and not command:
            raise HTTPException(400, "command is required for stdio transport")
        if transport == "sse" and not url:
            raise HTTPException(400, "url is required for SSE transport")
        if transport == "http" and not url:
            raise HTTPException(400, "url is required for HTTP transport")

        # Parse JSON fields
        try:
            parsed_args = json.loads(args) if args else []
        except json.JSONDecodeError:
            parsed_args = []
        try:
            parsed_env = json.loads(env) if env else {}
        except json.JSONDecodeError:
            parsed_env = {}
        if not isinstance(parsed_env, dict):
            parsed_env = {}

        # Parse OAuth config
        parsed_oauth_config = None
        if oauth_config:
            try:
                parsed_oauth_config = _sanitize_mcp_oauth_config(json.loads(oauth_config))

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Send url as a form field, e.g. url="https://mcp.example.com/mcp" with transport="http".
  2. Double-check the form field name is exactly 'url' and the request is multipart/form-data or application/x-www-form-urlencoded.
  3. Test the URL with curl first — a reachable endpoint avoids a follow-up connect failure after registration.

Example fix

# before
data = {"transport": "http"}

# after
data = {"transport": "http", "url": "https://mcp.example.com/mcp"}
Defensive patterns

Strategy: validation

Validate before calling

def http_config_valid(data: dict) -> bool:
    return data.get("transport") != "http" or bool(data.get("url"))

Try / catch

Catch the 400 and correct the form payload; the endpoint is transactional — no partial server is created.

Prevention

When it happens

Trigger: POST with transport="http" and no url form field; url present but empty string; sending the url in a JSON body while the endpoint expects Form fields.

Common situations: Newer streamable-HTTP MCP server registered with the wrong field name; client switched transport dropdown to http without filling the endpoint; env-specific URL not templated into the request.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/cec5147b0f5cfacd. Report an issue: GitHub.