Computer Manager & Computer

November 14, 2025 ยท View on GitHub

The Computer Manager orchestrates multiple Computer instances, each representing an isolated execution namespace with dedicated MCP servers and tools. This enables context-specific tool routing and fine-grained control over data collection vs. action execution.


Overview

The Computer layer consists of two components working together:

  • ComputerManager: High-level orchestrator managing multiple Computer instances
  • Computer: Individual execution namespace with its own MCP servers and tool registry

Computer Manager Responsibilities

CapabilityDescriptionImplementation
Multi-Computer ManagementCreate and manage multiple Computer instancesPer-process, per-agent namespaces
Namespace IsolationSeparate tool namespaces for different contextsIndependent MCP servers per Computer
Command RoutingRoute commands to appropriate Computer instancesCommandRouter resolves by agent/process/root
MCP Server ConfigurationConfigure data collection and action serversConfig-driven server initialization
Lifecycle ManagementInitialize, reset, and tear down ComputersAsync initialization, cascading reset

Computer (Instance) Responsibilities

CapabilityDescriptionImplementation
Tool RegistryMaintain registry of available MCP tools_tools_registry dict
Tool ExecutionExecute MCP tool calls with timeout protectionThread pool isolation (max 10 workers)
Server ManagementManage data collection and action MCP serversSeparate namespaces
Meta ToolsProvide built-in tools (list_tools, etc.)Decorated meta tool methods
Async InitializationInitialize MCP servers asynchronouslyasync_init()

Architectural Relationship:

graph TB
    subgraph "Computer Manager Layer"
        CM[Computer Manager]
        CR[Command Router]
    end
    
    subgraph "Computer Instances"
        C1[Computer: default]
        C2[Computer: notepad.exe]
        C3[Computer: explorer.exe]
    end
    
    subgraph "Computer 1 Components"
        C1 --> DC1[Data Collection Servers]
        C1 --> AS1[Action Servers]
        C1 --> TR1[Tool Registry]
        C1 --> MT1[Meta Tools]
    end
    
    CM -->|manages| C1
    CM -->|manages| C2
    CM -->|manages| C3
    CR -->|routes to| C1
    CR -->|routes to| C2
    CR -->|routes to| C3
    
    style CM fill:#ffe0b2
    style C1 fill:#bbdefb
    style C2 fill:#bbdefb
    style C3 fill:#bbdefb

๐Ÿ—๏ธ Computer Manager Architecture

Computer Instance Management

graph LR
    subgraph "ComputerManager"
        Config[UFO Config]
        Registry[Computer Registry]
    end
    
    subgraph "Computers"
        Default[default_agent]
        Proc1[notepad.exe]
        Proc2[explorer.exe]
    end
    
    Config -->|creates| Default
    Config -->|creates| Proc1
    Config -->|creates| Proc2
    
    Registry -->|tracks| Default
    Registry -->|tracks| Proc1
    Registry -->|tracks| Proc2
    
    style Config fill:#fff3e0
    style Registry fill:#e1f5fe

Computer Namespaces:

Namespace TypePurposeExample
Data CollectionGathering information, non-invasive queriesScreenshots, UI element detection, app state
ActionPerforming actions, invasive operationsGUI automation, file operations, app control

Data collection tools are designed for non-invasive information gathering, while action tools have full control for state-changing operations.


Computer Manager Architecture

๐Ÿ–ฅ๏ธ Computer (Instance) Architecture

Internal Structure

graph TB
    subgraph "Computer Instance"
        Init[Initialization]
        Servers[MCP Servers]
        Registry[Tool Registry]
        Execution[Tool Execution]
    end
    
    subgraph "MCP Servers"
        Servers --> DC[Data Collection Servers]
        Servers --> AS[Action Servers]
    end
    
    subgraph "Tool Registry"
        Registry --> TR[_tools_registry Dict]
        TR -->|key: action::click| T1[MCPToolCall]
        TR -->|key: data_collection::screenshot| T2[MCPToolCall]
        TR -->|key: action::list_tools| T3[Meta Tool]
    end
    
    subgraph "Execution Engine"
        Execution --> TP[Thread Pool Executor]
        Execution --> TO[Timeout Protection]
        TP -->|max 10 workers| Threads[Isolated Threads]
    end
    
    Init --> Servers
    Servers --> Registry
    Registry --> Execution
    
    style Init fill:#c8e6c9
    style Servers fill:#bbdefb
    style Registry fill:#fff9c4
    style Execution fill:#ffccbc

Key Attributes:

AttributeTypePurpose
_namestrComputer name (identifier)
_process_namestrAssociated process (e.g., "notepad.exe")
_data_collection_serversDict[str, BaseMCPServer]Namespace โ†’ MCP server mapping (data collection)
_action_serversDict[str, BaseMCPServer]Namespace โ†’ MCP server mapping (actions)
_tools_registryDict[str, MCPToolCall]Tool key โ†’ tool info mapping
_meta_toolsDict[str, Callable]Built-in meta tools
_executorThreadPoolExecutorThread pool for tool execution (10 workers)
_tool_timeoutintTool execution timeout: 6000 seconds (100 minutes)

