bytedance/deer-flow · error · HTTPException

Failed to update MCP server state: {str(e)}

Error message

Failed to update MCP server state: {str(e)}

What it means

500 raised when the single-server enable/disable path (_apply_mcp_server_state_update) fails unexpectedly after the 404 checks passed — e.g. JSON parse/write errors on extensions_config.json, validation failures when re-validating the enabled server through McpServerConfigResponse/_validate_mcp_update_request, or reload errors. Unlike the full-update path, the detail carries str(e) and the log names the server involved.

Source

Thrown at backend/app/gateway/routers/mcp.py:970

    "/mcp/config",
    response_model=McpConfigResponse,
    summary="Update MCP Server State",
    description="Enable or disable one MCP server without replacing the full extensions configuration.",
)
async def update_mcp_server_state(request: Request, body: McpServerStateUpdateRequest) -> McpConfigResponse:
    """Enable or disable one MCP server and reload the MCP tool cache."""
    try:
        await require_admin_user(request, detail=_ADMIN_REQUIRED_DETAIL)
        reloaded_servers = await asyncio.to_thread(_apply_mcp_server_state_update, body)

        servers = {name: _mask_server_config(McpServerConfigResponse(**server.model_dump())) for name, server in reloaded_servers.items()}
        reset_mcp_tools_cache()
        return McpConfigResponse(mcp_servers=servers)
    except HTTPException:
        raise
    except Exception as e:
        logger.error("Failed to update MCP server %s state: %s", body.server_name, e, exc_info=True)
        raise HTTPException(status_code=500, detail=f"Failed to update MCP server state: {str(e)}")

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Check the Gateway log 'Failed to update MCP server <name> state' for the underlying exception
  2. If validation of the stored entry failed, update that server's definition (command/args/env) to pass current validation before enabling it
  3. Confirm the config file and its directory are writable by the Gateway process
  4. Retry after resolving; PATCH is serialized under extensions_config_write_lock so a retry is safe

Example fix

# before: stored server {"command": "/opt/srv/run.sh"} -> enable -> 500 (validation fails)
# after: PUT corrected definition first
{"my-server": {"type": "stdio", "command": "uvx", "args": ["my-server"]}}
# then PATCH {"server_name": "my-server", "enabled": true}
Defensive patterns

Strategy: try-catch

Validate before calling

const cfg = await getMcpConfig(); const srv = cfg.mcp_servers[body.server_name]; if (!srv) throw new Error('unknown server'); if ((srv.type ?? 'stdio') === 'stdio' && srv.command === '***') throw new Error('masked command in stored config; fix definition via PUT before enabling');

Type guard

null

Try / catch

try { await patchMcpState(name, enabled); } catch (e) { if (e.status === 500) { console.error(`enable/disable of ${name} failed:`, e.detail); /* check log, repair stored definition via PUT, retry PATCH once */ } throw e; }

Prevention

When it happens

Trigger: PATCH /api/mcp/config enabling a server whose stored raw JSON fails stdio allowlist validation; config file becomes unwritable (permissions, read-only mount); malformed JSON introduced by an external editor between the read and write inside the lock.

Common situations: Enabling a legacy server entry that predates the stdio command allowlist rules; containerized Gateway with a read-only config mount; operators hand-editing config while the API is being used.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/a37f1c30abe58801. Report an issue: GitHub.