{"record":{"id":"a5d376ffb16e23fc","repo":"unslothai/unsloth","slug":"local-commands-aren-t-enabled-on-this-server-to-a","errorCode":null,"errorMessage":"Local commands aren't enabled on this server. To allow them, set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 and restart Unsloth, or use an http:// or https:// URL instead.","messagePattern":"Local commands aren't enabled on this server\\. To allow them, set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 and restart Unsloth, or use an http:// or https:// URL instead\\.","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"studio/backend/routes/mcp_servers.py","lineNumber":103,"sourceCode":"                status_code = 400,\n                detail = \"Enter an http(s):// URL, or a local command whose \"\n                \"first token is an executable (not a URL).\",\n            )\n        return trimmed\n    parsed = urlparse(trimmed)\n    if parsed.scheme not in (\"http\", \"https\"):\n        if _looks_like_command(trimmed):\n            detail = (\n                \"Local commands aren't enabled on this server. To allow them, \"\n                \"set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 and restart Unsloth, or use \"\n                \"an http:// or https:// URL instead.\"\n            )\n        else:\n            detail = (\n                \"MCP server address must start with http:// or https:// \"\n                \"(for example https://example.com/mcp).\"\n            )\n        raise HTTPException(status_code = 400, detail = detail)\n    if not parsed.netloc:\n        raise HTTPException(status_code = 400, detail = \"url is missing a host\")\n    return trimmed\n\n\ndef _normalize_headers(headers: dict[str, str] | None) -> dict[str, str] | None:\n    \"\"\"Trim header names, drop empties, coerce values to str; None if empty.\"\"\"\n    if not headers:\n        return None\n    out: dict[str, str] = {}\n    for raw_key, value in headers.items():\n        key = str(raw_key).strip()\n        if key:\n            out[key] = str(value)\n    return out or None\n\n\ndef _row_to_response(row: dict) -> McpServerResponse:","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/mcp_servers.py#L85-L121","documentation":"400 raised when the value is not an http(s) URL (scheme check failed) and it contains whitespace — the one-way signal that it's a local command — but stdio MCP is disabled on this server. stdio_mcp_enabled() gates local commands behind UNSLOTH_STUDIO_ALLOW_STDIO_MCP (auto-on for loopback binds, off for 0.0.0.0/Colab), because a stdio MCP server executes a process as the backend user, bypassing the sandbox.","triggerScenarios":"Creating/updating an MCP server with a command like 'npx -y @modelcontextprotocol/server-filesystem /tmp' while the backend is bound to 0.0.0.0, running in Colab, or with UNSLOTH_STUDIO_ALLOW_STDIO_MCP=0/unset.","commonSituations":"Deploying Unsloth Studio on a LAN/remote host (where the loopback auto-default doesn't apply) and re-using an MCP command config that worked locally; or hard-disabling tools with --disable-tools.","solutions":["Use an http(s):// MCP server URL instead — commands are intentionally blocked on network-exposed hosts.","If this is your own machine and you accept local code execution, set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 in the backend environment and restart Unsloth.","Check the bind/host policy: on loopback the flag defaults to 1, so a 403/400 here usually means a network bind or an explicit --disable-tools."],"exampleFix":"# before (backend bound to 0.0.0.0)\nclient.post('/api/mcp-servers/', json={'url': 'npx -y @modelcontextprotocol/server-memory'})\n# 400: local commands aren't enabled\n\n# after\nclient.post('/api/mcp-servers/', json={'url': 'https://mcp.example.com/sse'})\n# or: start backend with UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 on your own machine","handlingStrategy":"validation","validationCode":"const isUrl = /^https?:\\/\\//i.test(url.trim());\nconst looksLikeCommand = /\\s/.test(url.trim());\nif (!isUrl && looksLikeCommand && !stdioEnabled) throw new Error('Local commands disabled — use an http(s) URL');","typeGuard":"function acceptableMcpUrl(url, stdioEnabled) { const v = url.trim(); return /^https?:\\/\\//i.test(v) || (stdioEnabled && !v.split(/\\s+/)[0].includes('://')); }","tryCatchPattern":null,"preventionTips":["Know the deployment posture: network-bound hosts disable stdio MCP by design.","Keep a remote (http(s)) MCP endpoint as the portable default.","Set UNSLOTH_STUDIO_ALLOW_STDIO_MCP=1 only on your own loopback machine."],"tags":["mcp","stdio","security","http-400","config"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}