odysseus-dev/odysseus · error · HTTPException
url is required for SSE transport
Error message
url is required for SSE transport
What it means
The admin MCP server registration endpoint rejects transport="sse" configurations that omit url. SSE servers connect to a remote HTTP endpoint that streams events, so the URL is the connection target and is mandatory before any connect attempt.
Source
Thrown at routes/mcp/mcp_routes.py:180
transport: str = Form("stdio"),
command: str = Form(None),
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:View on GitHub (pinned to f9235ebbf1)
Solutions
- Include url="https://host.example/sse" as a form field when transport="sse".
- Verify the field is literally named 'url' and sent as form data, not JSON.
- If the server is local-stdio, use transport="stdio" with a command instead.
Example fix
# before
data = {"transport": "sse"}
# after
data = {"transport": "sse", "url": "https://mcp.example.com/sse"} Defensive patterns
Strategy: validation
Validate before calling
def sse_config_valid(data: dict) -> bool:
return data.get("transport") != "sse" or bool(data.get("url")) Try / catch
Treat as a client bug: catch the 400, log the payload, fix the url field — no retry.
Prevention
- Name the field exactly 'url'.
- Validate url parses as https:// before submitting.
When it happens
Trigger: POST with transport="sse" and url empty/omitted; typo'd form field name (e.g. "endpoint" instead of "url"); JSON body sent to the Form()-based endpoint so url arrives as None.
Common situations: Switching a server entry from stdio to SSE and leaving the command field but no url; form-binding bug that drops the url input; copy-pasting a config where the field is named uri/endpoint.
Related errors
- url is required for HTTP transport
- Email account not found for selector {account!r}. Available
- command is required for stdio transport
- disabled must be a list of tool names
- Server has no OAuth config
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/9e5e1e5fe9a0aab0.
Report an issue: GitHub.