Metadata-Version: 2.4
Name: erdos-renyi
Version: 0.1.1
Summary: MCP connector: run Erdos queries on Reyni-registered EHR exports.
Author-email: Krv Labs <team@krv.ai>
License: Apache-2.0
Requires-Python: <3.15,>=3.11
Description-Content-Type: text/markdown
Requires-Dist: fastmcp>=2.0
Requires-Dist: polars>=1.0.0
Requires-Dist: sqlglot>=23.0.0
Requires-Dist: marimo>=0.8.0
Requires-Dist: pyarrow>=15.0.0
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest>=8.3; extra == "dev"
Requires-Dist: ruff>=0.9; extra == "dev"

# erdos-renyi

`erdos-renyi` is an MCP server providing the privacy-preserving handshake between Erdos and Reyni. Clinicians register fine-grained EHR cohort exports with Reyni, and agents rewrite Erdos predictive SQL queries against tokenized schema names (`tok_…`) without ever accessing raw cell values or PHI. Results are staged locally in Arrow IPC format, gated by k-anonymity for agent-visible counts, and rendered in a private localhost Marimo dashboard for clinician review.

## Quickstart

```bash
# Install dependencies
uv sync --extra dev

# Run test suite
uv run pytest

# Run the MCP server over stdio
uv run er-mcp
```

## Reyni Gateway Setup

Add `erdos-renyi` to `~/Library/Application Support/reyni/servers.toml` (Windows: `%APPDATA%\reyni\servers.toml`):

```toml
[[server]]
name       = "erdos"
launch     = ["uv", "tool", "run", "--python", "3.12", "--from", "erdos-renyi", "er-mcp"]
phi_access = true
```

During local development, point `--from` to the local repository path:

```toml
[[server]]
name       = "erdos"
launch     = ["uv", "tool", "run", "--python", "3.12", "--from", "/path/to/erdos-renyi", "er-mcp"]
phi_access = true
```

Agent-visible Erdos tools: `erdos__get_schema`, `erdos__stage_query`. After staging, call `reyni__register_dashboard` (Reyni gateway). `launch_dashboard` is gateway-internal only.

## Agent Workflow

1. **`reyni__list_datasets`**: Obtain the `safe_path` for the tokenized twin export.
2. **`erdos__get_schema(safe_path)`**: Inspect column names and data types (no row values or samples).
3. **Rewrite SQL**: Adapt the Erdos predictive query to target the local schema. The table name in Polars SQL is always **`cohort`**.
4. **`erdos__stage_query(safe_path, sql)`**: Sanitize and execute SQL. If the match count is below the k-anonymity threshold ($k < 5$), the exact count is withheld (`below_threshold`), but the session is staged for the clinician.
5. **`reyni__register_dashboard(session_id)`**: Reyni launches the Marimo dashboard internally, reads a clinician-only sidecar (`session_{id}.launch.json`), and stores the URL encrypted — the agent receives only a `dashboard_ref`.

## Security Guarantees

- **Zero cell egress**: MCP tools only return column metadata and aggregate match counts.
- **SQL Sanitization**: Enforces read-only `SELECT` queries, rejects external filesystem functions (`read_csv`, `eval`), and clamps `LIMIT` to 1000 rows.
- **Localhost Enclave**: Staging files use Arrow IPC; dashboards bind to `127.0.0.1`. Launch URLs are written to mode-`0600` sidecars, not returned over MCP.
