ena-mcp
by Ian3738
README.md
# ena-mcp
An [MCP](https://modelcontextprotocol.io) server that lets an AI assistant drive
**Epistemic Network Analysis** models hosted on the webENA cloud service
(`app.epistemicnetwork.org`).
Models are computed by webENA's own **R / OpenCPU + rENA** backend, so the numbers
are canonical rENA output — this is not a reimplementation or an approximation.
The server handles transport, decoding, and presentation.
繁體中文說明:[README.zh-TW.md](README.zh-TW.md)
---
## What it does
Once connected, an assistant can list your ENA projects, inspect a set's column
roles and algorithm parameters, run the model, and get back per-unit ENA scores,
edge weights, node positions, variance explained, eigenvalues, the rotation
matrix, and goodness-of-fit correlations — then plot networks, sweep the stanza
window, run group statistics, and pull the raw discourse behind any connection.
Protocol details are documented in [docs/PROTOCOL.md](docs/PROTOCOL.md), derived
from observed traffic against a live account.
> **Unofficial.** This project is not affiliated with, endorsed by, or supported
> by the Epistemic Analytics Lab or UW–Madison. It talks to a private API that
> carries no compatibility guarantee. See [Limitations](#limitations).
---
## Install
```bash
git clone https://github.com/Ian3738/ena-mcp.git
cd ena-mcp
npm install && npm run build
```
Requires Node.js 20 or newer.
## Authentication
webENA authenticates with an **HttpOnly session cookie**. There is no API token,
and the login endpoint is not part of the app bundle, so the cookie has to be
copied manually once. Accounts registered through Google SSO cannot use
programmatic username/password login at all.
1. Sign in at `https://app.epistemicnetwork.org`
2. Open DevTools → **Application** → Cookies → `app.epistemicnetwork.org`
3. Copy the session cookie as `name=value` (e.g. `connect.sid=s%3A…`)
4. Store it:
```bash
mkdir -p ~/.ena-mcp && chmod 700 ~/.ena-mcp
printf '%s' 'connect.sid=PASTE_HERE' > ~/.ena-mcp/cookie
chmod 600 ~/.ena-mcp/cookie
```
Alternatives: set `ENA_SESSION_COOKIE` directly, or point
`ENA_SESSION_COOKIE_FILE` at another path.
The cookie expires. When it does, every tool returns the same actionable error —
fetch a fresh one. The cookie value is redacted from all tool output before it
leaves the process.
## Verify
```bash
npm run smoke
```
Checks the cookie, lists projects, and opens the socket.io connection. To run a
model end to end:
```bash
npm run smoke -- --set "<setID>" --project "<projectName>"
```
## Connect an MCP client
Add to `claude_desktop_config.json` (or any MCP client's server config):
```json
{
"mcpServers": {
"ena": {
"command": "node",
"args": ["/absolute/path/to/ena-mcp/dist/src/index.js"],
"env": { "ENA_SESSION_COOKIE_FILE": "/Users/you/.ena-mcp/cookie" }
}
}
}
```
### Configuration
| Variable | Default | Purpose |
|---|---|---|
| `ENA_SESSION_COOKIE` | — | Session cookie value |
| `ENA_SESSION_COOKIE_FILE` | `~/.ena-mcp/cookie` | File containing it |
| `ENA_ORIGIN` | `https://app.epistemicnetwork.org` | Server origin |
| `ENA_TIMEOUT_MS` | `360000` | Request timeout (matches the server's own 6-minute watchdog) |
---
## Tools
### Session and browsing
| Tool | Purpose |
|---|---|
| `ena_check_session` | Validate the cookie and list projects. **Run this first** |
| `ena_get_project` | Folders, uploaded data files, and sets inside a project |
| `ena_get_set` | Column roles and algorithm parameters, without computing |
### Modelling
| Tool | Purpose |
|---|---|
| `ena_run_model` | **Core.** Returns per-unit ENA scores, edge weights, node positions, variance explained, eigenvalues, rotation matrix, goodness of fit. Algorithm parameters can be overridden per run |
| `ena_sweep_window` | Run across several moving-window sizes and compare variance explained and GOF — for justifying a window choice |
| `ena_optimal_window` | The server's recommended window size |
| `ena_get_correlations` | Co-registration correlations (reviewers expect these reported) |
| `ena_get_methods` | webENA's auto-generated Methods paragraph for the current model |
### Data and qualitative evidence
| Tool | Purpose |
|---|---|
| `ena_get_data` | The raw CSV behind a set — for reading utterances, checking coding, pulling quotes |
| `ena_get_conversation` | The discourse rows behind a selected connection |
### Statistics and visualization
| Tool | Purpose |
|---|---|
| `ena_compare_groups` | Between-group test (Mann-Whitney U / t-test) |
| `ena_plot_network` | ENA network as SVG |
| `ena_plot_subtraction` | Between-group subtraction network as SVG |
A typical flow:
```
ena_check_session → ena_get_project → ena_get_set
→ ena_run_model → ena_plot_network / ena_compare_groups
→ ena_get_data (quotes) → ena_get_methods (write-up)
```
Model results are cached per set for the session, so plotting and comparison do
not re-run the model.
---
## Limitations
**1. Parameters yes, selections no.**
`/set/generate` strips `selections`
(`ENA.getSaveableSet = set => _.omit(set, "selections", "set")`) and the server
resolves them from the persisted `selectionsRef`. Therefore:
- ✅ **Algorithm parameters** (`stanzaSize`, `stanza`, `sphereNorm`, `centerZero`, `ordered`) take effect directly
- ❌ **Which individual units / conversations / codes are selected** requires
`/set/save-model` plus a rebuilt selection tree — effectively reproducing two
browser web workers. Change selections in the web UI, then run the model here.
**2. This is a private API.** webENA publishes no API contract. A release can
break this server without warning. `docs/PROTOCOL.md` records what was observed
so the differences can be re-derived.
**3. Data leaves the machine.** Every model run computes discourse on
UW–Madison's servers. The data already lives there, but for human-subjects work
under an ethics protocol this belongs in the risk assessment.
**4. Cookies expire** and must be refreshed by hand.
---
## Alternative
rENA's CRAN maintainer publishes
[`@qe-mcp/server-ena`](https://www.npmjs.com/package/@qe-mcp/server-ena), which
runs ENA **locally** via WASM and installs as a one-click `.mcpb`.
The two do not overlap:
| | ena-mcp | `@qe-mcp/server-ena` |
|---|---|---|
| Existing sets in a webENA account | ✅ read and model | ❌ not visible |
| Offline / data stays local | ❌ | ✅ |
| Change individual unit/code selections | ❌ | ✅ |
| API stability | reverse-engineered | package-versioned |
Installing both is reasonable: this one to work with existing cloud projects,
the official one for local exploration and CSV experiments.
---
## Development
```bash
npm run build # compile
npm test # decoder tests (13)
npm run dev # watch mode
```
## License
MIT — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues