unslothai/unsloth · error · HTTPException

Local (stdio) MCP servers can only be configured from the Un

Error message

Local (stdio) MCP servers can only be configured from the Unsloth UI, not with an API key. Use an http:// or https:// MCP server instead.

What it means

HTTP 403 raised by require_ui_session_for_local_commands when a request authenticated with an sk-unsloth API key tries to configure a local (stdio) MCP server. stdio MCP executes an arbitrary command on the host as the backend user, outside the python/terminal sandbox, so the backend restricts that capability to interactive UI sessions; API-key callers may only register http:// or https:// MCP endpoints.

Source

Thrown at studio/backend/auth/authentication.py:197

    credentials: HTTPAuthorizationCredentials = Depends(security),
) -> bool:
    """True when the caller used an sk-unsloth API key, not a UI session JWT.

    Lets routes treat programmatic API callers differently from the Unsloth UI
    (e.g. refuse a teardown the UI would allow).
    """
    return bool(credentials and credentials.credentials.startswith(API_KEY_PREFIX))


def require_ui_session_for_local_commands(via_api_key: bool) -> None:
    """Refuse an sk-unsloth API key that asks to define a local (stdio) MCP command.

    stdio MCP runs a command on this host as the backend user, outside the
    python/terminal sandbox, so only a UI session may choose what runs. API keys
    keep http(s) MCP, and stdio servers the owner already configured.
    """
    if via_api_key:
        raise HTTPException(
            status_code = status.HTTP_403_FORBIDDEN,
            detail = "Local (stdio) MCP servers can only be configured from the Unsloth UI, "
            "not with an API key. Use an http:// or https:// MCP server instead.",
        )


async def allow_ambient_hf_token(via_api_key: bool = Depends(authenticated_via_api_key)) -> bool:
    """Whether a download this caller starts may fall back to the backend's own HF_TOKEN.

    A UI session already gets the saved token from Settings, so the ambient one grants it
    nothing new. ``require_ui_session`` refuses an sk-unsloth API key that same token, so it
    must not reach private repos by naming one in a download instead; it sends its own token
    in ``X-Unsloth-HF-Token``.
    """
    return not via_api_key


async def authenticated_via_desktop_jwt(

View on GitHub (pinned to 203007d190)

Solutions

  1. Replace the stdio MCP server with an http:// or https:// MCP endpoint when authenticating via API key (e.g. run the local server yourself and expose it over HTTP).
  2. Or perform the stdio MCP configuration once interactively from the Unsloth UI in a browser session.
  3. If you own the local tool, front it with a small HTTP MCP adapter and point the API-key config at that URL.

Example fix

# before
mcp_providers=[{"provider_type": "stdio", "command": "my-mcp", "args": []}]  # via sk-unsloth key

# after
mcp_providers=[{"provider_type": "http", "url": "http://127.0.0.1:8000/mcp"}]  # or configure stdio in the UI
Defensive patterns

Strategy: validation

Validate before calling

def assert_mcp_config_allowed(providers, via_api_key):
    if via_api_key and any(p.get('provider_type') == 'stdio' for p in providers):
        raise ValueError('configure stdio MCP from the UI, or use http(s) MCP with API keys')

Type guard

def is_remote_mcp_only(providers: list[dict]) -> bool:
    return all(p.get('provider_type') in ('http', 'https', 'sse', 'streamable_http') for p in providers)

Try / catch

try:
    save_mcp_providers(providers)
except HTTPException as e:
    if e.status_code == 403 and 'stdio' in e.detail:
        switch_to_http_mcp_or_use_ui()

Prevention

When it happens

Trigger: POST/PUT to an MCP-provider configuration endpoint with an sk-unsloth-... bearer token whose payload contains a provider of type 'stdio' (a command + args); automating studio configuration via API key and including a local command MCP server.

Common situations: Scripts or CI that provision studio settings with an API key and attempt to register a local MCP wrapper binary; users copying a stdio MCP config (meant for the UI) into an API-driven workflow; misunderstanding that API keys are deliberately scoped away from host command execution.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/554c983aaba40e5a. Report an issue: GitHub.