npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

diabetes-data-mcp

v1.1.0

Published

Mac Mini diabetes data plane: LAN-only Nightscout (LaunchAgents, loopback MongoDB), the Nightscout to SQLite sync, and a read-only bearer-token Streamable HTTP MCP over that archive

Readme

Diabetes Data MCP

the local diabetes data plane on the Mac Mini, as one product: Nightscout itself (moved off GCP gcns-vm, home network only), the Nightscout → SQLite sync, and a read-only MCP server over that SQLite archive. The same 8 tools are available to Grok Bot (Local Execution / Mini Shell), Claude Desktop, ChatGPT, and any other MCP client.

Published to npm as diabetes-data-mcp. The Mini runs the global npm install, never a git checkout: see Deploy on the Mini. Every command below uses PKG=~/.local/node/lib/node_modules/diabetes-data-mcp (the global install under the LaunchAgents' node).

Pieces

| Piece | What | LaunchAgent | | --- | --- | --- | | nightscout/diabetes-nightscout-server | Nightscout 15.0.7 on the home LAN, 0.0.0.0:8425. Dexcom Share bridge + tconnectsync feed it. See Nightscout on the Mini. | com.diabetes-nightscout.server — KeepAlive | | MongoDB 8.0 (nightscout/install-runtime.sh) | Nightscout's database, 127.0.0.1:27017 only. | com.diabetes-nightscout.mongod — KeepAlive | | tconnectsync/diabetes-tconnectsync | tconnectsync 3.0.3 (pinned venv): Tandem Source pump data → Nightscout. Logins from Keychain. | com.diabetes-tconnectsync.sync — hourly at :35 | | sync/diabetes-sqlite-sync | Nightscout entries + treatments → ~/.diabetes-data/diabetes.sqlite, then rebuilds daily_stats / weekly_stats. Sole writer. | com.diabetes-sqlite.sync — every minute (StartInterval=60) | | bin/diabetes-data-mcp.js serve | Streamable HTTP MCP, bearer token on every request including /health. Preferred port 8424. | com.diabetes-mcp.server — KeepAlive | | stdio | Same tools over stdio for Claude Desktop on the Mini. | — | | http-proxy <url> | stdio → HTTP bridge for Claude Desktop on another Mac. Token in DIABETES_DATA_MCP_TOKEN. | — | | http-token | Print the Keychain bearer token (creates it on first use). | — | | check-config | Print the resolved DB path, host, and preferred port. Binds nothing. | — |

Ports on the Mini: ResMed 8420, Apple Tools 8421, Network Tools 8422, SimpleFIN 8423, Diabetes MCP 8424, Diabetes Nightscout 8425. If 8424 is taken, serve binds the next free port above it and logs preferred port 8424 is in use; listening on http://<host>:<port>/mcp. Point clients at the logged URL.

Requires Node.js 22.5+ (node:sqlite, no native addon) and macOS /usr/bin/python3 (3.9+) for the sync.

Conventions

  • Timezone: America/Chicago. Every date_* argument is a local calendar day and every time_* is local HH:MM. Rows come back with ts (ISO UTC) and local (Chicago ISO with offset). DST days are 23 or 25 hours.
  • Time in range: 80–180 mg/dL only (tir_80_180, under_80 = below 80, over_180 = above 180, percent of readings). Never 70–180.
  • Weeks: Sunday–Saturday; week_ending is the Saturday.

Tools (V1, locked)

| Tool | Purpose | | --- | --- | | sync_status | last_sync_at / last_sync_mode from meta, hours since the last sync (stale after 1 h), row counts, earliest/latest SGV and treatments, daily/weekly span, schema_version, TIR band. URL/secret-like meta keys are hidden and URLs in values are redacted. | | list_sgv | Readings for date_from..date_to (≤ 31 days), optional time_from/time_to slice per day (wraps midnight when from > to), sample (every Nth), order, limit (default 1000, max 10000). raw_json only with include_raw. | | list_treatments | Treatments for date_from..date_to (≤ 366 days): created_at, local, event_type, insulin, carbs, duration_min, rate, percent, absolute, entered_by, notes. Filters: event_type (string or list, exact, case-insensitive), entered_by substring. include_raw for combo-bolus split details. | | get_daily_stats | daily_stats rows by date, date_from/date_to, or newest limit (default 14). | | get_weekly_stats | weekly_stats rows by week_ending, a week_ending range, or newest limit (default 8). Includes trend_note. | | get_range_stats | Computed stats for any window: days, optional per-day time_from/time_to, optional weekdays. Returns TIR/under/over, avg, SD, CV, min/max, sgv_count, hours_covered (distinct 5-minute slots) vs window_hours. include_insulin adds bolus / temp-basal / carbs totals for treatments in the same slice (temp basal = insulin, else rate × duration, not clipped to the slice; scheduled profile basal is not in the archive). | | get_coverage | Earliest/latest SGV and treatments; per local day in the window (default the whole SGV span) the days with no readings, days under low_threshold (default 200; a full day is ~288), days with readings but no daily_stats row; optional include_gaps with gap_minutes (default 30). | | query_raw | One read-only SELECT (or WITH … SELECT), capped at 1000 rows. Escape hatch. |

get_range_stats uses the same formulas as the sync's daily_stats (population SD, CV = SD / mean), so a whole-day range matches that day's rollup. The test suite checks this end to end.

Out of scope for V1: live Nightscout, the active profile (I:C, CF, basal schedule), pump settings math, Meals synthesis, profile history.

Read-only guarantee

The MCP opens SQLite with readOnly: true (SQLITE_OPEN_READONLY) and PRAGMA query_only = ON. Writes fail with attempt to write a readonly database. It does not create the file, run migrations, call Nightscout, or touch com.diabetes-sqlite.sync.

Schema (schema_version 1)

Same DDL as the Grok box archive (sync/sync_from_nightscout.py SCHEMA_SQL).

| Table | Columns | | --- | --- | | meta | key PK, value — schema_version, timezone, tir_low=80, tir_high=180, last_sync_at, last_sync_mode, last_sync_writer, path_note, … | | sgv | date_ms PK (UTC ms), date_string, sgv, direction, device, type, raw_json | | treatments | id PK, created_at (ISO UTC), timestamp_ms, event_type, insulin, carbs, duration_min, rate, percent, absolute, entered_by, notes, raw_json | | daily_stats | day PK (Chicago), tir_80_180, under_80, over_180, avg_mgdl, cv_pct, tdd_u, bolus_u, basal_u, sgv_count, source, updated_at | | weekly_stats | week_ending PK (Saturday), week_start, tir_80_180, under_80, over_180, avg_mgdl, cv_pct, tdd_u (mean per day), sgv_count, source, trend_note, updated_at |

Sync

sync/diabetes-sqlite-sync check    # credentials present? (no network, no DB write)
sync/diabetes-sqlite-sync sync     # entries + treatments + rollups (LaunchAgent default, every minute)
sync/diabetes-sqlite-sync backfill # one-off: full history from Nightscout, dedupe box-era ids, rebuild all rollups
sync/diabetes-sqlite-sync stats    # rebuild daily/weekly rollups only, no network

Credentials are never in git, config, or logs:

  1. Env NIGHTSCOUT_URL + NIGHTSCOUT_API_SECRET (one-off runs / tests)
  2. macOS Keychain service diabetes-sqlite, accounts nightscout-url and api-secret (the plaintext site API_SECRET; the sync sends its SHA-1 as the api-secret header)

Seed the Keychain on the Mini (keep the values out of shell history):

security add-generic-password -U -s diabetes-sqlite -a nightscout-url -w
security add-generic-password -U -s diabetes-sqlite -a api-secret -w

(-w last with no value prompts for it.) Missing credentials exit 2 before the database is opened or created. A Nightscout or network error exits 1; nothing from that run is committed. A second run while one is active prints SKIP: another sync already running (flock on ~/.diabetes-data/sync.lock). Logs: ~/Library/Logs/diabetes-sqlite.sync.{out,err}.log.

StartInterval=60 runs every minute. TZ=America/Chicago in the plist sets the sync's own date math.

A routine run asks Nightscout for the newest page of entries and treatments, stops as soon as it overlaps what is already stored, and recomputes daily_stats / weekly_stats only for the newest few days (DIABETES_SYNC_RECOMPUTE_DAYS, default 3). The first run of each local day recomputes everything, so a late edit to an older day is picked up within a day.

Two databases, on purpose

| | Nightscout's MongoDB | diabetes.sqlite | | --- | --- | --- | | Role | Live working store; the Dexcom bridge and tconnectsync write to it | Uniform analytics archive the MCP reads | | Access | 127.0.0.1:27017, no auth, owned by Nightscout's layout | Read-only to the MCP, Chicago-time days, TIR 80–180 rollups | | History | Dexcom + pump back to 2021-05-25 (treatments to 2023-01-01) | Everything Mongo has, after a backfill |

The MCP never reads Mongo. sync keeps SQLite current each minute. sync/diabetes-sqlite-sync backfill walks the whole Nightscout history into SQLite (commits per page, safe to interrupt and rerun), removes box-era rows whose synthesized id now exists under the real Nightscout id (otherwise insulin would double count), and rebuilds every daily/weekly rollup. Rows deleted from Nightscout are not deleted from SQLite (upsert-only).

Mini is the sole Nightscout→SQLite writer. Box /workspace/diabetes-db is legacy/fail-closed. The sync reads the Mini's own Nightscout: Keychain nightscout-url = http://127.0.0.1:8425.

Nightscout on the Mini

Dexcom Share ──(bridge, outbound)──┐
Tandem Source ──(tconnectsync)─────┴─► Nightscout :8425 ─► MongoDB 127.0.0.1:27017
                                            └─► com.diabetes-sqlite.sync ─► SQLite ─► MCP :8424

Upstream cgm-remote-monitor 15.0.7, downloaded and pinned, not forked or vendored (AGPL-3.0). Home network only: no public URL, port-forward, tunnel, or DNS (nsrange.mooo.com retired with gcns-vm). Dexcom and Tandem are outbound pulls; nothing on the internet connects in.

Who connects:

  • Grok Bot agents: Local Execution on the Mini → http://127.0.0.1:8425, like the other Mini services.
  • Devices at home: http://<LocalHostName>.local:8425.

Every request needs the site API secret (AUTH_DEFAULT_ROLES=denied); without it the API returns 401. Don't port-forward 8425 or 27017.

Secrets (Keychain only)

| Service / account | What | | --- | --- | | diabetes-sqlite / api-secret | Plaintext site API_SECRET. Nightscout reads it at launch; the sync and nightscout/prove.sh send its SHA-1. One item, so they can't drift. | | diabetes-nightscout / dexcom-username, dexcom-password | Dexcom Share login. Read only when BRIDGE_ENABLE=1. |

security add-generic-password -U -s diabetes-nightscout -a dexcom-username -w
security add-generic-password -U -s diabetes-nightscout -a dexcom-password -w

Dexcom Share: one poller only

Share allows one session per login, so two Nightscouts polling it duplicate or drop readings. The bridge is off by default. Turn it on only after every other Nightscout's bridge is off:

echo BRIDGE_ENABLE=1 >> ~/.diabetes-data/nightscout/config.env
launchctl kickstart -k gui/$(id -u)/com.diabetes-nightscout.server

tconnectsync (Tandem → Nightscout)

Runs tconnectsync --days 1 --features BASAL BOLUS PUMP_EVENTS PROFILES hourly at :35 against http://127.0.0.1:8425. It does not upload CGM; Dexcom comes through the bridge. Pinned to 3.0.3, which already sends eventCodes (Tandem rejects the old eventIds with HTTP 400). A true combo/extended bolus is written in the Care Portal shape (insulin = immediate U, enteredinsulin = total U, splitNow/splitExt %, duration min, relative extended U/h) by tconnectsync/combo_bolus.py, applied at run time through tconnectsync/diabetes_tconnectsync.py; nothing in site-packages is edited, and the hook refuses (with a loud WARNING) on any tconnectsync version other than 3.0.3. The later "Extended Bolus" completion entry is dropped so insulin is not double counted. diabetes-tconnectsync enrich START END [--apply] re-maps combos already in Nightscout (dry run by default; only replaces a combo whose old plain document exists, so it is safe to rerun).

| Keychain service / account | What | | --- | --- | | diabetes-tconnectsync / tconnect-email, tconnect-password, pump-serial-number | Tandem Source login and pump | | diabetes-sqlite / api-secret | Nightscout secret (shared) |

sh "$PKG/tconnectsync/install.sh"
"$PKG/tconnectsync/diabetes-tconnectsync" --pretend    # dry run: reads Tandem + Nightscout, uploads nothing
sh "$PKG/examples/install-launchagents.sh" "$(command -v node)" tconnectsync

Log: ~/Library/Logs/diabetes-tconnectsync.sync.log.

Install / update

sh "$PKG/nightscout/install-runtime.sh" "$(command -v node)"                 # Mongo + tools (sha256-pinned), Nightscout tag + npm ci
sh "$PKG/examples/install-launchagents.sh" "$(command -v node)" nightscout   # mongod + server agents
sh "$PKG/nightscout/prove.sh"                                                # read-only: bind, 401/200, newest SGV, counts

Optional non-secret overrides: ~/.diabetes-data/nightscout/config.env (see nightscout/config.env.example). Upgrading Nightscout = bump NS_TAG in nightscout/install-runtime.sh, rerun it, kickstart the server; the old version stays under runtime/ for rollback.

| Path | What | | --- | --- | | ~/.diabetes-data/nightscout/mongo/ | MongoDB data | | ~/.diabetes-data/nightscout/runtime/ | mongod, Database Tools, Nightscout checkout, cached downloads | | ~/Library/Logs/diabetes-nightscout.{server,mongod}.log | Logs |

Backup / restore (archives hold health data; *.archive.gz is git-ignored):

R=~/.diabetes-data/nightscout/runtime/mongotools/bin
$R/mongodump --host 127.0.0.1 --port 27017 --db Nightscout --gzip --archive=nightscout-$(date +%Y%m%d-%H%M).archive.gz
$R/mongorestore --host 127.0.0.1 --port 27017 --gzip --archive=<file> --nsInclude='Nightscout.*' --drop

Deploy on the Mini

The Mini runs the published npm package, installed globally under the node that the LaunchAgents use. Never point a LaunchAgent at ~/code/Diabetes-Data-MCP or a dig worktree; the checkout is for development and tests only.

NODE="$HOME/.local/node/bin/node"                 # the node the LaunchAgents run (same prefix as apple-tools-mcp)
PREFIX="$(dirname "$(dirname "$NODE")")"
"$PREFIX/bin/npm" install -g --prefix "$PREFIX" diabetes-data-mcp@<version>
PKG="$PREFIX/lib/node_modules/diabetes-data-mcp"
sh "$PKG/examples/install-launchagents.sh" "$NODE" all            # com.diabetes-mcp.server + com.diabetes-sqlite.sync
sh "$PKG/examples/install-launchagents.sh" "$NODE" nightscout     # com.diabetes-nightscout.mongod + .server
sh "$PKG/examples/install-launchagents.sh" "$NODE" tconnectsync   # com.diabetes-tconnectsync.sync
sh "$PKG/nightscout/prove.sh"

One time per machine (state lives in ~/.diabetes-data/ and survives package upgrades): sh "$PKG/nightscout/install-runtime.sh" "$NODE" and sh "$PKG/tconnectsync/install.sh".

Releases follow Development Team Rules → QA and npm Releases: bump the version in the PR (ask the maintainer for the number), merge, publish a GitHub Release vX.Y.Z, and .github/workflows/npm-publish.yml publishes via npm Trusted Publishing (OIDC, no tokens). Then on the Mini: the npm install -g --prefix line with @X.Y.Z, rerun the three installer lines above (paths do not change, so this just reloads), and run prove.sh. The very first publish (1.0.0) is a one-time manual npm publish by the maintainer in a local Terminal.

LaunchAgents do not load a login shell, so the installer writes the absolute node path into com.diabetes-mcp.server and com.diabetes-nightscout.server.

Server log: ~/Library/Logs/diabetes-data-mcp.server.log.

Keychain bearer token

Service diabetes-data-mcp-http, account http-auth-token. serve creates it on first start. Print it once on the Mini for client setup:

diabetes-data-mcp http-token

Never paste it into chat, Notion, or logs. Rotate: security delete-generic-password -s diabetes-data-mcp-http -a http-auth-token, kickstart the server, update clients. Client setup: examples/mcp-client.md.

Config

Optional ~/.diabetes-data-mcp/config.json (see examples/config.json.example). Env overrides the file; the file overrides defaults.

| Key / env | Default | | --- | --- | | dbPath / DIABETES_DATA_MCP_DB_PATH | ~/.diabetes-data/diabetes.sqlite (derived from the runtime home) | | serverHost / DIABETES_DATA_MCP_SERVER_HOST | 0.0.0.0 | | serverPort / DIABETES_DATA_MCP_SERVER_PORT | 8424 (preferred start) |

DIABETES_DATA_MCP_HOME relocates the config directory (tests only).

Develop

npm install
npm test          # vitest: tools, time math, HTTP auth, and a fake-Nightscout end-to-end sync
npm run typecheck

Persistent database setting

The default archive is .diabetes-data/diabetes.sqlite under the runtime user's home. For a different archive, enter its absolute path once as dbPath in ~/.diabetes-data-mcp/config.json (mode 0600, directory mode 0700). Existing local config survives npm upgrades. Environment overrides the file; the file overrides the home-derived default. No deploy-time path entry is needed. The MCP always opens the archive read-only; the existing sync job remains its sole writer. The example config omits dbPath to keep the portable default.

Privacy gates

Install Gitleaks 8.30.1 and enable the staged gate once per clone:

git config core.hooksPath .githooks
gitleaks git --log-opts=--all --config .gitleaks.toml --redact=100 --no-banner .
npm run build && npm run scan:package

Push and pull-request CI scans full fetched history and the exact npm package file list. Release CI scans history and prepublishOnly rebuilds and scans the package before OIDC publication. Tests use synthetic Patient A fixtures. Keep real paths and people solely in local settings, and secrets in Keychain. After a history rewrite, discard old clones and re-clone so removed history is not restored by an old branch.