PixInsight MCP Bridge
by priestjim
README.md
# PixInsight MCP Bridge
An MCP (Model Context Protocol) bridge for [PixInsight](https://pixinsight.com/) that enables LLMs to interact with PixInsight's image processing capabilities through a local HTTP/SSE server.
## Overview
PixInsight MCP Bridge runs as a PixInsight script that spawns a local Node.js HTTP server implementing the MCP protocol. This allows any MCP-compatible client (Claude Desktop, VS Code Copilot, etc.) to:
- **List all available PixInsight processes** with categories and descriptions
- **Invoke any PixInsight process** with custom parameters on specific views or globally
- **List open image views** with metadata (dimensions, color space, bit depth)
- **Get the currently focused view** and its properties
- **Change focus** to any open view by ID
- **Capture image data** from any view as base64-encoded JPEG for LLM visual inspection
- **Register custom processes** (e.g. third-party plugins) via the dialog UI, persisted across sessions
## Architecture
```
┌─────────────────┐ HTTP/SSE ┌──────────────────┐ stdin/stdout ┌───────────────────┐
│ MCP Client │ ◄──────────────── │ Node.js Bridge │ ◄──────────────► │ PJSR Script │
│ (Claude, etc.) │ ──────────────► │ Server │ ────────────────► │ (PixInsight) │
└─────────────────┘ └──────────────────┘ └───────────────────┘
port 3189 (default)
```
The bridge uses a hybrid architecture:
1. **PJSR Script** (`pixinsight-mcp-bridge.js`) — Runs inside PixInsight's JavaScript runtime (ECMA 262-5/ES5). Handles all PixInsight API interactions and spawns the HTTP server via `ExternalProcess`.
2. **Node.js Bridge Server** (`bridge/server.js`) — Handles MCP protocol communication over HTTP. Supports both legacy SSE transport (spec 2024-11-05) and Streamable HTTP transport (spec 2025-03-26).
3. **IPC Layer** — Line-delimited JSON over stdin/stdout pipes between the two processes.
## Requirements
- **PixInsight** 1.8.x or later
- **Node.js** >= 14.0.0 (must be in PATH or at a standard install location)
## Installation
### 1. Download the plugin
Clone or download this repository:
```bash
git clone https://github.com/GaiaLabs/pixinsight-mcp-bridge.git
```
### 2. Copy to PixInsight scripts directory
Copy the `src/` directory contents to your PixInsight scripts folder:
- **macOS**: `/Applications/PixInsight/src/scripts/MCP-Bridge/`
- **Windows**: `C:\Program Files\PixInsight\src\scripts\MCP-Bridge\`
- **Linux**: `/opt/PixInsight/src/scripts/MCP-Bridge/`
The resulting structure should be:
```
PixInsight/src/scripts/MCP-Bridge/
├── pixinsight-mcp-bridge.js
├── lib/
│ └── handlers.jsh
└── bridge/
├── server.js
├── mcp-handler.js
└── ipc.js
```
### 3. Register the script in PixInsight
1. Open PixInsight
2. Go to **Script > Feature Scripts...**
3. Click **Add**
4. Navigate to the `MCP-Bridge/` directory you created
5. Click **OK** — the script will appear under **Script > MCP > PixInsight MCP Bridge**
### 4. Configure your MCP client
Add the server to your MCP client configuration. For example, in Claude Desktop's `claude_desktop_config.json`:
```json
{
"mcpServers": {
"pixinsight": {
"url": "http://127.0.0.1:3189/sse"
}
}
}
```
For clients that support Streamable HTTP transport, use:
```json
{
"mcpServers": {
"pixinsight": {
"url": "http://127.0.0.1:3189/mcp"
}
}
}
```
## Usage
### Starting the Bridge
1. Open PixInsight
2. Go to **Script > MCP > PixInsight MCP Bridge**
3. Set the port (default: 3189)
4. Optionally register custom processes (see below)
5. Click **Start**
6. The bridge server will start and the MCP endpoint will be available at `http://127.0.0.1:3189`
### Registering Custom Processes
The built-in process registry covers ~60 common PixInsight processes. To expose third-party processes (BlurXTerminator, StarNet2, NoiseXTerminator, etc.):
1. In the bridge dialog, find the **Custom Processes** section
2. Enter the **Process ID** (the exact constructor name, e.g. `BlurXTerminator`), a **Category**, and a **Description**
3. Click **Add**
Custom processes are persisted across PixInsight sessions. They are verified at runtime — if a registered process isn't installed, it will be silently excluded from `list_processes` results. You can add or remove custom processes while the bridge is running; changes take effect immediately.
### Available MCP Tools
#### `list_processes`
List all available PixInsight processes and scripts.
| Parameter | Type | Required | Description |
| ---------- | ------ | -------- | ------------------------------------ |
| `category` | string | No | Filter by category (e.g. "PixelMath") |
Example response:
```json
{
"processes": [
{ "id": "PixelMath", "category": "PixelMath", "description": "Pixel math expressions and formulas" },
{ "id": "ImageIntegration", "category": "ImageIntegration", "description": "Image stacking / integration" }
],
"count": 2
}
```
#### `invoke_process`
Execute a PixInsight process with specified parameters.
| Parameter | Type | Required | Description |
| ------------ | ------ | -------- | ------------------------------------------------ |
| `processId` | string | Yes | Process name (e.g. "PixelMath") |
| `parameters` | object | No | Process parameters as key-value pairs |
| `viewId` | string | No | View to execute on; omit for global execution |
Example — apply PixelMath to an image:
```json
{
"processId": "PixelMath",
"parameters": {
"expression": "$T * 2",
"createNewImage": false
},
"viewId": "Image01"
}
```
#### `list_views`
List all open image views (main views and previews).
No parameters required. Returns view metadata including dimensions, color space, bit depth, and file path.
#### `get_focused_view`
Get the currently active/focused view and its properties.
No parameters required.
#### `set_focused_view`
Change focus to a specific view by ID.
| Parameter | Type | Required | Description |
| --------- | ------ | -------- | -------------------------- |
| `viewId` | string | Yes | View ID (e.g. "Image01") |
#### `get_image_from_view`
Get the actual image contents of a view as a base64-encoded JPEG. The image is saved to a temporary JPEG file, read back as base64, and returned as MCP image content alongside metadata (dimensions, color space, bit depth).
| Parameter | Type | Required | Description |
| --------- | ------ | -------- | ------------------------------------------------------------------ |
| `viewId` | string | No | View ID to capture. If omitted, captures the currently focused view |
The response includes both the image data (as MCP `image` content) and a text block with view metadata.
### Standalone Mode (Testing)
You can run the bridge server without PixInsight for testing and development:
```bash
node src/bridge/server.js --standalone --port 3189
```
This starts the server with mock responses, useful for testing MCP client integrations.
## MCP Transport Support
The bridge supports two MCP transports:
### Legacy HTTP+SSE (2024-11-05 spec)
- `GET /sse` — Opens SSE stream, receives `endpoint` event with message URI
- `POST /messages?sessionId=<id>` — Send JSON-RPC messages; responses arrive via SSE
### Streamable HTTP (2025-03-26 spec)
- `POST /mcp` — Send JSON-RPC messages; response returned as JSON body or SSE stream
- `GET /mcp` — Open SSE stream for server-initiated messages
- `DELETE /mcp` — Terminate session
### Health Check
- `GET /health` — Returns `{ "status": "ok" }`
## Development
### Project Structure
```
pixinsight-mcp-bridge/
├── src/
│ ├── pixinsight-mcp-bridge.js # Main PJSR entry point (ES5)
│ ├── lib/
│ │ └── handlers.jsh # PixInsight command handlers (ES5)
│ └── bridge/
│ ├── server.js # Node.js HTTP/SSE MCP server
│ ├── mcp-handler.js # MCP protocol logic
│ └── ipc.js # IPC communication layer
├── test/
│ ├── run-tests.js # Test runner
│ ├── test-mcp-handler.js # MCP protocol tests
│ ├── test-server.js # HTTP server integration tests
│ └── test-handlers.js # PJSR handler tests (mocked PI API)
├── package.json
└── README.md
```
### Key Design Decisions
- **Hybrid architecture**: PixInsight's PJSR runtime has no HTTP server capability (`NetworkTransfer` is client-only). The solution uses `ExternalProcess` to spawn a Node.js HTTP server and communicates via stdin/stdout IPC.
- **ES5 compliance**: All PJSR code (`*.js` and `*.jsh` in `src/`) is ECMA 262-5 compliant — no `let`/`const`, no arrow functions, no template literals, no classes, no promises.
- **Zero dependencies**: The Node.js bridge server uses only built-in modules (`http`, `url`, `crypto`). No npm install required.
- **Process registry**: Since PJSR doesn't expose a direct "list all processes" API, the bridge maintains a curated registry of known processes and verifies availability at runtime via constructor detection.
### Running Tests
```bash
npm test
# or
node test/run-tests.js
```
The test suite includes:
- **MCP protocol tests** — JSON-RPC message handling, initialization, tool listing/calling
- **HTTP server tests** — Both SSE and Streamable HTTP transports, CORS, error handling
- **Handler tests** — PJSR command handlers with mocked PixInsight API
### Adding New Tools
1. Define the tool schema in `src/bridge/mcp-handler.js` in the `TOOLS` array
2. Add parameter validation in `MCPHandler.prototype._validateToolParams`
3. Implement the handler in `src/lib/handlers.jsh` in `CommandDispatcher`
4. Add mock handling in `createMockHandler` in `src/bridge/server.js`
5. Write tests
### Adding New Processes to the Registry
**For end users:** Use the **Custom Processes** section in the bridge dialog UI to register additional processes. These are persisted via PixInsight's Settings API and survive restarts.
**For developers:** Edit `CommandDispatcher.prototype._getProcessRegistry` in `src/lib/handlers.jsh` to add new built-in process entries:
```javascript
{ id: "NewProcess", category: "CategoryName", description: "What it does" }
```
All processes (both built-in and custom) are verified at runtime — entries for processes not installed in the user's PixInsight will be automatically excluded.
### PJSR Development Notes
- Use `#include "path/file.jsh"` for includes (preprocessor directive, not standard JS)
- Use `#feature-id Category > Name` to register scripts in PixInsight's Script menu
- All PixInsight processes are global constructors (e.g., `new PixelMath()`)
- Use `processEvents()` in loops to keep the GUI responsive
- `ExternalProcess` requires `processEvents()` polling for event handling
- `Timer` uses seconds (not milliseconds) for its interval
## Troubleshooting
### "Node.js not found"
Ensure Node.js >= 14 is installed and accessible. The script searches these locations:
- macOS/Linux: `which node`, `/usr/local/bin/node`, `/usr/bin/node`, `/opt/homebrew/bin/node`
- Windows: `where node`, `C:\Program Files\nodejs\node.exe`
### Server won't start
Check the PixInsight console (View > Process Console) for error messages. Common issues:
- Port already in use — change the port number
- File permissions — ensure the bridge server files are readable
### MCP client can't connect
- Verify the server is running (check `http://127.0.0.1:3189/health`)
- Ensure your MCP client config points to the correct endpoint
- The server only listens on `127.0.0.1` (localhost) — it's not accessible from other machines
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues