status.bobsmcp.uk since 2026-07-11. It runs as a second, independent Docker Compose project on the existing broker VM (no new compute cost) and is gated by Cloudflare Access to Bob's email alone. Deliberately not wired through the MCP broker — a headless poller calls provider REST APIs directly and writes a sanitized snapshot the static page reads.
Key points
- Two processes, no new ports. A Python poller (no listening port) writes
snapshot.json; an nginx container serves the static site + snapshot on127.0.0.1:8080only. Public reach is via the existing outbound Cloudflare Tunnel — the deny-all firewall is unchanged. - Keyless identity. The poller impersonates a dedicated, read-only
mcp-status-poller-sa(viamcp-broker-sa's metadata identity + the IAM Credentials API) — no downloadable key exists (the org enforcesdisableServiceAccountKeyCreation). The poller SA has zero compute write verbs, strictly weaker than the broker's ownmcpBrokerOps. - Sources (one module each, own cadence): GCP compute/logging (5 min), GCP billing month-to-date (6 h, BigQuery export), Tailscale devices, GitHub + GitLab activity, Cloudflare health, Notion recent edits (5 min), Adzuna roles (30 min, free-tier rate limit).
- Leakage guard is real, not cosmetic. Every source returns an allow-listed
dict (e.g. Tailscale emits only name/os/online/last-seen — never IPs or node
keys; billing is a single cost sum, no row detail or account IDs);
snapshot.schema.json(additionalProperties: falsethroughout) + a test that injects a fakeservice_account_keyand asserts rejection fail the build if any field ever leaks. - Frontend is inert + hardened. Vanilla HTML/CSS/JS, no build step; untrusted
values rendered via
textContent, links regex-guarded tohttp(s)://. nginx sends a strict CSP +nosniff+no-referrer+frame-ancestors 'none'.
Access & data path
Browser → Cloudflare Access (email OTP) → Cloudflare Tunnel → nginx
127.0.0.1:8080 → static page → fetches /data/snapshot.json. The browser never
holds a credential; it only ever reads the pre-built, schema-validated snapshot.
See gcp-mcp-standalone/network-access for how this sits alongside the broker's
paths.
Details
Source: this repo (status-dashboard/poller/, status-dashboard/site/), deployed
by ansible/status-dashboard.yml as its own compose project. Security reviewed
and live-verified twice (docs/security-review-2026-07-10-status-dashboard.md;
folded into gcp-mcp-standalone/security-review). Phase 2 (AWS/"lifebot" cost +
EC2 panel) is deferred — the schema and frontend are already structured for it.
Related
Sources
wiki/projects/gcp-mcp-standalone/status-dashboard.md · git is the source of truth