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
- 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).
- Or perform the stdio MCP configuration once interactively from the Unsloth UI in a browser session.
- 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
- Never put stdio MCP definitions in API-key-driven configuration payloads.
- Gate MCP config UIs on the auth method before submit.
- Run local MCP tools behind an HTTP endpoint if automation needs them.
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
- Password change required
- Invalid or expired API key
- Directory not allowed
- Invalid or expired token
- Invalid token payload
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/554c983aaba40e5a.
Report an issue: GitHub.