{"record":{"id":"fe2db4b4312504d7","repo":"unslothai/unsloth","slug":"stdio-mcp-servers-are-disabled-on-this-host-fe2db4","errorCode":null,"errorMessage":"stdio MCP servers are disabled on this host","messagePattern":"stdio MCP servers are disabled on this host","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"studio/backend/routes/mcp_servers.py","lineNumber":285,"sourceCode":"    invalidate_tool_cache(server_id)\n    await asyncio.to_thread(close_stdio_sessions, old[\"url\"], parse_server_headers(old))\n\n\n@router.post(\"/{server_id}/refresh\", response_model = McpServerProbeResult)\nasync def refresh_mcp_server_tools(\n    server_id: str,\n    current_subject: str = Depends(get_current_subject),\n    via_api_key: ViaApiKey = False,\n):\n    server = mcp_servers_db.get_server(server_id)\n    if not server:\n        raise HTTPException(status_code = 404, detail = \"MCP server not found\")\n    # Refresh uses the stored address, so re-check the stdio gate here too: a\n    # stdio row from a desktop DB must not spawn on a hosted/network host.\n    if is_stdio(server[\"url\"]):\n        require_ui_session_for_local_commands(via_api_key)\n        if not stdio_mcp_enabled():\n            raise HTTPException(\n                status_code = 400, detail = \"stdio MCP servers are disabled on this host\"\n            )\n\n    use_oauth = bool(server.get(\"use_oauth\"))\n    try:\n        tools = await list_tools_async(\n            url = server[\"url\"],\n            headers = parse_server_headers(server),\n            timeout = probe_timeout(server[\"url\"], use_oauth),\n            use_oauth = use_oauth,\n        )\n    except Exception as exc:  # noqa: BLE001 — surface transport+timeout errors to UI\n        logger.error(\n            \"mcp_servers.refresh_failed\",\n            server_id = server_id,\n            error = str(exc),\n            exc_info = True,\n        )","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/mcp_servers.py#L267-L303","documentation":"Raised as a 400 by the refresh endpoint when the stored server URL is a stdio:// target and stdio_mcp_enabled() reports stdio MCP disabled on the current host. Refresh reuses the stored address, so the endpoint re-applies the stdio gate: a stdio row that came from a desktop database must not be allowed to spawn a local process on a hosted/network host.","triggerScenarios":"POST /api/mcp-servers/{id}/refresh for a server whose url starts with stdio:// while the host has stdio MCP disabled (hosted deployment, or the enabling env/config flag off), or the request arrives via an API key (via_api_key) without a UI session — require_ui_session_for_local_commands is checked first, but the 400 here is the disabled-flag branch.","commonSituations":"Copying a desktop studio DB (with stdio servers configured) to a hosted environment; disabling stdio servers via configuration after they were added; environment flag controlling stdio support not set on a server deployment.","solutions":["Check the host's stdio MCP enablement setting/env flag and enable it if local process spawning is intended and safe on this host.","If you are on a hosted/network host, delete the stdio server entry and re-add it as an HTTP/SSE MCP server instead.","Refresh from a real UI session (not an API key) if the gate also requires an interactive session for local commands.","Confirm is_stdio(url) classification — the URL scheme must genuinely be stdio for this branch to fire."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const servers = await (await fetch('/api/mcp-servers')).json();\nconst srv = servers.find(s => s.id === id);\nif (srv && srv.url.startsWith('stdio://')) {\n  const caps = await (await fetch('/api/mcp-servers/capabilities')).json(); // or host config flag\n  if (!caps.stdioEnabled) throw new Error('stdio MCP disabled on this host — use an HTTP MCP server');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await refreshMcpServer(id);\n} catch (e) {\n  if (e.status === 400 && /stdio.*disabled/.test(e.detail)) markServerUnavailable(id);\n  else throw e;\n}","preventionTips":["On hosted deployments, register stdio servers as HTTP/SSE endpoints instead.","Never copy a desktop studio DB with stdio rows onto a hosted host.","Surface the stdio-enabled flag in the UI so users see the limitation before adding stdio servers."],"tags":["mcp","stdio","hosting","configuration","security"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}