diff --git a/docs/ANALYTICS_MCP.html b/docs/ANALYTICS_MCP.html index 939be71..34f5f1c 100644 --- a/docs/ANALYTICS_MCP.html +++ b/docs/ANALYTICS_MCP.html @@ -32,7 +32,7 @@ ul.chk li:before{content:"☐";position:absolute;left:0;color:var(--mut)}

Read-only Analytics MCP Server

-

Implementation guide · standalone repo fleetanalytics_mcp, hosted on the tracksolid_db Coolify host · 2026-06-16 · built — pending deploy

+

Implementation guide · standalone repo fleetanalytics_mcp, hosted on the tracksolid_db Coolify host · updated 2026-06-17 · deployed & live

1. Purpose & context

The decision & analytics team needs to pull fleet reporting data (fuel, utilisation, @@ -62,7 +62,7 @@ SQL guard in the query tool.

analytics_mcpuvicorn :8892 · coolify net
role = analytics_ro · READ ONLY
-
timescale_db:5432tracksolid_db
reporting.* · tracksolid.*
+
timescale_db:5432tracksolid_db
reporting.* · tracksolid.* · tickets.* · fuel.*

Ports in use: 8890 prod dashboard_api · 8891 staging dashboard_api · 8892 analytics_mcp.

@@ -92,15 +92,23 @@ superuser (it does CREATE ROLE), with the password supplied as ALTER ROLE analytics_ro WITH LOGIN PASSWORD :'ro_pw'; GRANT CONNECT ON DATABASE tracksolid_db TO analytics_ro; -GRANT USAGE ON SCHEMA reporting, tracksolid TO analytics_ro; +GRANT USAGE ON SCHEMA reporting, tracksolid, tickets, fuel TO analytics_ro; GRANT SELECT ON ALL TABLES IN SCHEMA reporting TO analytics_ro; -- tables + views GRANT SELECT ON ALL TABLES IN SCHEMA tracksolid TO analytics_ro; +GRANT SELECT ON ALL TABLES IN SCHEMA tickets TO analytics_ro; -- INC/CRQ tickets +GRANT SELECT ON ALL TABLES IN SCHEMA fuel TO analytics_ro; -- fuel GRANT SELECT ON reporting.v_trips TO analytics_ro; -- matview (not in ALL TABLES) GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA reporting TO analytics_ro; --- future objects auto-grant +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA tickets TO analytics_ro; +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA fuel TO analytics_ro; +-- future objects auto-grant; key to the OWNER role (postgres for tickets/fuel) ALTER DEFAULT PRIVILEGES FOR ROLE tracksolid_owner IN SCHEMA reporting GRANT SELECT ON TABLES TO analytics_ro; ALTER DEFAULT PRIVILEGES FOR ROLE tracksolid_owner IN SCHEMA tracksolid GRANT SELECT ON TABLES TO analytics_ro; ALTER DEFAULT PRIVILEGES FOR ROLE tracksolid_owner IN SCHEMA reporting GRANT EXECUTE ON FUNCTIONS TO analytics_ro; +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA tickets GRANT SELECT ON TABLES TO analytics_ro; +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA fuel GRANT SELECT ON TABLES TO analytics_ro; +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA tickets GRANT EXECUTE ON FUNCTIONS TO analytics_ro; +ALTER DEFAULT PRIVILEGES FOR ROLE postgres IN SCHEMA fuel GRANT EXECUTE ON FUNCTIONS TO analytics_ro; -- extra hardening over dashboard_ro: this role serves ad-hoc HUMAN queries ALTER ROLE analytics_ro SET default_transaction_read_only = on; ALTER ROLE analytics_ro SET statement_timeout = '30s'; @@ -118,7 +126,7 @@ Tracksolid ingestion secrets, which this read-only server has no business holdin - + @@ -156,6 +164,30 @@ Flask-style @app.route decorator — verified against the installed
Full, current source is the repo's analytics_mcp.py; the excerpt above is abridged.
+

4.1 Readable data surface

+

analytics_ro (and the helper tools, via READABLE_SCHEMAS, default +reporting,tracksolid,tickets,fuel, override with env MCP_READABLE_SCHEMAS) +can read:

+
ToolPurpose
query(sql, max_rows=1000)guarded read-only SELECT/WITH; single statement, keyword-blocked, auto-LIMIT; returns rows + truncated flag
list_schemas()readable schemas (reporting, tracksolid) + object counts
list_schemas()readable schemas (reporting, tracksolid, tickets, fuel) + object counts
list_tables(schema)tables + views in a schema
describe_table(schema, table)columns, types, nullability, defaults
list_functions(schema='reporting')reporting.fn_* signatures
+ + + + + +
SchemaOwnerWhat's there
reportingtracksolid_ownercurated views/matviews (v_daily_summary, v_trips, v_monthly_cost_centre, …) + fn_* functions
tracksolidtracksolid_ownerraw ingestion tables (devices, positions, events, …)
ticketspostgresINC/CRQ tickets: inc, crq, closure_events, inc_daily_snapshot, geo_clusters, geo_locations, inc_open_sla (view) + 7 functions
fuelpostgresrecords, ingest_state + 7 functions
+

Adding a schema later is config-only: GRANT USAGE/SELECT/EXECUTE … to +analytics_ro (persist in analytics_ro_role.sql), then add it to +MCP_READABLE_SCHEMAS and redeploy — no code change.

+
Owner gotcha. ALTER DEFAULT PRIVILEGES FOR ROLE … must name +the role that owns the schema's objects — postgres for +tickets/fuel, tracksolid_owner for +reporting/tracksolid — or future objects won't auto-grant.
+
tickets.inc shape. Each row has both typed columns +(bucket, raw_status, normalized_status, sla_status, +region, cluster, owner, mttr, closed_at, +latitude/longitude, geog/geom, …) and a +raw text blob with the original source fields. Query the typed columns, not raw.
+

5. Packaging — Dockerfile + pyproject.toml

Self-contained: pyproject.toml declares the deps (mcp[cli], psycopg2-binary, uvicorn[standard]) and the Dockerfile @@ -177,8 +209,16 @@ TLS from the domain; auto-deploys on push via the Forgejo webhook.

Fallback — deploy.sh. Check the repo out on the host and run it: it builds the image, resolves the DB network + DSN from the running stack, swaps in the analytics_ro credentials, and runs a standalone Traefik bridge.

-
cd ~/fleetanalytics_mcp && git pull
-MCP_AUTH_TOKENS="alice:$(openssl rand -hex 16)" bash deploy.sh
+
# add/rotate a token (sets the full token list):
+cd ~/fleetanalytics_mcp && git pull
+MCP_AUTH_TOKENS="alice:$(openssl rand -hex 16)" bash deploy.sh
+
+# code-only redeploy (e.g. a schema change): omit MCP_AUTH_TOKENS —
+# deploy.sh reuses the running container's tokens, no secret to re-type:
+cd ~/fleetanalytics_mcp && git pull && bash deploy.sh
+

Optional env: MCP_READABLE_SCHEMAS (default +reporting,tracksolid,tickets,fuel) controls which schemas the introspection helpers +expose; MCP_MAX_ROWS (default 10000) the row ceiling.

7. Deploy runbook (ordered)

    @@ -196,7 +236,8 @@ claude mcp list # → "fireside-analytics: connected"Claude Desktop / claude.ai: add a custom connector with the same URL and an Authorization: Bearer <your-token> header. Example prompts: "list the schemas", "describe reporting.v_daily_summary", "top 10 cost centres by distance -in the last 30 days".

    +in the last 30 days", "open INC tickets by region and SLA status from tickets.inc", +"MTTR by cluster this month".

    9. Verification checklist