Metadata-Version: 2.4
Name: miosa-mcp
Version: 0.2.0
Summary: MCP server that exposes MIOSA computer-use tools to Claude Code
Project-URL: Homepage, https://miosa.ai
Project-URL: Documentation, https://miosa.ai/docs/mcp
Author-email: MIOSA <dev@miosa.ai>
License-Expression: MIT
Keywords: agents,ai,claude,computer-use,desktop,mcp,miosa
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.10
Requires-Dist: mcp>=1.0.0
Requires-Dist: miosa>=1.2.0
Description-Content-Type: text/markdown

# miosa-mcp

MCP (Model Context Protocol) bridge that exposes MIOSA cloud sandboxes &
desktops to any MCP-aware client (Claude Code, Cursor, Gemini CLI, etc.).

## Two ways to run it

### 1. Hosted (recommended) — no install

MIOSA ships a public MCP endpoint at `https://api.miosa.ai/api/v1/mcp`. Point
any MCP client at it with your `msk_u_*` API key as a Bearer token:

```bash
claude mcp add --transport http miosa \
  https://api.miosa.ai/api/v1/mcp \
  --header "Authorization: Bearer msk_u_your_key_here"
```

Full guide: [`docs/api/mcp-connect.md`](../docs/api/mcp-connect.md).

### 2. Local stdio (this Python package)

Install:

```bash
pip install miosa-mcp
```

Add to `~/.claude/mcp.json`:

```json
{
  "mcpServers": {
    "miosa": {
      "command": "python",
      "args": ["-m", "miosa_mcp"],
      "env": {
        "MIOSA_API_KEY": "msk_u_your_key_here"
      }
    }
  }
}
```

Use stdio when you need to wrap the MCP layer with custom local logic, or
your client doesn't yet support remote MCP. Both modes hit the same MIOSA
REST API under the hood.

Get your API key at <https://miosa.ai/dashboard/api-keys>.

## Tools

### Lifecycle

| Tool | Description |
|------|-------------|
| `computer_create(name, template_type?, size?)` | Create a computer and start it. Becomes the active computer. |
| `computer_list()` | List all computers in your tenant. |
| `computer_destroy(computer_id?)` | Permanently destroy a computer. |

### Desktop — Visual

| Tool | Description |
|------|-------------|
| `computer_screenshot(computer_id?)` | Capture a PNG screenshot. Claude can see and reason about it. |
| `computer_get_screen_size(computer_id?)` | Get screen resolution in pixels. |
| `computer_get_cursor_position(computer_id?)` | Get current cursor x/y. |

### Desktop — Pointer

| Tool | Description |
|------|-------------|
| `computer_click(x, y, button?, computer_id?)` | Click at coordinates. |
| `computer_double_click(x, y, computer_id?)` | Double-click at coordinates. |
| `computer_move_cursor(x, y, computer_id?)` | Move cursor without clicking. |
| `computer_drag(from_x, from_y, to_x, to_y, computer_id?)` | Click-drag between positions. |
| `computer_scroll(direction?, clicks?, x?, y?, computer_id?)` | Scroll up/down/left/right. |

### Desktop — Keyboard

| Tool | Description |
|------|-------------|
| `computer_type(text, computer_id?)` | Type text into the focused field. |
| `computer_key(key, computer_id?)` | Press a single key (Return, Tab, Escape, etc.). |
| `computer_hotkey(keys, computer_id?)` | Press a key combo (e.g. `["ctrl", "c"]`). |

### Clipboard

| Tool | Description |
|------|-------------|
| `computer_get_clipboard(computer_id?)` | Read clipboard text. |
| `computer_set_clipboard(text, computer_id?)` | Write clipboard text. |

### Window Management

| Tool | Description |
|------|-------------|
| `computer_windows(computer_id?)` | List open windows with IDs, titles, positions. |
| `computer_launch(app, computer_id?)` | Launch an app by name (firefox, gedit, xterm…). |

### Shell & Files

| Tool | Description |
|------|-------------|
| `computer_bash(command, timeout?, computer_id?)` | Run a bash command; returns stdout, stderr, exit_code. |
| `computer_write_file(path, content, computer_id?)` | Write a file inside the VM. |
| `computer_read_file(path, computer_id?)` | Read a file from inside the VM. |

## Active Computer

All tools accept an optional `computer_id`. When omitted, the server uses the most recently created or accessed computer automatically. This means you can `computer_create` once and omit the ID for the rest of the session.

## Example session

```
> computer_create(name="my-dev-box")
Created computer 'my-dev-box' (id=comp_abc123, status=running). This is now the active computer.

> computer_screenshot()
[PNG image of the desktop appears in Claude's context]

> computer_bash(command="ls /home")
stdout:
ubuntu
exit_code: 0

> computer_launch(app="firefox")
Launched: firefox

> computer_screenshot()
[Firefox is now open]

> computer_click(x=640, y=50)
Clicked (640, 50) button=left

> computer_type(text="https://miosa.ai")
Typed: 'https://miosa.ai'

> computer_key(key="Return")
Pressed key: Return
```

## Development

```bash
# Install deps (requires Python 3.10+)
pip install -e ".[dev]"

# Type-check
mypy miosa_mcp/

# Lint
ruff check miosa_mcp/
```

## Architecture

The server is a single async Python process that:
1. Reads `MIOSA_API_KEY` from the environment
2. Initializes an `AsyncMiosa` client
3. Maintains an in-process cache of `AsyncComputer` objects
4. Serves MCP tools over stdio (the protocol Claude Code uses)
5. Maps every tool call to the corresponding MIOSA SDK method
6. Returns screenshots as base64-encoded PNG images (MCP `ImageContent`)

All desktop action tools (`click`, `type`, `key`, etc.) call the MIOSA platform API which proxies commands through to the running VM's envd daemon at port 49983.