Note: The tool execution timeout is 6000 seconds (100 minutes), allowing for very long-running operations while preventing indefinite hangs.


Initialization

Computer Manager Initialization

Creating Computer Manager:

from ufo.client.computer import ComputerManager
from ufo.client.mcp.mcp_server_manager import MCPServerManager
from config.config_loader import get_ufo_config

# 1. Get UFO configuration
ufo_config = get_ufo_config()

# 2. Initialize MCP server manager
mcp_server_manager = MCPServerManager()

# 3. Create computer manager
computer_manager = ComputerManager(
    ufo_config.to_dict(),
    mcp_server_manager
)

Computer Instance Initialization

Computer Async Initialization:

computer = Computer(
    name="default_agent",
    process_name="explorer.exe",
    mcp_server_manager=mcp_server_manager,
    data_collection_servers_config=[...],
    action_servers_config=[...]
)

# Async initialization (required)
await computer.async_init()

Initialization Flow:

sequenceDiagram
    participant Code
    participant Computer
    participant MCP as MCP Server Manager
    participant Servers
    
    Code->>Computer: __init__(name, process, configs)
    Computer->>Computer: Create thread pool executor
    Computer->>Computer: Register meta tools
    
    Code->>Computer: async_init()
    Computer->>Computer: _init_data_collection_servers()
    Computer->>MCP: create_or_get_server(config)
    MCP-->>Computer: BaseMCPServer
    
    Computer->>Computer: _init_action_servers()
    Computer->>MCP: create_or_get_server(config)
    MCP-->>Computer: BaseMCPServer
    
    par Register Data Collection Servers
        Computer->>Servers: register_mcp_servers(data_collection)
    and Register Action Servers
        Computer->>Servers: register_mcp_servers(action)
    end
    
    Servers-->>Computer: Tools registered

Configuration Example:

data_collection_servers:
  - namespace: screenshot_collector
    type: local
    module: ufo.client.mcp.local_servers.screenshot_server
    reset: false
  - namespace: ui_collector
    type: local
    module: ufo.client.mcp.local_servers.ui_server
    reset: false

action_servers:
  - namespace: gui_automator
    type: local
    module: ufo.client.mcp.local_servers.automation_server
    reset: false

๐Ÿ”€ Command Routing

CommandRouter

The CommandRouter resolves which Computer instance should handle each command based on agent/process/root context.

Routing Signature:

async def execute(
    self,
    agent_name: str,
    process_name: str,
    root_name: str,
    commands: List[Command]
) -> List[Result]

Routing Logic:

graph TD
    Start[Command List]
    Start --> Resolve[Resolve Computer Instance]
    Resolve -->|agent_name, process_name, root_name| Computer[Get/Create Computer]
    
    Computer --> Loop[For Each Command]
    Loop --> Parse[Parse Command to MCPToolCall]
    Parse --> Lookup[Lookup Tool in Registry]
    
    Lookup -->|Found| Execute[Execute Tool]
    Lookup -->|Not Found| Error[Return Error Result]
    
    Execute --> Timeout[Tool Execution with Timeout]
    Timeout -->|Success| Result[Return Result]
    Timeout -->|Timeout| TimeoutError[Timeout Error Result]
    Timeout -->|Exception| ExecError[Execution Error Result]
    
    Result --> Collect[Collect Results]
    Error --> Collect
    TimeoutError --> Collect
    ExecError --> Collect
    
    Collect --> Return[Return List[Result]]
    
    style Start fill:#e1f5fe
    style Computer fill:#bbdefb
    style Execute fill:#c8e6c9
    style Collect fill:#fff9c4

๐Ÿ”ง Tool Execution

Tool Execution Pipeline

MCP tools are executed in isolated threads to prevent blocking operations (like time.sleep) from blocking the main event loop and causing WebSocket disconnections.

Execution Flow:

sequenceDiagram
    participant Computer
    participant TP as Thread Pool
    participant Thread
    participant Loop as New Event Loop
    participant MCP as MCP Server
    
    Computer->>Computer: _run_action(tool_call)
    Computer->>Computer: Lookup tool in registry
    
    alt Meta Tool
        Computer->>Computer: Execute meta tool directly
        Computer-->>Computer: Result
    else MCP Tool
        Computer->>TP: Submit _call_tool_in_thread()
        TP->>Thread: Execute in thread
        Thread->>Loop: Create new event loop
        Loop->>MCP: client.call_tool(name, params)
        
        alt Success (within timeout)
            MCP-->>Loop: Result
            Loop-->>Thread: Result
            Thread-->>TP: Result
            TP-->>Computer: CallToolResult
        else Timeout (> 6000s)
            Note over Computer,MCP: Tool execution timeout
            Computer-->>Computer: TimeoutError Result
        else Exception
            Note over Computer,MCP: Tool execution failed
            Computer-->>Computer: Error Result
        end
    end

