Skip to main content

EpiDash

CI Codecov PyPI Python 3.12+ License: MIT

A light, MCP-controlled dashboard service. EpidBot (and any MCP client holding a control key) builds, updates, publishes and unpublishes dashboards through an MCP tool surface; anyone with a dashboard link views it in a minimal web UI. Viewers can ask EpidBot to tweak a dashboard from the browser.

Live instance: https://dash.kwar-ai.com.br

EpidBot agent ──(MCP client, dk_ key)──▶ EpiDash /mcp (FastMCP tools)
                                            │
                       SQLite ◀─────────────┤ (dashboards, charts, keys, audit)
                                            │
Viewer browser ──(public link)──▶ EpiDash / (vanilla JS + Plotly)
      │                                 │
      └── tweak request ──▶ POST /api/dashboards/{slug}/tweak
                                 │  (X-Internal-Request: shared secret)
                                 ▼
                           EpidBot /api/v1/chat ──agent──▶ EpiDash MCP tools

Quick start

uv sync
uv run uvicorn epidash.main:app --port 8000

Then issue a control key and talk to the MCP endpoint:

uv run python -m epidash.cli add-key "local"
# → dk_...  (shown once)
# The MCP endpoint is stateless: one POST per call, no handshake needed.
curl -s -X POST http://localhost:8000/mcp \
  -H "X-API-Key: dk_..." -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

In an MCP client (e.g. Claude Desktop, Cursor, EpidBot):

{
  "mcpServers": {
    "epidash": {
      "url": "http://localhost:8000/mcp",
      "headers": { "X-API-Key": "dk_..." }
    }
  }
}

Configuration (environment variables)

Variable Default Purpose
EPIDASH_DB_PATH data/epidash.db SQLite file (WAL)
EPIDASH_BASE_URL http://localhost:8000 Public base URL for share links
EPIDASH_MCP_PATH /mcp Mount path of the MCP endpoint
EPIDASH_ALLOWED_HOSTS localhost,127.0.0.1 Host header allowlist (DNS-rebinding protection)
EPIDASH_BOOTSTRAP_KEY — Pre-shared dk_ key seeded at startup (infra automation)
EPIDBOT_BASE_URL — EpidBot base URL; enables the tweak flow
EPIDBOT_INTERNAL_SECRET — Shared secret (EpidBot INTERNAL_API_SECRET) or ek_ API key
EPIDASH_TWEAK_RATE_LIMIT_PER_HOUR 20 Per-dashboard viewer tweak budget
EPIDASH_ASK_RATE_LIMIT_PER_HOUR 30 Per-dashboard viewer question budget
EPIDASH_TWEAK_TIMEOUT_S 300 Max wait for an EpidBot tweak turn

MCP tools

Read-only: list_dashboards, get_dashboard, get_view_stats, get_audit_log (filterable by action and dashboard_id).

Mutations (audited): create_dashboard, update_dashboard, publish_dashboard (confirm), unpublish_dashboard (confirm), delete_dashboard (confirm), add_chart, update_chart, remove_chart (confirm), duplicate_dashboard, style_charts.

Live data sources

Charts can auto-update from a remote URL instead of holding a static snapshot. attach_data_source(chart_id, kind, url, refresh_interval_s=300, path=None) attaches a source:

kind payload
url_json the chart's data envelope itself ({"columns": ..., "rows": ...}); path optionally extracts a nested object (dotted keys, e.g. "result.week")
url_csv header row + data rows (numeric cells auto-converted); feeds line/bar/pie/table charts

A background refresher fetches due sources every 30s (minimum interval 30s) and replaces the chart's data on success — viewers pick the change up on their next poll, and chart cards show an ⇣ auto badge with refresh status. Failures never lose existing data; inspect them with get_data_source(chart_id), force a run with refresh_data_source, or stop with remove_data_source (confirm).

Chart data envelopes

kind data
line, bar, pie, table {"columns": ["month", "cases"], "rows": [["Jan", 120], ...]}
kpi {"value": 1234, "label": "Cases", "unit": "", "delta": "+12%"}
choropleth {"values": {"SP": 120, "RJ": 90}, "region_level": "uf", "label": "cases"}

spec accepts style overrides ({"color": "#4ade80"}, {"y_label": "cases"}) and position controls ordering/width ({"order": 1, "width": "half"}).

Viewer tweak flow

A viewer types a request ("show only the Southeast after 2020") into the dashboard's chat box. EpiDash forwards it as an EpidBot chat turn with the dashboard context; the EpidBot agent uses its EpiDash MCP tools to update the charts; the viewer's browser picks up the change on its next poll.

Viewers can also ask questions ("why did cases spike in March?") via the Ask button — the same chat pipeline, but the prompt instructs EpidBot to answer from the dashboard data without modifying it. No authentication is required for either; questions are recorded in the tweaks table with kind='question' and rate-limited separately from tweaks.

Requires EPIDBOT_BASE_URL + EPIDBOT_INTERNAL_SECRET (EpidBot must accept X-Internal-Request on its chat endpoint — see the EpidBot-side integration docs) or an ek_ API key.

Deployment

Single container, single volume:

docker compose up -d --build

Production (KwarAI) deploys this via the Ansible epidash role behind nginx at dash.kwar-ai.com.br — see the infrastructure repo.

Development

uv sync                  # deps
uv run pytest -v         # tests
uv run ty check epidash/ # type check

Browser end-to-end tests (headless chromium):

uv sync --group e2e
uv run playwright install chromium
uv run pytest tests_e2e -m e2e -v

License

MIT

Metadata

Release files for epidash 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for epidash 0.3.0
File Size Uploaded Provenance
epidash-0.3.0.tar.gz 1.8 MB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for epidash 0.3.0
File Interpreter ABI Platform
epidash-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 3.6 MB

Release files / epidash-0.3.0.tar.gz

Download URL epidash-0.3.0.tar.gz
Size 1.8 MB
Tags Source
SHA-256 checksum
How to use checksums
0e106a4c250ff5c177920122ff6c82beb1fb5094b750983c50cbaff648105d65
BLAKE2b-256 checksum
How to use checksums
c429434b92f69352313ed8fc19559130d8889c78b7c6b13341a7fc20038a8059
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / epidash-0.3.0-py3-none-any.whl

Download URL epidash-0.3.0-py3-none-any.whl
Size 1.7 MB
Tags Python 3
SHA-256 checksum
How to use checksums
8fc0f3e0442e28429c07dd281cbc0eca5c5304c74087398c09efcfa40bdaee4e
BLAKE2b-256 checksum
How to use checksums
babb93308cd2d1ca0a12a00b0eee69ffaa0aaaf54d7f3a044402ba2cede5c223
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for epidash 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for epidash-0.3.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page