mirror of
https://github.com/trycua/computer.git
synced 2026-05-07 23:51:55 -05:00
Merge pull request #493 from YeIIcw/docs/mcp-server-locally
Add Local Desktop Mode for MCP Server with updated docs
This commit is contained in:
@@ -6,6 +6,67 @@ title: Client Integrations
|
|||||||
|
|
||||||
To use with Claude Desktop, add an entry to your Claude Desktop configuration (`claude_desktop_config.json`, typically found in `~/.config/claude-desktop/`):
|
To use with Claude Desktop, add an entry to your Claude Desktop configuration (`claude_desktop_config.json`, typically found in `~/.config/claude-desktop/`):
|
||||||
|
|
||||||
|
### Package Installation Method
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "anthropic/claude-sonnet-4-20250514",
|
||||||
|
"ANTHROPIC_API_KEY": "your-anthropic-api-key-here",
|
||||||
|
"CUA_MAX_IMAGES": "3",
|
||||||
|
"CUA_USE_HOST_COMPUTER_SERVER": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Method
|
||||||
|
|
||||||
|
If you're working with the CUA source code:
|
||||||
|
|
||||||
|
**Standard VM Mode:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/usr/bin/env",
|
||||||
|
"args": [
|
||||||
|
"bash", "-lc",
|
||||||
|
"export CUA_MODEL_NAME='anthropic/claude-sonnet-4-20250514'; export ANTHROPIC_API_KEY='your-anthropic-api-key-here'; /path/to/cua/libs/python/mcp-server/scripts/start_mcp_server.sh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Host Computer Control Mode:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/usr/bin/env",
|
||||||
|
"args": [
|
||||||
|
"bash", "-lc",
|
||||||
|
"export CUA_MODEL_NAME='anthropic/claude-sonnet-4-20250514'; export ANTHROPIC_API_KEY='your-anthropic-api-key-here'; export CUA_USE_HOST_COMPUTER_SERVER='true'; export CUA_MAX_IMAGES='1'; /path/to/cua/libs/python/mcp-server/scripts/start_mcp_server.sh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Replace `/path/to/cua` with the absolute path to your CUA repository directory.
|
||||||
|
|
||||||
|
**⚠️ Host Computer Control Setup**: When using `CUA_USE_HOST_COMPUTER_SERVER='true'`, you must also:
|
||||||
|
1. Install computer server dependencies: `python3 -m pip install uvicorn fastapi`
|
||||||
|
2. Install the computer server: `python3 -m pip install -e libs/python/computer-server --break-system-packages`
|
||||||
|
3. Start the computer server: `python -m computer_server --log-level debug`
|
||||||
|
4. The AI will have direct access to your desktop - use with caution!
|
||||||
|
|
||||||
For more information on MCP with Claude Desktop, see the [official MCP User Guide](https://modelcontextprotocol.io/quickstart/user).
|
For more information on MCP with Claude Desktop, see the [official MCP User Guide](https://modelcontextprotocol.io/quickstart/user).
|
||||||
|
|
||||||
## Cursor Integration
|
## Cursor Integration
|
||||||
@@ -15,6 +76,43 @@ To use with Cursor, add an MCP configuration file in one of these locations:
|
|||||||
- **Project-specific**: Create `.cursor/mcp.json` in your project directory
|
- **Project-specific**: Create `.cursor/mcp.json` in your project directory
|
||||||
- **Global**: Create `~/.cursor/mcp.json` in your home directory
|
- **Global**: Create `~/.cursor/mcp.json` in your home directory
|
||||||
|
|
||||||
|
Example configuration for Cursor:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "anthropic/claude-sonnet-4-20250514",
|
||||||
|
"ANTHROPIC_API_KEY": "your-anthropic-api-key-here"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
After configuration, you can simply tell Cursor's Agent to perform computer tasks by explicitly mentioning the CUA agent, such as "Use the computer control tools to open Safari."
|
After configuration, you can simply tell Cursor's Agent to perform computer tasks by explicitly mentioning the CUA agent, such as "Use the computer control tools to open Safari."
|
||||||
|
|
||||||
For more information on MCP with Cursor, see the [official Cursor MCP documentation](https://docs.cursor.com/context/model-context-protocol).
|
For more information on MCP with Cursor, see the [official Cursor MCP documentation](https://docs.cursor.com/context/model-context-protocol).
|
||||||
|
|
||||||
|
## Other MCP Clients
|
||||||
|
|
||||||
|
The MCP server is compatible with any MCP-compliant client. The server exposes the following tools:
|
||||||
|
|
||||||
|
- `run_cua_task` - Execute single computer tasks
|
||||||
|
- `run_multi_cua_tasks` - Execute multiple tasks (sequential or concurrent)
|
||||||
|
- `screenshot_cua` - Capture screenshots
|
||||||
|
- `get_session_stats` - Monitor session statistics
|
||||||
|
- `cleanup_session` - Manage session lifecycle
|
||||||
|
|
||||||
|
### Configuration Options
|
||||||
|
|
||||||
|
All MCP clients can configure the server using environment variables:
|
||||||
|
|
||||||
|
- `CUA_MODEL_NAME` - Model to use for task execution
|
||||||
|
- `CUA_MAX_IMAGES` - Maximum images to keep in context
|
||||||
|
- `CUA_USE_HOST_COMPUTER_SERVER` - Use host system instead of VM
|
||||||
|
|
||||||
|
See the [Configuration](/docs/libraries/mcp-server/configuration) page for detailed configuration options.
|
||||||
|
|||||||
@@ -4,7 +4,66 @@ title: Configuration
|
|||||||
|
|
||||||
The server is configured using environment variables (can be set in the Claude Desktop config):
|
The server is configured using environment variables (can be set in the Claude Desktop config):
|
||||||
|
|
||||||
| Variable | Description | Default |
|
| Variable | Description | Default |
|
||||||
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ |
|
|----------|-------------|---------|
|
||||||
| `CUA_MODEL_NAME` | Model string (e.g., "anthropic/claude-3-5-sonnet-20241022", "openai/computer-use-preview", "huggingface-local/ByteDance-Seed/UI-TARS-1.5-7B", "omniparser+litellm/gpt-4o", "omniparser+ollama_chat/gemma3") | anthropic/claude-3-5-sonnet-20241022 |
|
| `CUA_MODEL_NAME` | Model string (e.g., "anthropic/claude-sonnet-4-20250514", "anthropic/claude-3-5-sonnet-20240620", "openai/computer-use-preview", "huggingface-local/ByteDance-Seed/UI-TARS-1.5-7B", "omniparser+litellm/gpt-4o", "omniparser+ollama_chat/gemma3") | anthropic/claude-sonnet-4-20250514 |
|
||||||
| `CUA_MAX_IMAGES` | Maximum number of images to keep in context | 3 |
|
| `ANTHROPIC_API_KEY` | Your Anthropic API key (required for Anthropic models) | None |
|
||||||
|
| `CUA_MAX_IMAGES` | Maximum number of images to keep in context | 3 |
|
||||||
|
| `CUA_USE_HOST_COMPUTER_SERVER` | Target your local desktop instead of a VM. Set to "true" to use your host system. **Warning:** AI models may perform risky actions. | false |
|
||||||
|
|
||||||
|
## Model Configuration
|
||||||
|
|
||||||
|
The `CUA_MODEL_NAME` environment variable supports various model providers through LiteLLM integration:
|
||||||
|
|
||||||
|
### Supported Providers
|
||||||
|
- **Anthropic**: `anthropic/claude-sonnet-4-20250514`, `anthropic/claude-3-5-sonnet-20240620`, `anthropic/claude-3-haiku-20240307`
|
||||||
|
- **OpenAI**: `openai/computer-use-preview`, `openai/gpt-4o`
|
||||||
|
- **Local Models**: `huggingface-local/ByteDance-Seed/UI-TARS-1.5-7B`
|
||||||
|
- **Omni + LiteLLM**: `omniparser+litellm/gpt-4o`, `omniparser+litellm/claude-3-haiku`
|
||||||
|
- **Ollama**: `omniparser+ollama_chat/gemma3`
|
||||||
|
|
||||||
|
### Example Configurations
|
||||||
|
|
||||||
|
**Claude Desktop Configuration:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "anthropic/claude-sonnet-4-20250514",
|
||||||
|
"ANTHROPIC_API_KEY": "your-anthropic-api-key-here",
|
||||||
|
"CUA_MAX_IMAGES": "5",
|
||||||
|
"CUA_USE_HOST_COMPUTER_SERVER": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Local Model Configuration:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "huggingface-local/ByteDance-Seed/UI-TARS-1.5-7B",
|
||||||
|
"CUA_MAX_IMAGES": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Session Management Configuration
|
||||||
|
|
||||||
|
The MCP server automatically manages sessions with the following defaults:
|
||||||
|
- **Max Concurrent Sessions**: 10
|
||||||
|
- **Session Timeout**: 10 minutes of inactivity
|
||||||
|
- **Computer Pool Size**: 5 instances
|
||||||
|
- **Automatic Cleanup**: Enabled
|
||||||
|
|
||||||
|
These settings are optimized for typical usage and don't require configuration for most users.
|
||||||
|
|||||||
@@ -7,3 +7,21 @@ github:
|
|||||||
---
|
---
|
||||||
|
|
||||||
**cua-mcp-server** is a MCP server for the Computer-Use Agent (CUA), allowing you to run CUA through Claude Desktop or other MCP clients.
|
**cua-mcp-server** is a MCP server for the Computer-Use Agent (CUA), allowing you to run CUA through Claude Desktop or other MCP clients.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Multi-Client Support**: Concurrent sessions with automatic resource management
|
||||||
|
- **Progress Reporting**: Real-time progress updates during task execution
|
||||||
|
- **Error Handling**: Robust error recovery with screenshot capture
|
||||||
|
- **Concurrent Execution**: Run multiple tasks in parallel for improved performance
|
||||||
|
- **Session Management**: Automatic cleanup and resource pooling
|
||||||
|
- **LiteLLM Integration**: Support for multiple model providers
|
||||||
|
- **VM Safety**: Default VM execution with optional host system control
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. **Install**: `pip install cua-mcp-server`
|
||||||
|
2. **Configure**: Add to your MCP client configuration
|
||||||
|
3. **Use**: Ask Claude to perform computer tasks
|
||||||
|
|
||||||
|
See the [Installation](/docs/libraries/mcp-server/installation) guide for detailed setup instructions.
|
||||||
|
|||||||
@@ -38,19 +38,98 @@ You can then use the script in your MCP configuration like this:
|
|||||||
"command": "/bin/bash",
|
"command": "/bin/bash",
|
||||||
"args": ["~/.cua/start_mcp_server.sh"],
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
"env": {
|
"env": {
|
||||||
"CUA_MODEL_NAME": "anthropic/claude-3-5-sonnet-20241022"
|
"CUA_MODEL_NAME": "anthropic/claude-sonnet-4-20250514",
|
||||||
|
"ANTHROPIC_API_KEY": "your-anthropic-api-key-here"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Important**: You must include your Anthropic API key for the MCP server to work properly.
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
If you're working with the CUA source code directly (like in the CUA repository), you can use the development script instead:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/usr/bin/env",
|
||||||
|
"args": [
|
||||||
|
"bash", "-lc",
|
||||||
|
"export CUA_MODEL_NAME='anthropic/claude-sonnet-4-20250514'; export ANTHROPIC_API_KEY='your-anthropic-api-key-here'; /path/to/cua/libs/python/mcp-server/scripts/start_mcp_server.sh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**For host computer control** (development setup):
|
||||||
|
|
||||||
|
1. **Install Computer Server Dependencies**:
|
||||||
|
```bash
|
||||||
|
python3 -m pip install uvicorn fastapi
|
||||||
|
python3 -m pip install -e libs/python/computer-server --break-system-packages
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Start the Computer Server**:
|
||||||
|
```bash
|
||||||
|
cd /path/to/cua
|
||||||
|
python -m computer_server --log-level debug
|
||||||
|
```
|
||||||
|
This will start the computer server on `http://localhost:8000` that controls your actual desktop.
|
||||||
|
|
||||||
|
3. **Configure Claude Desktop**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/usr/bin/env",
|
||||||
|
"args": [
|
||||||
|
"bash", "-lc",
|
||||||
|
"export CUA_MODEL_NAME='anthropic/claude-sonnet-4-20250514'; export ANTHROPIC_API_KEY='your-anthropic-api-key-here'; export CUA_USE_HOST_COMPUTER_SERVER='true'; export CUA_MAX_IMAGES='1'; /path/to/cua/libs/python/mcp-server/scripts/start_mcp_server.sh"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note**: Replace `/path/to/cua` with the absolute path to your CUA repository directory.
|
||||||
|
|
||||||
|
**⚠️ Important**: When using host computer control (`CUA_USE_HOST_COMPUTER_SERVER='true'`), the AI will have direct access to your desktop and can perform actions like opening applications, clicking, typing, and taking screenshots. Make sure you're comfortable with this level of access.
|
||||||
|
|
||||||
### Troubleshooting
|
### Troubleshooting
|
||||||
|
|
||||||
If you get a `/bin/bash: ~/cua/libs/python/mcp-server/scripts/start_mcp_server.sh: No such file or directory` error, try changing the path to the script to be absolute instead of relative.
|
**Common Issues:**
|
||||||
|
|
||||||
To see the logs:
|
1. **"Claude's response was interrupted"** - This usually means:
|
||||||
|
- Missing API key: Add `ANTHROPIC_API_KEY` to your environment variables
|
||||||
|
- Invalid model name: Use a valid model like `anthropic/claude-sonnet-4-20250514`
|
||||||
|
- Check logs for specific error messages
|
||||||
|
|
||||||
```
|
2. **"Missing Anthropic API Key"** - Add your API key to the configuration:
|
||||||
|
```json
|
||||||
|
"env": {
|
||||||
|
"ANTHROPIC_API_KEY": "your-api-key-here"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **"model not found"** - Use a valid model name:
|
||||||
|
- ✅ `anthropic/claude-sonnet-4-20250514`
|
||||||
|
- ✅ `anthropic/claude-3-5-sonnet-20240620`
|
||||||
|
- ❌ `anthropic/claude-3-5-sonnet-20241022` (doesn't exist)
|
||||||
|
|
||||||
|
4. **Script not found** - If you get a `/bin/bash: ~/cua/libs/python/mcp-server/scripts/start_mcp_server.sh: No such file or directory` error, try changing the path to the script to be absolute instead of relative.
|
||||||
|
|
||||||
|
5. **Host Computer Control Issues** - If using `CUA_USE_HOST_COMPUTER_SERVER='true'`:
|
||||||
|
- **Computer Server not running**: Make sure you've started the computer server with `python -m computer_server --log-level debug`
|
||||||
|
- **Port 8000 in use**: Check if another process is using port 8000 with `lsof -i :8000`
|
||||||
|
- **Missing dependencies**: Install `uvicorn` and `fastapi` with `python3 -m pip install uvicorn fastapi`
|
||||||
|
- **Image size errors**: Use `CUA_MAX_IMAGES='1'` to reduce image context size
|
||||||
|
|
||||||
|
**Viewing Logs:**
|
||||||
|
```bash
|
||||||
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
|
tail -n 20 -f ~/Library/Logs/Claude/mcp*.log
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -6,5 +6,58 @@ title: Tools
|
|||||||
|
|
||||||
The MCP server exposes the following tools to Claude:
|
The MCP server exposes the following tools to Claude:
|
||||||
|
|
||||||
1. `run_cua_task` - Run a single Computer-Use Agent task with the given instruction
|
### Core Task Execution Tools
|
||||||
2. `run_multi_cua_tasks` - Run multiple tasks in sequence
|
|
||||||
|
1. **`run_cua_task`** - Run a single Computer-Use Agent task with the given instruction
|
||||||
|
- `task` (string): The task description for the agent to execute
|
||||||
|
- `session_id` (string, optional): Session ID for multi-client support. If not provided, a new session will be created
|
||||||
|
- Returns: Tuple of (combined text output, final screenshot)
|
||||||
|
|
||||||
|
2. **`run_multi_cua_tasks`** - Run multiple tasks in sequence or concurrently
|
||||||
|
- `tasks` (list of strings): List of task descriptions to execute
|
||||||
|
- `session_id` (string, optional): Session ID for multi-client support. If not provided, a new session will be created
|
||||||
|
- `concurrent` (boolean, optional): If true, run tasks concurrently. If false, run sequentially (default)
|
||||||
|
- Returns: List of tuples (combined text output, screenshot) for each task
|
||||||
|
|
||||||
|
### Utility Tools
|
||||||
|
|
||||||
|
3. **`screenshot_cua`** - Take a screenshot of the current screen
|
||||||
|
- `session_id` (string, optional): Session ID for multi-client support. If not provided, a new session will be created
|
||||||
|
- Returns: Screenshot image
|
||||||
|
|
||||||
|
4. **`get_session_stats`** - Get statistics about active sessions and resource usage
|
||||||
|
- Returns: Dictionary with session statistics including total sessions, active tasks, and session details
|
||||||
|
|
||||||
|
5. **`cleanup_session`** - Cleanup a specific session and release its resources
|
||||||
|
- `session_id` (string): The session ID to cleanup
|
||||||
|
- Returns: Confirmation message
|
||||||
|
|
||||||
|
## Session Management
|
||||||
|
|
||||||
|
The MCP server supports multi-client sessions with automatic resource management:
|
||||||
|
|
||||||
|
- **Session Isolation**: Each client can have its own session with isolated computer instances
|
||||||
|
- **Resource Pooling**: Computer instances are pooled for efficient resource usage
|
||||||
|
- **Automatic Cleanup**: Idle sessions are automatically cleaned up after 10 minutes
|
||||||
|
- **Concurrent Tasks**: Multiple tasks can run concurrently within the same session
|
||||||
|
- **Progress Reporting**: Real-time progress updates during task execution
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Basic Task Execution
|
||||||
|
```
|
||||||
|
"Open Chrome and navigate to github.com"
|
||||||
|
"Create a folder called 'Projects' on my desktop"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-Task Execution
|
||||||
|
```
|
||||||
|
"Run these tasks: 1) Open Finder, 2) Navigate to Documents, 3) Create a new folder called 'Work'"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Session Management
|
||||||
|
```
|
||||||
|
"Take a screenshot of the current screen"
|
||||||
|
"Show me the session statistics"
|
||||||
|
"Cleanup session abc123"
|
||||||
|
```
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: Usage
|
title: Usage
|
||||||
---
|
---
|
||||||
|
|
||||||
## Usage
|
## Basic Usage
|
||||||
|
|
||||||
Once configured, you can simply ask Claude to perform computer tasks:
|
Once configured, you can simply ask Claude to perform computer tasks:
|
||||||
|
|
||||||
@@ -13,9 +13,140 @@ Once configured, you can simply ask Claude to perform computer tasks:
|
|||||||
|
|
||||||
Claude will automatically use your CUA agent to perform these tasks.
|
Claude will automatically use your CUA agent to perform these tasks.
|
||||||
|
|
||||||
### First-time Usage Notes
|
## Advanced Features
|
||||||
|
|
||||||
|
### Progress Reporting
|
||||||
|
The MCP server provides real-time progress updates during task execution:
|
||||||
|
- Task progress is reported as percentages (0-100%)
|
||||||
|
- Multi-task operations show progress for each individual task
|
||||||
|
- Progress updates are streamed to the MCP client for real-time feedback
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
Robust error handling ensures reliable operation:
|
||||||
|
- Failed tasks return error messages with screenshots when possible
|
||||||
|
- Session state is preserved even when individual tasks fail
|
||||||
|
- Automatic cleanup prevents resource leaks
|
||||||
|
- Detailed error logging for troubleshooting
|
||||||
|
|
||||||
|
### Concurrent Task Execution
|
||||||
|
For improved performance, multiple tasks can run concurrently:
|
||||||
|
- Set `concurrent=true` in `run_multi_cua_tasks` for parallel execution
|
||||||
|
- Each task runs in its own context with isolated state
|
||||||
|
- Progress tracking works for both sequential and concurrent modes
|
||||||
|
- Resource pooling ensures efficient computer instance usage
|
||||||
|
|
||||||
|
### Session Management
|
||||||
|
Multi-client support with automatic resource management:
|
||||||
|
- Each client gets isolated sessions with separate computer instances
|
||||||
|
- Sessions automatically clean up after 10 minutes of inactivity
|
||||||
|
- Resource pooling prevents resource exhaustion
|
||||||
|
- Session statistics available for monitoring
|
||||||
|
|
||||||
|
## Target Computer Options
|
||||||
|
|
||||||
|
By default, the MCP server runs CUA in a virtual machine for safety. However, you can also configure it to run on your local system.
|
||||||
|
|
||||||
|
### Default: Using a VM (Recommended)
|
||||||
|
|
||||||
|
The MCP server will automatically start and connect to a VM based on your platform. This is the safest option as AI actions are isolated from your host system.
|
||||||
|
|
||||||
|
No additional configuration is needed - this is the default behavior.
|
||||||
|
|
||||||
|
### Option: Targeting Your Local Desktop
|
||||||
|
|
||||||
|
<Callout type="warn">
|
||||||
|
**Warning:** When targeting your local system, AI models have direct access to your desktop and may perform risky actions. Use with caution.
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
To have the MCP server control your local desktop instead of a VM:
|
||||||
|
|
||||||
|
1. **Start the Computer Server on your host:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install cua-computer-server
|
||||||
|
python -m computer_server
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Configure the MCP server to use your host system:**
|
||||||
|
|
||||||
|
Add the `CUA_USE_HOST_COMPUTER_SERVER` environment variable to your MCP client configuration:
|
||||||
|
|
||||||
|
<Tabs items={['Claude Desktop', 'Other MCP Clients']}>
|
||||||
|
<Tab value="Claude Desktop">
|
||||||
|
Update your Claude Desktop config (see [Installation](/docs/libraries/mcp-server/installation)) to include the environment variable:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "anthropic/claude-3-5-sonnet-20241022",
|
||||||
|
"CUA_USE_HOST_COMPUTER_SERVER": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
<Tab value="Other MCP Clients">
|
||||||
|
Set the environment variable in your MCP client configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export CUA_USE_HOST_COMPUTER_SERVER=true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then start your MCP client as usual.
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
3. **Restart your MCP client** (e.g., Claude Desktop) to apply the changes.
|
||||||
|
|
||||||
|
Now Claude will control your local desktop directly when you ask it to perform computer tasks.
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Single Task Execution
|
||||||
|
```
|
||||||
|
"Open Safari and navigate to apple.com"
|
||||||
|
"Create a new folder on the desktop called 'My Projects'"
|
||||||
|
"Take a screenshot of the current screen"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-Task Execution (Sequential)
|
||||||
|
```
|
||||||
|
"Run these tasks in order: 1) Open Finder, 2) Navigate to Documents folder, 3) Create a new folder called 'Work'"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multi-Task Execution (Concurrent)
|
||||||
|
```
|
||||||
|
"Run these tasks simultaneously: 1) Open Chrome, 2) Open Safari, 3) Open Finder"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Session Management
|
||||||
|
```
|
||||||
|
"Show me the current session statistics"
|
||||||
|
"Take a screenshot using session abc123"
|
||||||
|
"Cleanup session xyz789"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Recovery
|
||||||
|
```
|
||||||
|
"Try to open a non-existent application and show me the error"
|
||||||
|
"Find all files with .tmp extension and delete them safely"
|
||||||
|
```
|
||||||
|
|
||||||
|
## First-time Usage Notes
|
||||||
|
|
||||||
**API Keys**: Ensure you have valid API keys:
|
**API Keys**: Ensure you have valid API keys:
|
||||||
|
- Add your Anthropic API key in the Claude Desktop config (as shown above)
|
||||||
|
- Or set it as an environment variable in your shell profile
|
||||||
|
- **Required**: The MCP server needs an API key to authenticate with the model provider
|
||||||
|
|
||||||
- Add your Anthropic API key, or other model provider API key in the Claude Desktop config (as shown above)
|
**Model Selection**: Choose the appropriate model for your needs:
|
||||||
- Or set it as an environment variable in your shell profile
|
- **Claude Sonnet 4**: Latest model with best performance (`anthropic/claude-sonnet-4-20250514`)
|
||||||
|
- **Claude 3.5 Sonnet**: Reliable performance (`anthropic/claude-3-5-sonnet-20240620`)
|
||||||
|
- **Computer-Use Preview**: Specialized for computer tasks (`openai/computer-use-preview`)
|
||||||
|
- **Local Models**: For privacy-sensitive environments
|
||||||
|
- **Ollama**: For offline usage
|
||||||
|
|||||||
@@ -1287,7 +1287,15 @@ class MacOSAutomationHandler(BaseAutomationHandler):
|
|||||||
if not isinstance(screenshot, Image.Image):
|
if not isinstance(screenshot, Image.Image):
|
||||||
return {"success": False, "error": "Failed to capture screenshot"}
|
return {"success": False, "error": "Failed to capture screenshot"}
|
||||||
|
|
||||||
|
# Resize image to reduce size (max width 1920, maintain aspect ratio)
|
||||||
|
max_width = 1920
|
||||||
|
if screenshot.width > max_width:
|
||||||
|
ratio = max_width / screenshot.width
|
||||||
|
new_height = int(screenshot.height * ratio)
|
||||||
|
screenshot = screenshot.resize((max_width, new_height), Image.Resampling.LANCZOS)
|
||||||
|
|
||||||
buffered = BytesIO()
|
buffered = BytesIO()
|
||||||
|
# Use PNG format with optimization to reduce file size
|
||||||
screenshot.save(buffered, format="PNG", optimize=True)
|
screenshot.save(buffered, format="PNG", optimize=True)
|
||||||
buffered.seek(0)
|
buffered.seek(0)
|
||||||
image_data = base64.b64encode(buffered.getvalue()).decode()
|
image_data = base64.b64encode(buffered.getvalue()).decode()
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Quick Test Commands for MCP Server Local Desktop Option
|
||||||
|
# Run these commands to test the implementation
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
echo "======================================================================"
|
||||||
|
echo "Testing MCP Server Local Desktop Option"
|
||||||
|
echo "======================================================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Change to repo root
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Test 1: Quick Logic Test (No setup required)
|
||||||
|
echo "Test 1: Quick Logic Test (No setup required)"
|
||||||
|
echo "----------------------------------------------------------------------"
|
||||||
|
python tests/quick_test_local_option.py
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 2: Automated Tests (Requires pytest and packages)
|
||||||
|
echo "Test 2: Automated Tests (Requires pytest and packages installed)"
|
||||||
|
echo "----------------------------------------------------------------------"
|
||||||
|
if command -v pytest &> /dev/null; then
|
||||||
|
echo "Running pytest..."
|
||||||
|
pytest tests/test_mcp_server_local_option.py -v || echo "Note: Some tests may require full setup"
|
||||||
|
else
|
||||||
|
echo "⚠️ pytest not found. Install with: pip install pytest"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 3: Existing MCP server tests
|
||||||
|
echo "Test 3: Existing MCP Server Tests"
|
||||||
|
echo "----------------------------------------------------------------------"
|
||||||
|
if command -v pytest &> /dev/null; then
|
||||||
|
echo "Running existing session management tests..."
|
||||||
|
pytest tests/test_mcp_server_session_management.py -v || echo "Note: Some tests may fail if dependencies are missing"
|
||||||
|
else
|
||||||
|
echo "⚠️ pytest not found. Install with: pip install pytest"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo "======================================================================"
|
||||||
|
echo "Test Summary"
|
||||||
|
echo "======================================================================"
|
||||||
|
echo "✅ Quick logic test completed"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps for comprehensive testing:"
|
||||||
|
echo "1. Install dependencies:"
|
||||||
|
echo " pip install -e libs/python/core"
|
||||||
|
echo " pip install -e libs/python/computer"
|
||||||
|
echo " pip install -e libs/python/agent"
|
||||||
|
echo " pip install -e libs/python/mcp-server"
|
||||||
|
echo " pip install -e libs/python/computer-server"
|
||||||
|
echo ""
|
||||||
|
echo "2. For manual end-to-end testing, see:"
|
||||||
|
echo " tests/MANUAL_TEST_LOCAL_OPTION.md"
|
||||||
|
echo ""
|
||||||
|
echo "3. For detailed testing info, see:"
|
||||||
|
echo " tests/TESTING_SUMMARY.md"
|
||||||
|
echo ""
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ This module provides:
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
import weakref
|
import weakref
|
||||||
@@ -57,7 +58,14 @@ class ComputerPool:
|
|||||||
logger.debug("Creating new computer instance")
|
logger.debug("Creating new computer instance")
|
||||||
from computer import Computer
|
from computer import Computer
|
||||||
|
|
||||||
computer = Computer(verbosity=logging.INFO)
|
# Check if we should use host computer server
|
||||||
|
use_host = os.getenv("CUA_USE_HOST_COMPUTER_SERVER", "false").lower() in (
|
||||||
|
"true",
|
||||||
|
"1",
|
||||||
|
"yes",
|
||||||
|
)
|
||||||
|
|
||||||
|
computer = Computer(verbosity=logging.INFO, use_host_computer_server=use_host)
|
||||||
await computer.run()
|
await computer.run()
|
||||||
self._in_use.add(computer)
|
self._in_use.add(computer)
|
||||||
return computer
|
return computer
|
||||||
|
|||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Quick test to verify the local desktop option logic without full setup.
|
||||||
|
|
||||||
|
This script tests the environment variable parsing and logic flow
|
||||||
|
without requiring VMs, computer-server, or MCP clients to be running.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_var_parsing():
|
||||||
|
"""Test that environment variable is parsed correctly."""
|
||||||
|
print("Testing CUA_USE_HOST_COMPUTER_SERVER environment variable parsing...")
|
||||||
|
print("-" * 60)
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
# (env_value, expected_result, description)
|
||||||
|
("true", True, "lowercase 'true'"),
|
||||||
|
("True", True, "capitalized 'True'"),
|
||||||
|
("TRUE", True, "uppercase 'TRUE'"),
|
||||||
|
("1", True, "numeric '1'"),
|
||||||
|
("yes", True, "lowercase 'yes'"),
|
||||||
|
("Yes", True, "capitalized 'Yes'"),
|
||||||
|
("false", False, "lowercase 'false'"),
|
||||||
|
("False", False, "capitalized 'False'"),
|
||||||
|
("FALSE", False, "uppercase 'FALSE'"),
|
||||||
|
("0", False, "numeric '0'"),
|
||||||
|
("no", False, "lowercase 'no'"),
|
||||||
|
("", False, "empty string"),
|
||||||
|
("random", False, "random value"),
|
||||||
|
(None, False, "not set (None)"),
|
||||||
|
]
|
||||||
|
|
||||||
|
passed = 0
|
||||||
|
failed = 0
|
||||||
|
|
||||||
|
for env_value, expected, description in test_cases:
|
||||||
|
# Simulate the logic from session_manager.py line 59
|
||||||
|
if env_value is None:
|
||||||
|
actual = os.getenv("CUA_USE_HOST_COMPUTER_SERVER", "false").lower() in (
|
||||||
|
"true",
|
||||||
|
"1",
|
||||||
|
"yes",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
os.environ["CUA_USE_HOST_COMPUTER_SERVER"] = env_value
|
||||||
|
actual = os.getenv("CUA_USE_HOST_COMPUTER_SERVER", "false").lower() in (
|
||||||
|
"true",
|
||||||
|
"1",
|
||||||
|
"yes",
|
||||||
|
)
|
||||||
|
|
||||||
|
status = "✓ PASS" if actual == expected else "✗ FAIL"
|
||||||
|
if actual == expected:
|
||||||
|
passed += 1
|
||||||
|
else:
|
||||||
|
failed += 1
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"{status} | Value: {env_value!r:15} | Expected: {expected!s:5} | Got: {actual!s:5} | {description}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
os.environ.pop("CUA_USE_HOST_COMPUTER_SERVER", None)
|
||||||
|
|
||||||
|
print("-" * 60)
|
||||||
|
print(f"Results: {passed} passed, {failed} failed")
|
||||||
|
return failed == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_session_manager_logic():
|
||||||
|
"""Test the logic flow in session_manager.py without actual Computer creation."""
|
||||||
|
print("\nTesting session_manager.py logic flow...")
|
||||||
|
print("-" * 60)
|
||||||
|
|
||||||
|
# Read the actual session_manager.py to verify the logic
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
session_manager_path = (
|
||||||
|
pathlib.Path(__file__).parent.parent
|
||||||
|
/ "libs"
|
||||||
|
/ "python"
|
||||||
|
/ "mcp-server"
|
||||||
|
/ "mcp_server"
|
||||||
|
/ "session_manager.py"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not session_manager_path.exists():
|
||||||
|
print(f"✗ FAIL | session_manager.py not found at {session_manager_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = session_manager_path.read_text()
|
||||||
|
|
||||||
|
# Check for the key logic
|
||||||
|
checks = [
|
||||||
|
('os.getenv("CUA_USE_HOST_COMPUTER_SERVER"', "Environment variable check present"),
|
||||||
|
("use_host_computer_server=use_host", "use_host_computer_server parameter passed"),
|
||||||
|
("Computer(", "Computer instantiation present"),
|
||||||
|
]
|
||||||
|
|
||||||
|
all_checks_passed = True
|
||||||
|
for check_str, description in checks:
|
||||||
|
if check_str in content:
|
||||||
|
print(f"✓ PASS | {description}")
|
||||||
|
else:
|
||||||
|
print(f"✗ FAIL | {description} - not found")
|
||||||
|
all_checks_passed = False
|
||||||
|
|
||||||
|
print("-" * 60)
|
||||||
|
return all_checks_passed
|
||||||
|
|
||||||
|
|
||||||
|
def test_documentation_consistency():
|
||||||
|
"""Verify documentation mentions the new feature."""
|
||||||
|
print("\nTesting documentation consistency...")
|
||||||
|
print("-" * 60)
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
docs_to_check = [
|
||||||
|
("configuration.mdx", "CUA_USE_HOST_COMPUTER_SERVER"),
|
||||||
|
("usage.mdx", "Targeting Your Local Desktop"),
|
||||||
|
]
|
||||||
|
|
||||||
|
docs_path = (
|
||||||
|
pathlib.Path(__file__).parent.parent
|
||||||
|
/ "docs"
|
||||||
|
/ "content"
|
||||||
|
/ "docs"
|
||||||
|
/ "libraries"
|
||||||
|
/ "mcp-server"
|
||||||
|
)
|
||||||
|
|
||||||
|
all_docs_ok = True
|
||||||
|
for doc_file, expected_content in docs_to_check:
|
||||||
|
doc_path = docs_path / doc_file
|
||||||
|
if not doc_path.exists():
|
||||||
|
print(f"✗ FAIL | {doc_file} not found")
|
||||||
|
all_docs_ok = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
content = doc_path.read_text()
|
||||||
|
if expected_content in content:
|
||||||
|
print(f"✓ PASS | {doc_file} contains '{expected_content}'")
|
||||||
|
else:
|
||||||
|
print(f"✗ FAIL | {doc_file} missing '{expected_content}'")
|
||||||
|
all_docs_ok = False
|
||||||
|
|
||||||
|
print("-" * 60)
|
||||||
|
return all_docs_ok
|
||||||
|
|
||||||
|
|
||||||
|
def print_usage_examples():
|
||||||
|
"""Print usage examples for both modes."""
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("USAGE EXAMPLES")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
print("\n1. DEFAULT MODE (VM):")
|
||||||
|
print("-" * 60)
|
||||||
|
print(
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "anthropic/claude-3-5-sonnet-20241022"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Note: CUA_USE_HOST_COMPUTER_SERVER is not set, so VM mode is used (safe).
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
print("\n2. LOCAL DESKTOP MODE:")
|
||||||
|
print("-" * 60)
|
||||||
|
print(
|
||||||
|
"""
|
||||||
|
Step 1: Start computer-server locally:
|
||||||
|
python -m computer_server
|
||||||
|
|
||||||
|
Step 2: Configure MCP client:
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cua-agent": {
|
||||||
|
"command": "/bin/bash",
|
||||||
|
"args": ["~/.cua/start_mcp_server.sh"],
|
||||||
|
"env": {
|
||||||
|
"CUA_MODEL_NAME": "anthropic/claude-3-5-sonnet-20241022",
|
||||||
|
"CUA_USE_HOST_COMPUTER_SERVER": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
⚠️ WARNING: AI will have direct access to your desktop!
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run all quick tests."""
|
||||||
|
print("=" * 60)
|
||||||
|
print("QUICK TEST: MCP Server Local Desktop Option")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
|
||||||
|
results = []
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
results.append(("Environment Variable Parsing", test_env_var_parsing()))
|
||||||
|
results.append(("Session Manager Logic", test_session_manager_logic()))
|
||||||
|
results.append(("Documentation Consistency", test_documentation_consistency()))
|
||||||
|
|
||||||
|
# Print summary
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("SUMMARY")
|
||||||
|
print("=" * 60)
|
||||||
|
for test_name, passed in results:
|
||||||
|
status = "✓ PASSED" if passed else "✗ FAILED"
|
||||||
|
print(f"{status} | {test_name}")
|
||||||
|
|
||||||
|
all_passed = all(result for _, result in results)
|
||||||
|
|
||||||
|
if all_passed:
|
||||||
|
print("\n🎉 All quick tests passed!")
|
||||||
|
print_usage_examples()
|
||||||
|
print("\nNext steps:")
|
||||||
|
print("1. Run full automated tests: pytest tests/test_mcp_server_local_option.py")
|
||||||
|
print("2. Follow manual testing guide: tests/MANUAL_TEST_LOCAL_OPTION.md")
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
print("\n❌ Some tests failed. Please review the output above.")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
"""
|
||||||
|
Test script to verify MCP Server local desktop option works correctly.
|
||||||
|
|
||||||
|
This test verifies:
|
||||||
|
1. Default behavior: Computer uses VM
|
||||||
|
2. New behavior: Computer uses host when CUA_USE_HOST_COMPUTER_SERVER=true
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add the mcp-server module to path
|
||||||
|
mcp_server_path = Path(__file__).parent.parent / "libs" / "python" / "mcp-server"
|
||||||
|
sys.path.insert(0, str(mcp_server_path.parent.parent.parent / "libs" / "python"))
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_default_vm_mode():
|
||||||
|
"""Test that the default mode uses VM (not host computer server)."""
|
||||||
|
# Ensure environment variable is not set or is false
|
||||||
|
os.environ.pop("CUA_USE_HOST_COMPUTER_SERVER", None)
|
||||||
|
|
||||||
|
from mcp_server.session_manager import ComputerPool
|
||||||
|
|
||||||
|
pool = ComputerPool(max_size=1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
computer = await pool.acquire()
|
||||||
|
|
||||||
|
# Verify the computer was initialized
|
||||||
|
assert computer is not None
|
||||||
|
|
||||||
|
# Check that use_host_computer_server was set to False (default)
|
||||||
|
# This should start a VM
|
||||||
|
print("✓ Default mode: Computer initialized (VM mode expected)")
|
||||||
|
|
||||||
|
await pool.release(computer)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
await pool.shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_local_desktop_mode():
|
||||||
|
"""Test that setting CUA_USE_HOST_COMPUTER_SERVER=true uses host."""
|
||||||
|
# Set environment variable to true
|
||||||
|
os.environ["CUA_USE_HOST_COMPUTER_SERVER"] = "true"
|
||||||
|
|
||||||
|
# Need to reload module to pick up new env var
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
import mcp_server.session_manager
|
||||||
|
from mcp_server.session_manager import ComputerPool
|
||||||
|
|
||||||
|
importlib.reload(mcp_server.session_manager)
|
||||||
|
|
||||||
|
pool = mcp_server.session_manager.ComputerPool(max_size=1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
computer = await pool.acquire()
|
||||||
|
|
||||||
|
# Verify the computer was initialized
|
||||||
|
assert computer is not None
|
||||||
|
|
||||||
|
# Check that use_host_computer_server was set to True
|
||||||
|
print("✓ Local mode: Computer initialized (host mode expected)")
|
||||||
|
|
||||||
|
await pool.release(computer)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
await pool.shutdown()
|
||||||
|
# Clean up env var
|
||||||
|
os.environ.pop("CUA_USE_HOST_COMPUTER_SERVER", None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_env_var_parsing():
|
||||||
|
"""Test that various values of CUA_USE_HOST_COMPUTER_SERVER are parsed correctly."""
|
||||||
|
test_cases = [
|
||||||
|
("true", True),
|
||||||
|
("True", True),
|
||||||
|
("TRUE", True),
|
||||||
|
("1", True),
|
||||||
|
("yes", True),
|
||||||
|
("false", False),
|
||||||
|
("False", False),
|
||||||
|
("FALSE", False),
|
||||||
|
("0", False),
|
||||||
|
("no", False),
|
||||||
|
("", False),
|
||||||
|
("random", False),
|
||||||
|
]
|
||||||
|
|
||||||
|
for value, expected in test_cases:
|
||||||
|
os.environ["CUA_USE_HOST_COMPUTER_SERVER"] = value
|
||||||
|
|
||||||
|
# Check parsing logic
|
||||||
|
use_host = os.getenv("CUA_USE_HOST_COMPUTER_SERVER", "false").lower() in (
|
||||||
|
"true",
|
||||||
|
"1",
|
||||||
|
"yes",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
use_host == expected
|
||||||
|
), f"Failed for value '{value}': expected {expected}, got {use_host}"
|
||||||
|
print(f"✓ Env var '{value}' correctly parsed as {expected}")
|
||||||
|
|
||||||
|
os.environ.pop("CUA_USE_HOST_COMPUTER_SERVER", None)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Testing MCP Server Local Desktop Option")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
print("\n1. Testing environment variable parsing...")
|
||||||
|
asyncio.run(test_env_var_parsing())
|
||||||
|
|
||||||
|
print("\n2. Testing default VM mode...")
|
||||||
|
try:
|
||||||
|
asyncio.run(test_default_vm_mode())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Default VM mode test failed: {e}")
|
||||||
|
print("Note: This may require lume/VM setup to fully test")
|
||||||
|
|
||||||
|
print("\n3. Testing local desktop mode...")
|
||||||
|
try:
|
||||||
|
asyncio.run(test_local_desktop_mode())
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ Local desktop mode test failed: {e}")
|
||||||
|
print("Note: This may require computer-server to be running locally")
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("Tests completed!")
|
||||||
Reference in New Issue
Block a user