Thread Pool Configuration:

ParameterValuePurpose
max_workers10Maximum concurrent tool executions
thread_name_prefix"mcp_tool_"Thread naming for debugging
Timeout6000 seconds (100 minutes)Per-tool execution timeout

Code Implementation:

def _call_tool_in_thread():
    """
    Execute MCP tool call in an isolated thread with its own event loop.
    This prevents blocking operations in MCP tools from blocking the main event loop.
    """
    # Create a new event loop for this thread
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        async def _do_call():
            async with Client(server) as client:
                return await client.call_tool(
                    name=tool_name, arguments=params, raise_on_error=False
                )
        return loop.run_until_complete(_do_call())
    finally:
        loop.close()

# Execute in thread pool with timeout protection
result = await asyncio.wait_for(
    loop.run_in_executor(self._executor, _call_tool_in_thread),
    timeout=self._tool_timeout
)

๐Ÿ› ๏ธ Tool Registry

Tool Registration

Tools are discovered from MCP servers during initialization and registered with unique keys.

Tool Key Format:

<tool_type>::<tool_name>

Examples:
- action::click
- action::type_text
- data_collection::screenshot
- data_collection::get_ui_elements

Registration Process:

async def register_one_mcp_server(
    self, namespace: str, tool_type: str, mcp_server: BaseMCPServer
) -> None:
    async with Client(mcp_server.server) as client:
        tools = await client.list_tools()
        
        for tool in tools:
            tool_key = self.make_tool_key(tool_type, tool.name)
            
            self._register_tool(
                tool_key=tool_key,
                tool_name=tool.name,
                title=tool.title,
                namespace=namespace,
                tool_type=tool_type,
                description=tool.description,
                input_schema=tool.inputSchema,
                output_schema=tool.outputSchema,
                mcp_server=mcp_server
            )

MCPToolCall Structure:

FieldTypeDescription
tool_keystrUnique key (e.g., "action::click")
tool_namestrTool name (e.g., "click")
titlestrDisplay title
namespacestrServer namespace
tool_typestr"action" or "data_collection"
descriptionstrTool description
input_schemaDictInput parameters schema
output_schemaDictOutput schema
mcp_serverBaseMCPServerReference to server

Meta Tools

Meta tools are built-in methods decorated with @meta_tool that provide computer-level operations.

Example: list_tools Meta Tool

@Computer.meta_tool("list_tools")
async def list_tools(
    self,
    tool_type: Optional[str] = None,
    namespace: Optional[str] = None,
    remove_meta: bool = True
) -> CallToolResult:
    """
    Get available tools of a specific type.
    """
    tools = []
    
    for tool in self._tools_registry.values():
        if ((tool_type is None or tool.tool_type == tool_type)
            and (namespace is None or tool.namespace == namespace)
            and (not remove_meta or tool.tool_name not in self._meta_tools)):
            tools.append(tool.tool_info.model_dump())
    
    return CallToolResult(
        content=[TextContent(type="text", text=json.dumps(tools))]
    )

Meta Tool Registration:

# In __init__:
for attr in dir(self):
    method = getattr(self, attr)
    if callable(method) and hasattr(method, "_meta_tool_name"):
        name = getattr(method, "_meta_tool_name")
        self._meta_tools[name] = method

๐Ÿ”„ Lifecycle Management

Reset

# Computer Manager reset (cascades to all computers)
computer_manager.reset()

# Computer instance reset
computer.reset()

Reset Operations:

ComponentReset Action
Computer ManagerReset all Computer instances
ComputerClear tool registry, reset MCP servers
MCP ServersReset server state

Best Practices

Monitor Tool Execution Times

import time
start = time.time()
result = await computer._run_action(tool_call)
duration = time.time() - start
if duration > 300:  # 5 minutes
    logger.warning(f"Slow tool: {tool_call.tool_name} took {duration}s")

Handle Timeouts Gracefully

# 100-minute timeout is generous but not infinite
# Design tools to complete within reasonable time

Use Namespace Isolation

# Separate data collection from actions
data_tools = await computer.list_tools(tool_type="data_collection")
action_tools = await computer.list_tools(tool_type="action")

๐Ÿš€ Next Steps

๐Ÿ‘‰ Device Info Provider - System profiling
๐Ÿ‘‰ MCP Integration - MCP server details
๐Ÿ‘‰ UFO Client - Execution orchestration
๐Ÿ‘‰ Quick Start - Get started with client
๐Ÿ‘‰ Configuration - UFO configuration