mirror of
https://github.com/thomasnordquist/MQTT-Explorer.git
synced 2026-07-27 19:56:50 +00:00
Add MCP introspection support for Electron frontend with Playwright integration
Co-authored-by: thomasnordquist <7721625+thomasnordquist@users.noreply.github.com>
This commit is contained in:
co-authored by
thomasnordquist
parent
2d8b976e33
commit
0046656134
@@ -9,3 +9,6 @@ test.png
|
||||
.awcache
|
||||
.scannerwork
|
||||
screen*.png
|
||||
|
||||
# MCP introspection artifacts
|
||||
mqtt-explorer-mcp-screenshot.png
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
# MCP Introspection Support
|
||||
|
||||
This document explains how to use MCP (Model Context Protocol) introspection with MQTT Explorer for deterministic testing and automation with tools like GitHub Copilot with Playwright.
|
||||
|
||||
## What is MCP Introspection?
|
||||
|
||||
MCP introspection allows external tools to interact with and control the MQTT Explorer Electron application through the Chrome DevTools Protocol (CDP). This enables:
|
||||
|
||||
- Deterministic automated testing with Playwright
|
||||
- GitHub Copilot agent mode integration
|
||||
- Remote debugging and inspection of the application
|
||||
- Automated UI testing and interaction
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js >= 18
|
||||
- Yarn package manager
|
||||
- MQTT Explorer built from source
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Option 1: Using the npm script (Recommended)
|
||||
|
||||
```bash
|
||||
# Build the application first
|
||||
yarn build
|
||||
|
||||
# Start with MCP introspection enabled
|
||||
yarn start:mcp
|
||||
```
|
||||
|
||||
### Option 2: Using the shell script directly
|
||||
|
||||
```bash
|
||||
# Build the application first
|
||||
yarn build
|
||||
|
||||
# Start with default debugging port (9222)
|
||||
./scripts/start-with-mcp.sh
|
||||
|
||||
# Or specify a custom port
|
||||
REMOTE_DEBUG_PORT=9223 ./scripts/start-with-mcp.sh
|
||||
```
|
||||
|
||||
### Option 3: Manual electron launch
|
||||
|
||||
```bash
|
||||
# Build the application first
|
||||
yarn build
|
||||
|
||||
# Start with MCP flags
|
||||
electron . --enable-mcp-introspection --remote-debugging-port=9222
|
||||
```
|
||||
|
||||
## Using with Playwright
|
||||
|
||||
Once the application is running with MCP introspection enabled, you can connect to it using Playwright:
|
||||
|
||||
```javascript
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
// Connect to the running Electron app
|
||||
const browser = await chromium.connectOverCDP('http://localhost:9222');
|
||||
const context = browser.contexts()[0];
|
||||
const page = context.pages()[0];
|
||||
|
||||
// Now you can interact with the page
|
||||
await page.screenshot({ path: 'screenshot.png' });
|
||||
|
||||
// ... perform your tests ...
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
```
|
||||
|
||||
## Using with GitHub Copilot Agent Mode
|
||||
|
||||
When using GitHub Copilot with Playwright MCP server:
|
||||
|
||||
1. Ensure the MCP configuration is set up (see `mcp.json`)
|
||||
2. Start MQTT Explorer with MCP introspection:
|
||||
```bash
|
||||
yarn start:mcp
|
||||
```
|
||||
3. Use Copilot agent commands to interact with the running application
|
||||
|
||||
## Configuration
|
||||
|
||||
### MCP Configuration File
|
||||
|
||||
The `mcp.json` file in the root directory contains the MCP server configuration for Playwright:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"playwright": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-playwright"
|
||||
],
|
||||
"env": {
|
||||
"PLAYWRIGHT_BROWSERS_PATH": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Remote Debugging Port
|
||||
|
||||
The default remote debugging port is `9222`. You can customize it by:
|
||||
|
||||
1. Setting the `REMOTE_DEBUG_PORT` environment variable:
|
||||
```bash
|
||||
REMOTE_DEBUG_PORT=9223 yarn start:mcp
|
||||
```
|
||||
|
||||
2. Passing the `--remote-debugging-port` flag directly:
|
||||
```bash
|
||||
electron . --enable-mcp-introspection --remote-debugging-port=9223
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
If you get an error that the port is already in use, either:
|
||||
- Stop the other process using that port
|
||||
- Use a different port with `REMOTE_DEBUG_PORT` environment variable
|
||||
|
||||
### Cannot Connect
|
||||
|
||||
Ensure that:
|
||||
1. The application is running with the `--enable-mcp-introspection` flag
|
||||
2. The remote debugging port matches between the application and your client
|
||||
3. No firewall is blocking the connection
|
||||
|
||||
## Security Considerations
|
||||
|
||||
When running with MCP introspection enabled:
|
||||
|
||||
- The application exposes debugging capabilities on a local port
|
||||
- Only run this in development/testing environments
|
||||
- Do not expose the debugging port to untrusted networks
|
||||
- Do not run with introspection in production
|
||||
|
||||
## Related Files
|
||||
|
||||
- `src/development.ts` - Helper functions for MCP introspection mode
|
||||
- `src/electron.ts` - Main Electron process with MCP support
|
||||
- `scripts/start-with-mcp.sh` - Convenience script to start with MCP
|
||||
- `mcp.json` - MCP server configuration
|
||||
- `src/spec/demoVideo.ts` - Example Playwright test implementation
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
||||
- [Playwright Documentation](https://playwright.dev/)
|
||||
- [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/)
|
||||
- [Electron Remote Debugging](https://www.electronjs.org/docs/latest/tutorial/debugging-main-process)
|
||||
@@ -47,6 +47,18 @@ To achieve a reliable product automated tests run regularly on travis.
|
||||
- MQTT integration
|
||||
- UI-Tests (The demo is a recorded ui test)
|
||||
|
||||
## MCP Introspection for Testing and Automation
|
||||
|
||||
MQTT Explorer supports MCP (Model Context Protocol) introspection for deterministic testing and integration with tools like GitHub Copilot agent mode with Playwright.
|
||||
|
||||
See [MCP_INTROSPECTION.md](MCP_INTROSPECTION.md) for detailed documentation.
|
||||
|
||||
Quick start:
|
||||
```bash
|
||||
yarn build
|
||||
yarn start:mcp
|
||||
```
|
||||
|
||||
## Run UI-tests
|
||||
|
||||
A [mosquitto](https://mosquitto.org/) MQTT broker is required to run the ui-tests.
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Example script demonstrating how to use Playwright to connect to
|
||||
* MQTT Explorer running with MCP introspection enabled.
|
||||
*
|
||||
* Prerequisites:
|
||||
* 1. Start MQTT Explorer with MCP introspection:
|
||||
* yarn start:mcp
|
||||
*
|
||||
* 2. Run this script:
|
||||
* node examples/playwright-mcp-example.js
|
||||
*/
|
||||
|
||||
const { chromium } = require('playwright')
|
||||
|
||||
async function main() {
|
||||
console.log('Connecting to MQTT Explorer via Chrome DevTools Protocol...')
|
||||
|
||||
try {
|
||||
// Connect to the running Electron app via CDP
|
||||
const browser = await chromium.connectOverCDP('http://localhost:9222')
|
||||
console.log('Connected successfully!')
|
||||
|
||||
// Get the existing browser context
|
||||
const contexts = browser.contexts()
|
||||
if (contexts.length === 0) {
|
||||
console.error('No browser contexts found')
|
||||
await browser.close()
|
||||
return
|
||||
}
|
||||
|
||||
const context = contexts[0]
|
||||
const pages = context.pages()
|
||||
|
||||
if (pages.length === 0) {
|
||||
console.error('No pages found')
|
||||
await browser.close()
|
||||
return
|
||||
}
|
||||
|
||||
const page = pages[0]
|
||||
console.log(`Page title: ${await page.title()}`)
|
||||
|
||||
// Take a screenshot
|
||||
await page.screenshot({ path: 'mqtt-explorer-mcp-screenshot.png' })
|
||||
console.log('Screenshot saved to mqtt-explorer-mcp-screenshot.png')
|
||||
|
||||
// Example: Check if the connection form is visible
|
||||
const usernameInput = await page.locator('//label[contains(text(), "Username")]/..//input')
|
||||
const isVisible = await usernameInput.isVisible().catch(() => false)
|
||||
console.log(`Username input visible: ${isVisible}`)
|
||||
|
||||
// You can add more interactions here
|
||||
// For example:
|
||||
// - Fill in connection details
|
||||
// - Click connect button
|
||||
// - Verify UI elements
|
||||
// - Test specific features
|
||||
|
||||
console.log('Done! Browser connection will remain open.')
|
||||
console.log('Press Ctrl+C to close this script (the app will keep running)')
|
||||
|
||||
// Keep the script running to maintain the connection
|
||||
await new Promise(() => {})
|
||||
} catch (error) {
|
||||
console.error('Error connecting to MQTT Explorer:', error.message)
|
||||
console.error('\nMake sure MQTT Explorer is running with MCP introspection:')
|
||||
console.error(' yarn start:mcp')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"playwright": {
|
||||
"command": "npx",
|
||||
"args": [
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-playwright"
|
||||
],
|
||||
"env": {
|
||||
"PLAYWRIGHT_BROWSERS_PATH": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"start": "electron .",
|
||||
"start:mcp": "./scripts/start-with-mcp.sh",
|
||||
"test": "yarn test:app && yarn test:backend",
|
||||
"test:app": "cd app && yarn test",
|
||||
"test:backend": "cd backend && yarn test",
|
||||
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script to launch MQTT Explorer with MCP introspection enabled
|
||||
# This allows tools like GitHub Copilot with Playwright MCP to interact with the app
|
||||
|
||||
REMOTE_DEBUG_PORT="${REMOTE_DEBUG_PORT:-9222}"
|
||||
|
||||
echo "Starting MQTT Explorer with MCP introspection enabled"
|
||||
echo "Remote debugging port: $REMOTE_DEBUG_PORT"
|
||||
echo ""
|
||||
echo "You can now use Playwright MCP or other debugging tools to connect to the app"
|
||||
echo "Connect to: http://localhost:$REMOTE_DEBUG_PORT"
|
||||
echo ""
|
||||
|
||||
# Build the app if needed
|
||||
if [ ! -d "dist" ]; then
|
||||
echo "Building the app..."
|
||||
yarn build
|
||||
fi
|
||||
|
||||
# Start the app with MCP introspection flags
|
||||
electron . --enable-mcp-introspection --remote-debugging-port=$REMOTE_DEBUG_PORT "$@"
|
||||
@@ -32,3 +32,15 @@ export function isDev() {
|
||||
export function runningUiTestOnCi() {
|
||||
return Boolean(process.argv.find(arg => arg === '--runningUiTestOnCi'))
|
||||
}
|
||||
|
||||
export function enableMcpIntrospection() {
|
||||
return Boolean(process.argv.find(arg => arg === '--enable-mcp-introspection'))
|
||||
}
|
||||
|
||||
export function getRemoteDebuggingPort() {
|
||||
const portArg = process.argv.find(arg => arg.startsWith('--remote-debugging-port='))
|
||||
if (portArg) {
|
||||
return parseInt(portArg.split('=')[1], 10)
|
||||
}
|
||||
return enableMcpIntrospection() ? 9222 : undefined
|
||||
}
|
||||
|
||||
+9
-1
@@ -8,7 +8,7 @@ import { promises as fsPromise } from 'fs'
|
||||
// import { electronTelemetryFactory } from 'electron-telemetry'
|
||||
import { menuTemplate } from './MenuTemplate'
|
||||
import buildOptions from './buildOptions'
|
||||
import { waitForDevServer, isDev, runningUiTestOnCi, loadDevTools } from './development'
|
||||
import { waitForDevServer, isDev, runningUiTestOnCi, loadDevTools, enableMcpIntrospection, getRemoteDebuggingPort } from './development'
|
||||
import { shouldAutoUpdate, handleAutoUpdate } from './autoUpdater'
|
||||
import { registerCrashReporter } from './registerCrashReporter'
|
||||
import { makeOpenDialogRpc, makeSaveDialogRpc } from '../events/OpenDialogRequest'
|
||||
@@ -22,6 +22,14 @@ registerCrashReporter()
|
||||
|
||||
// disable-dev-shm-usage is required to run the debug console
|
||||
app.commandLine.appendSwitch('--no-sandbox --disable-dev-shm-usage')
|
||||
|
||||
// Enable remote debugging for MCP introspection
|
||||
const remoteDebuggingPort = getRemoteDebuggingPort()
|
||||
if (remoteDebuggingPort) {
|
||||
app.commandLine.appendSwitch('--remote-debugging-port', remoteDebuggingPort.toString())
|
||||
log.info(`Remote debugging enabled on port ${remoteDebuggingPort}`)
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
backendRpc.on(makeOpenDialogRpc(), async request => {
|
||||
return dialog.showOpenDialog(BrowserWindow.getFocusedWindow() ?? BrowserWindow.getAllWindows()[0], request)
|
||||
|
||||
Reference in New Issue
Block a user