# PySide6 MCP [Health: Active]

**Category:** 📂 Browser Automation  
**Repository:** https://github.com/com55/pyside6-mcp  
**GitHub Stars:** 4  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/pyside6-mcp

## Description
Playwright-style MCP to inspect, control, and debug PySide6 desktop GUIs.

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "pyside6-mcp": {
    "command": "uvx",
    "args": ["pyside6-mcp"]
  }
}
```

## Documentation & README

<!-- mcp-name: io.github.com55/pyside6-mcp -->
# pyside6-mcp

Playwright-style MCP server for PySide6 apps — lets AI assistants see, control, and debug your Python desktop GUI without modifying your app's source code.

```
AI assistant → MCP tools → pyside6-mcp server → HTTP bridge (ephemeral localhost port) → PySide6 app
```

## Features

- **Screenshot** any window or widget
- **Inspect** the full widget tree (class, name, geometry, text, state)
- **Click, type, scroll, press keys** — full interaction
- **Find widgets** by class, objectName, or text content
- **Read Python logs** captured from the app
- **Run Python** inside the app process for advanced inspection
- **Launch and stop** the app from the agent

Zero changes to your app's source code required.

## Requirements

- Python 3.11+
- PySide6 6.6+
- [uv](https://docs.astral.sh/uv/) (recommended)
- Windows (tested), Linux/macOS (should work)

## Installation

The MCP server (stdio) and the in-app bridge are separate:

| Component | Where it runs | Needs PySide6? |
|-----------|---------------|----------------|
| **MCP server** (`pyside6-mcp`) | MCP client's process | No |
| **Bridge** (`python -m pyside6_mcp …`) | Inside your PySide6 app | Yes |

**No changes to the target project.** `launch_app(cwd=…)` injects only the
bridge modules via an isolated `PYTHONPATH` — nothing is added to `pyproject.toml`,
and the MCP server's dependencies (fastmcp, httpx, …) never enter the app environment.

Requires [uv](https://docs.astral.sh/uv/) on `PATH`. MCP Registry name:
`io.github.com55/pyside6-mcp`.

Unlike [qt-mcp](https://github.com/0xCarbon/qt-mcp), you do **not** add this
package to the target app or set a probe env var. `launch_app` injects the bridge.

### Claude Code

Plugin (MCP + skill). `install` only searches marketplaces you have added —
there is no `github:` install shorthand:

```bash
claude plugin marketplace add com55/pyside6-mcp
claude plugin install pyside6-mcp@pyside6-mcp
```

MCP server only:

```bash
claude mcp add -s user pyside6 -- uvx pyside6-mcp
```

### Cursor

Install the Agent Plugin from this repository (or from the Cursor Marketplace
once listed). Manual stdio config:

```json
{
  "mcpServers": {
    "pyside6": {
      "command": "uvx",
      "args": ["pyside6-mcp"]
    }
  }
}
```

After saving, reload MCP servers in **Cursor Settings → MCP**.
See [`examples/cursor-mcp-config.json`](https://github.com/com55/pyside6-mcp/blob/HEAD/examples/cursor-mcp-config.json).

### Any stdio MCP client

```json
{
  "mcpServers": {
    "pyside6": {
      "command": "uvx",
      "args": ["pyside6-mcp"]
    }
  }
}
```

Place it wherever that client expects MCP config (user-level or project-level).
See [`examples/mcp-config.json`](https://github.com/com55/pyside6-mcp/blob/HEAD/examples/mcp-config.json).

### VS Code / GitHub Copilot / other clients

Same stdio block as **Any stdio MCP client**.

> **Note:** `uvx` downloads and runs the MCP server in an isolated env — PySide6 is **not**
> required there. PySide6 is only needed in the target app's venv (already a project dependency).
>
> To run from a git checkout instead of PyPI: `uvx --from git+https://github.com/com55/pyside6-mcp pyside6-mcp`

## Usage

### From MCP (recommended — zero project setup)

```
launch_app(cwd="/path/to/project")                              # main.py at root
launch_app(cwd="/path/to/project", script="app.py")             # other name at root
launch_app(cwd="/path/to/project", script="backend/gui.py")   # entry in subfolder
get_launch_help()                                               # full script decision guide
list_apps()                                                     # pids of apps this server launched
```

`cwd` is the project root (`pyproject.toml`). `script` is the entry `.py` **relative to cwd**.

`launch_app` returns `{pid}` (the Qt app process, not the `uv` wrapper). Other tools omit `pid` to target the last launched app; pass `pid=` when several are running. Do not pass `port=`.

### Manual launch (when you start the app yourself)

Prefer `launch_app` above. Use these only when the app is already running, or
you want to start it outside the MCP server.

**Without editing app source** — run the entry script through the bridge launcher
(pulls `pyside6-mcp` into a temporary env; does not add it to the project):

```bash
cd your-pyside6-project
uv run --with pyside6-mcp python -m pyside6_mcp main.py
# other entry: … python -m pyside6_mcp app.py
# in a subfolder: … python -m pyside6_mcp backend/gui.py
```

Bridge listens on `http://127.0.0.1:7890` by default. Override with
`PYSIDE6_MCP_PORT`. Then from the agent call `wait_until_ready()` (and pass
`pid=` only if you use several apps).

`launch_app` is different: it picks an ephemeral port and injects only the
bridge modules via an isolated `PYTHONPATH` — you never set the port yourself.

**Embed in the app** (always-on; requires adding the package to that project):

```bash
uv add pyside6-mcp
```

```python
# In your app's main(), after QApplication is created and before app.exec()
from pyside6_mcp import install_bridge
install_bridge()  # same default port 7890 / PYSIDE6_MCP_PORT
```

### From your AI assistant

Once the app is running with the bridge active, ask your assistant:

> "Screenshot the app and click the Apply button"
> "Why is the checkbox disabled? Inspect its state."
> "Fill in the form and submit it"
> "Show me the last 20 log lines from the app"

Your assistant uses the `launch_app`, `screenshot`, `get_widget_tree`, `find_widget`, `click`, `type_text`, `get_logs`, and other tools automatically.

`launch_app` returns only when the UI is ready (a visible top-level window that has been quiet for at least 500 ms), not merely when the bridge HTTP server is up. Default `timeout` is 45 seconds.

## Tools

| Tool | Description |
|------|-------------|
| `launch_app(cwd, script?, app_args?, timeout)` | Launch app (no target-project install) and wait for UI readiness. Returns `{pid}` |
| `list_apps()` | Pids of apps launched by this server |
| `get_launch_help()` | How to set cwd, script, app_args before launch |
| `wait_until_ready(timeout, quiet_ms, pid?)` | Wait for UI readiness on an already-running app |
| `wait_for_idle(timeout, quiet_ms, pid?)` | Wait until UI has been quiet after an action |
| `get_app_status(pid?)` | Process + bridge health; detects likely modal blocks |
| `stop_app(pid?)` | Stop a launched app |
| `screenshot(widget_id?, pid?)` | Capture window or specific widget (modal/active-window aware) |
| `get_widget_tree(pid?)` | Full widget hierarchy with IDs |
| `get_widget_info(widget_id, pid?)` | Detailed properties of one widget |
| `get_app_state(pid?)` | Active window, focus, screen info |
| `find_widget(class_name?, object_name?, text?, visible?, pid?)` | Search widgets |
| `click(widget_id?, x?, y?, button?, pid?)` | Mouse click |
| `double_click(widget_id, x?, y?, pid?)` | Double click |
| `type_text(text, widget_id?, pid?)` | Keyboard input |
| `press_key(key, pid?)` | Named key: enter, escape, tab, up/down, f5, … |
| `scroll(dy, widget_id?, dx?, pid?)` | Scroll wheel |
| `list_actions(pid?)` | List QAction menu/toolbar items |
| `trigger_action(name?, text?, pid?)` | Trigger a QAction without clicking menus |
| `get_logs(n?, pid?)` | Recent Python log records |
| `get_app_output(n?, pid?)` | Raw stdout/stderr from launched app |
| `eval_python(code, pid?)` | Execute Python inside the app process |

## Agent Skill

A companion skill ships at [`skills/pyside6-mcp/SKILL.md`](https://github.com/com55/pyside6-mcp/blob/HEAD/skills/pyside6-mcp/SKILL.md)
and is installed automatically with the plugin. It tells the agent when and how
to use these tools — no need to explain the workflow every time.

## Architecture

```
pyside6_mcp/
├── bridge.py      # In-process HTTP server (runs inside the target app)
├── launch.py      # Isolated PYTHONPATH inject + launch_app argv/validation
├── session.py     # Handshake + in-memory pid → port sessions
├── server.py      # FastMCP stdio server (the MCP client talks to this)
├── __init__.py    # Exports install_bridge()
└── __main__.py    # Launcher: python -m pyside6_mcp <script>
```

**Thread safety**: all Qt operations are marshaled to the main thread via `QApplication.postEvent` with a custom event type — the same mechanism Qt uses internally for cross-thread signals.

## Examples

- [`examples/test_app.py`](https://github.com/com55/pyside6-mcp/blob/HEAD/examples/test_app.py) — minimal PySide6 app to verify the bridge
- [`examples/mcp-config.json`](https://github.com/com55/pyside6-mcp/blob/HEAD/examples/mcp-config.json) — generic MCP config (Cursor, VS Code, Windsurf, …)
- [`examples/cursor-mcp-config.json`](https://github.com/com55/pyside6-mcp/blob/HEAD/examples/cursor-mcp-config.json) — Cursor-specific template
- [`examples/claude-mcp-config.json`](https://github.com/com55/pyside6-mcp/blob/HEAD/examples/claude-mcp-config.json) — same format, kept for reference

## License

MIT

