# MCP HTTP quick how-to (imagej-elphel)

This is a minimal HTTP interface for interacting with the GUI logic without blocking dialogs.
The MCP server runs **inside the ImageJ JVM**, so it starts/stops with the plugin.

## Start
The server auto-starts when `Eyesis_Correction` runs.

Default:
- URL: `http://127.0.0.1:48888`

Lifecycle helper script:
- `scripts/eyesis_mcp_ctl.sh` can manage process lifecycle from terminal:
  - `start` / `stop` / `restart` / `status` / `logs` / `wait`
  - example:
    ```bash
    /home/elphel/git/imagej-elphel/scripts/eyesis_mcp_ctl.sh start \
      --configdir /media/elphel/btrfs-data/lwir16-proc/NC/config --rebuild
    ```
  - by default it uses the same VM settings as the Eclipse run profile from `AGENTS.md`
    and waits for MCP readiness.

Host daemon mode (recommended for no-repeat approvals):
- `scripts/eyesis_host_daemon_ctl.sh start` starts a queue-based host daemon in your desktop session.
- `scripts/eyesis_host_submit.sh ctl ...` and `scripts/eyesis_host_submit.sh mcp ...` submit requests through that daemon.
- details: `scripts/eyesis-host-daemon-howto.md`.

Optional JVM system properties:
- `-Delphel.mcp.port=PORT` (override port, default 48888)
- `-Delphel.mcp.mode=true|false` (enable/disable MCP dialog mode; default true)
- `-Delphel.mcp.dialogTimeoutMs=30000` (MCP dialog submit wait; 0 = wait forever)
- `-Delphel.slf4j.level=ERROR|WARN|INFO|DEBUG|TRACE` (override SLF4J/logback + JUL root level to reduce OME/Bio-Formats noise)
- `-Delphel.mcp.allowed.config=/path/to/config.corr-xml` (enable MCP file access rooted from list in config)
- `-Delphel.mcp.allowed.configdir=/path/to/configs` (allow any `*.corr-xml` in this directory)
- `-Delphel.mcp.allowed.extra=/path/a,/path/b` (comma/semicolon-separated extra allowed roots)

If `mcp.mode=false`, dialogs behave normally (GUI dialogs appear).

## Endpoints

### 1) Status
```
curl http://127.0.0.1:48888/mcp/status
```
Response (example):
```
{"running":false,"stopRequested":0,"confirmPending":false,"confirmConvenient":false,"buttonLabel":""}
```

### 2) Current dialog schema
```
curl http://127.0.0.1:48888/mcp/dialog
```
Response (example):
```
{"ok":true,"dialog":{"id":"...","title":"Set CLT parameters","fields":[...]} }
```
Each field includes:
- `type`: message | boolean | number | string | choice
- `label`: dialog label string
- `tab`: tab name
- `tooltip`: original tooltip
- `units`: numeric units (if any)
- `default`: default value as string
- `choices`: for choice fields

### 3) Set a dialog value
Set by **label** (labels must match exactly):
```
curl -X POST -d "label=Nominal (rectilinear) disparity between side of square cameras (pix)&value=12.5" \
  http://127.0.0.1:48888/mcp/dialog/values
```
Notes:
- Values are strings; numeric/boolean are parsed by the code.
- For choice fields, `value` can be an index (`0`, `1`, ...) or the exact choice text.
- If you open multiple dialogs, include the dialog `id` from `/mcp/dialog` to avoid cross-talk.

### 3b) Submit dialog (MCP “OK/Cancel”)
After setting values, submit the dialog:
```
curl -X POST -d "ok=1" http://127.0.0.1:48888/mcp/dialog/submit
```
Use `ok=0` to cancel.

With dialog id:
```
curl -X POST -d "id=...&ok=1" http://127.0.0.1:48888/mcp/dialog/submit
```

### 3a) MCP file selection (Restore/Save)
Some file pickers use MCP instead of the Swing file chooser when MCP mode is enabled. In that case a single string field
is exposed via `/mcp/dialog` with label `Selected path`. Provide it like this:
```
curl -X POST -d "label=Selected path&value=/path/to/file.corr-xml" \
  http://127.0.0.1:48888/mcp/dialog/values
```

For multi-select pickers, the field label is `Selected paths`. Use comma or newline separated paths:
```
curl -X POST -d "label=Selected paths&value=/path/a.tif,/path/b.tif" \
  http://127.0.0.1:48888/mcp/dialog/values
```

### 4) Trigger any button
```
curl -X POST -d "label=Setup CLT parameters" http://127.0.0.1:48888/mcp/button
```
This uses the same label as the GUI button.

### 5) Interrupt long-running commands
Request a stop (confirm=1 means pause and wait for confirmation):
```
curl -X POST -d "confirm=1&asap=0" http://127.0.0.1:48888/mcp/interrupt
```

Confirm or cancel a pending stop:
```
curl -X POST -d "stop=1" http://127.0.0.1:48888/mcp/interrupt/confirm
curl -X POST -d "stop=0" http://127.0.0.1:48888/mcp/interrupt/confirm
```

### 6) Read-only file access (allowed roots only)
Get allowed roots:
```
curl "http://127.0.0.1:48888/mcp/fs/roots"
```

List directory:
```
curl "http://127.0.0.1:48888/mcp/fs/list?path=/media/elphel/btrfs-data/lwir16-proc/NC"
```

Read file slice:
```
curl "http://127.0.0.1:48888/mcp/fs/read?path=/path/to/file.log&offset=0&maxBytes=16384"
```

Head/tail:
```
curl "http://127.0.0.1:48888/mcp/fs/head?path=/path/to/file.log&lines=50"
curl "http://127.0.0.1:48888/mcp/fs/tail?path=/path/to/file.log&lines=50"
```

Glob (within allowed roots):
```
curl "http://127.0.0.1:48888/mcp/fs/glob?pattern=**/*-SYSTEM_OUT.log&max=200"
```

Read a single column from a delimited file (1-based column index, default tab):
```
curl "http://127.0.0.1:48888/mcp/fs/csvcol?path=/path/to/file.csv&col=3"
curl "http://127.0.0.1:48888/mcp/fs/csvcol?path=/path/to/file.csv&col=3&sep=,"
```

### 7) RAG query (local index)
Query the local RAG index built by `scripts/rag_index.py`.

Query parameters:
- `text` (required): query string
- `topK` (optional): number of results (default 5)

```
curl "http://127.0.0.1:48888/mcp/rag/query?text=Explain%20differential%20rectification&topK=5"
```

RAG root path (optional, for non-standard checkouts):
```
-Delphel.rag.root=/home/elphel/wksp2/imagej-elphel
```

Example (config directory):
```
-Delphel.mcp.allowed.configdir=/media/elphel/btrfs-data/lwir16-proc/NC/config
```

Note: list parsing currently calls `getSourceSets(...)`, which has `mkdirs()` side-effects (marked with `// codex 2026-01-28`).
If you want MCP to be strictly read-only, consider removing or guarding those `mkdirs()` calls.

## Behavior notes
- MCP dialogs **do not block** in this version. If MCP doesn’t set a value, defaults are used.
- `Abort` and `Stop` labels are handled specially (set stopRequested).

## Troubleshooting
- If a dialog field isn’t found, check the exact label in `/mcp/dialog` output.
- If the server doesn’t respond, verify the plugin is running and the port is open.
- MCP startup log line `MCP: local-only (no reverse SSH tunnel detected; see mcp-remote-ssh-tunnel.md)` indicates a reverse tunnel is not running.

## Forward plan (single host → multi-host)
- **Single host first**: keep MCP local and use it to supervise runs and inspect outputs.
- **Health checks**: add a small run‑state file (timestamp, last scene, ok/error) and/or MCP status summary.
- **Work units**: define a scene‑level boundary so each unit is independent and outputs don’t conflict.
- **Idempotent commands**: prefer “process scene X with config Y” so retries are safe.
- **Distributed later**: add a lightweight work queue or task‑stealing in the program; MCP stays for monitoring each host.
- **Supervision**: codex can watch CSV/log indicators and stop/restart on anomalies.

## Notes: mkdirs side-effects in list parsing
`EyesisCorrectionParameters.CorrectionParameters.getSourceSets(...)` creates directories as part of parsing.
These calls were marked with `// codex 2026-01-28`:
- `rootDirectory` resolved base dir `mkdirs()`
- `sourceDirectory` `mkdirs()`
- per-`KEY_DIRS` (linkedModels, linkedCenters, videoDirectory, x3dDirectory, resultsDirectory, cuasSeedDir) `mkdirs()`

If you want to remove side-effects for MCP-only parsing, consider guarding or removing those `mkdirs()` calls.

## Quick test sequence (minimal MCP flow)

1) **Start in MCP mode**
   - In Eclipse VM args, remove `-Delphel.mcp.mode=false` (or set `-Delphel.mcp.mode=true`).

2) **Check server is up**
```
curl http://127.0.0.1:48888/mcp/status
```

3) **Trigger a dialog**
   Use MCP to click a button that normally opens a dialog (example):
```
curl -X POST -d "label=Setup CLT parameters" http://127.0.0.1:48888/mcp/button
```
   In MCP mode, no GUI dialog appears; schema should be published.

4) **Fetch dialog schema**
```
curl http://127.0.0.1:48888/mcp/dialog
```

5) **Set a value by label**
```
curl -X POST -d "label=Nominal (rectilinear) disparity between side of square cameras (pix)&value=12.5" \
  http://127.0.0.1:48888/mcp/dialog/values
```

6) **Run a command**
```
curl -X POST -d "label=CLT batch process" http://127.0.0.1:48888/mcp/button
```

If a value does not take, re-check exact label text via `/mcp/dialog`.
- `-Delphel.ome.singleton=true|false` (toggle OMEXMLService singleton reuse; default false)
