@uptimizr/mcp 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -19,12 +19,103 @@ collector remains the single gateway that enforces auth, per-project scoping, an
19
19
  UPTIMIZR_COLLECTOR_URL="https://collect.example.com" UPTIMIZR_API_KEY="utk_…" npx @uptimizr/mcp
20
20
  ```
21
21
 
22
+ ## Required key capability
23
+
24
+ `UPTIMIZR_API_KEY` must hold the **`query`** capability — and only that. Mint one with
25
+ `uptimizr new-key <projectId> --capabilities query --label "mcp-agent"` (`query` is the default).
26
+ `GET /api/v1/whoami` reports what a key holds, so a client can check before it registers tools; an
27
+ authenticated key missing a capability is refused with `403`, not `401`.
28
+
29
+ **`query:raw` is deliberately not needed.** Every tool here is an aggregate read; the server exposes
30
+ no raw per-session, replay or live-follow tool, so granting its key `query:raw` widens the blast
31
+ radius for nothing. `annotate` (metadata writes) and `ingest` are likewise never used. Prefer a
32
+ dedicated, labelled key with its own `--rate-limit-max` / `--rate-limit-window-ms` budget: the
33
+ collector's agent audit log records activity per key id, which is what makes an agent's reads
34
+ reviewable.
35
+
22
36
  ## Tools (read-only)
23
37
 
24
- `list_sessions`, `pointer_heatmap`, `world_heatmap`, `camera_heatmap`, `click_rays`, `flow_links`,
25
- `top_meshes`, `perf_summary`, `list_scenes`, `timeseries`, `event_counts`, `session_meta`,
26
- `scene_representation`. Most accept `since`/`until` (epoch ms) plus endpoint-specific filters
27
- (`scene`, `session`, `source`, `bins`, `cellSize`, `limit`).
38
+ <!-- generated:registry-tool-names:start — generated by `pnpm gen:docs`; edit the metric registry, not this table -->
39
+
40
+ `list_sessions`, `session_meta`, `scene_representation`, `list_scenes`, `timeseries`,
41
+ `event_counts`, `pointer_heatmap`, `mesh_uv_heatmap`, `world_heatmap`, `world_heatmap_stats`,
42
+ `gaze_heatmap`, `gaze_heatmap_stats`, `camera_heatmap`, `view_coverage_histogram`,
43
+ `position_heatmap`, `session_trajectory`, `aggregate_paths`, `scene_coverage`, `camera_distance`,
44
+ `click_rays`, `flow_links`, `top_meshes`, `mesh_sources`, `mesh_trend`, `mesh_dwell`,
45
+ `mesh_blind_spots`, `mesh_interaction_kinds`, `mesh_reachability`, `dead_clicks`, `rage_clicks`,
46
+ `hover_dwell`, `interaction_sources`, `top_input_actions`, `camera_gestures`, `navigation_stats`,
47
+ `backtrack_ratio`, `perf_summary`, `render_scale_truth`, `perf_distribution`, `fps_histogram`,
48
+ `frame_time_percentiles`, `jank_rate`, `perf_churn`, `perf_by_device`, `perf_by_scene`,
49
+ `perf_heatmap`, `compile_stalls`, `resource_summary`, `resource_percentiles`, `stability_counts`,
50
+ `graphics_diagnostics`, `error_heatmap`, `rendering_technology`, `capability_changes`,
51
+ `xr_rotation`, `xr_sources`, `xr_abandonment`, `xr_locomotion`, `xr_tracking_quality`,
52
+ `boundary_heatmap`, `boundary_heatmap_stats`, `xr_boundary_contacts`,
53
+ `ar_placement_time_to_place`, `ar_placement_attempts`, `ar_placement_surfaces`, `funnel`,
54
+ `scene_retention`, `load_bounce_funnel`, `variant_leaderboard`
55
+
56
+ <!-- generated:registry-tool-names:end -->
57
+
58
+ **69 tools, generated** from the `@uptimizr/metrics` semantic metric registry (ADR 0051 §1) — one per
59
+ metric the collector serves on a read endpoint. Names are the registry ids; the full table lives in
60
+ [README.md](./README.md), and `uptimizr://capabilities` enumerates them at runtime with each tool's
61
+ grain, column units and caveats.
62
+
63
+ Orientation: `list_sessions`, `list_scenes`, `session_meta`, `scene_representation`, `timeseries`,
64
+ `event_counts`. Attention: the `*_heatmap` family, `mesh_dwell`, `mesh_blind_spots`, `hover_dwell`.
65
+ Interaction: `top_meshes`, `mesh_sources`, `mesh_trend`, `mesh_interaction_kinds`,
66
+ `mesh_reachability`, `dead_clicks`, `rage_clicks`, `interaction_sources`, `top_input_actions`.
67
+ Navigation: `aggregate_paths`, `session_trajectory`, `scene_coverage`, `navigation_stats`,
68
+ `backtrack_ratio`, `camera_distance`, `camera_gestures`. Performance: `perf_summary`, `jank_rate`,
69
+ `perf_by_device`, `perf_by_scene`, `perf_heatmap`, `fps_histogram`, `frame_time_percentiles`,
70
+ `compile_stalls`, `resource_summary`, `rendering_technology`, … Errors: `stability_counts`,
71
+ `graphics_diagnostics`, `error_heatmap`, `capability_changes`. XR/AR: the `xr_*` and
72
+ `ar_placement_*` families. Conversion: `funnel`, `scene_retention`, `load_bounce_funnel`,
73
+ `variant_leaderboard`.
74
+
75
+ Most accept `since`/`until` (epoch ms) plus endpoint-specific filters (`scene`, `session`, `source`,
76
+ `bins`, `cellSize`, `limit`, `cameraMode`, `region`, …). Every tool declares an `outputSchema` and
77
+ returns `structuredContent` (`{ rows }`) alongside the JSON text — read the schema instead of
78
+ guessing the row shape, and read the tool description for the metric's caveats before trusting a
79
+ small sample.
80
+
81
+ ## Result formats (`format`)
82
+
83
+ Every **aggregate** tool takes a `format` argument choosing the envelope its rows arrive in
84
+ (ADR 0051 §2). It filters nothing.
85
+
86
+ | `format` | Returns | Use it when |
87
+ | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
88
+ | `summary` | A bounded digest — `ranked` top rows, a `series` trend, merged spatial `clusters`, or a single `record` — with shares, a sample size, the metric's `caveats` and a templated `reading` sentence. | **The default choice for an agent.** Always, unless you specifically need the rows. |
89
+ | `table` | `{ meta, rows }`: the same rows plus the metric, range, applied filters, sample size, row count, a truncation flag and the registry's limits. | You need every row _and_ the context to judge how far to trust it. |
90
+ | `full` | The bare rows, unchanged. Today's default. | You are post-processing the rows yourself and already know the sample is adequate. |
91
+
92
+ - `summary` is capped at the metric's `limits.maxSummaryRows`, so a 500-bin heatmap costs the same
93
+ as a 5-bin one. That is the whole point: a heatmap, voxel cloud or long leaderboard returned as
94
+ `full` can fill a context window on its own.
95
+ - `reading` and `caveats` are templated from the registry's column semantics by pure code — no model
96
+ is involved, so identical rows always produce identical words. Quote them; don't re-derive them.
97
+ - Shares appear only where the measure can honestly be summed. A metric in FPS or a ratio reports
98
+ `total: null` and no shares — do not compute a percentage from those rows.
99
+ - Cluster coordinates are **grid indices**: multiply by the effective `cellSize` for world space.
100
+ - `session_meta` and `scene_representation` are single stored records, not aggregations, and take no
101
+ `format`. Raw `/api/v1/sessions/:id/events` has an unrelated `format=json|ndjson`, and this server
102
+ exposes no tool for it.
103
+ - The catalog's default is still `full` — pass `format` explicitly.
104
+
105
+ ## Resources and prompts
106
+
107
+ - `uptimizr://capabilities` (`application/json`) — the machine-readable descriptor: schema version,
108
+ the canonical event types, the tool catalog, the parameter-semantics glossary, and `metrics`, the
109
+ whole registry with each metric's grain, column units, row JSON Schema, filters, limits,
110
+ interpretation, caveats, source channels and related metrics. Served from the package; **no
111
+ collector call**. Read it first — it is how to plan a query without trial and error.
112
+ - `uptimizr://scenes` (`application/json`) — the **live** list of scene ids with recent activity,
113
+ fetched through the read-only query API. These are the valid values for the `scene` parameter, so
114
+ resolve a user's scene name against it instead of guessing a string.
115
+ - Prompts: `weekly_scene_health` (optional `scene`), `attention_hotspots` (required `scene`) and
116
+ `xr_comfort_review` (optional `scene`). Each renders one user message that sequences the existing
117
+ read-only tools; they fetch nothing themselves and name no exact arguments, so the agent still
118
+ resolves the epoch-ms range and the filters.
28
119
 
29
120
  ## Rules for agents
30
121
 
@@ -32,9 +123,13 @@ UPTIMIZR_COLLECTOR_URL="https://collect.example.com" UPTIMIZR_API_KEY="utk_…"
32
123
  tools here. No data leaves the consumer's infrastructure (ADR 0003).
33
124
  - The server talks only to the configured collector with the consumer's `x-api-key`; never hardcode
34
125
  or log credentials.
35
- - Keep it a thin wrapper: a new tool = a new entry in the `readTools` catalog (defined in
36
- `@uptimizr/agent-core`) mapping to a documented query endpoint. Do not add aggregation/business
37
- logic — that lives in the collector.
126
+ - Keep it a thin wrapper: the `readTools` catalog (defined in `@uptimizr/agent-core`) is
127
+ **generated** from the `@uptimizr/metrics` metric registry, so a new tool = a new registry entry
128
+ for a documented query endpoint — never a hand-written array entry here. Do not add
129
+ aggregation/business logic — that lives in the collector.
130
+ - **No database driver, ever.** This server talks to a collector over HTTP; it must stay installable
131
+ with `npx`. Never add `@uptimizr/db` (or any package with a native/optional binary dependency) to
132
+ `dependencies` — `src/__tests__/dependencies.test.ts` fails if you do.
38
133
  - Tool definitions are pure (`buildRequest`) and must stay unit-testable without a live collector.
39
134
 
40
135
  ## Programmatic API
package/README.md CHANGED
@@ -75,37 +75,103 @@ For **GitHub Copilot CLI**, put the same entry in `~/.copilot/mcp-config.json` w
75
75
 
76
76
  ## Tools
77
77
 
78
- Most aggregate tools accept an optional time range (`since` / `until`, epoch ms) and the filters
79
- the underlying endpoint supports (`scene`, `session`, `source`, `bins`, `cellSize`, `interval`,
80
- `type`, `limit`, …). `session_meta` and `scene_representation` take their required IDs only.
81
-
82
- | Tool | Endpoint | Returns |
83
- | ---------------------- | ----------------------------------- | --------------------------------------------------- |
84
- | `list_sessions` | `/api/v1/sessions` | Recent sessions. |
85
- | `pointer_heatmap` | `/api/v1/heatmaps/pointer` | 2D pointer heatmap bins. |
86
- | `world_heatmap` | `/api/v1/heatmaps/world` | 3D world-space pointer voxels. |
87
- | `camera_heatmap` | `/api/v1/heatmaps/camera` | View-direction (spherical) bins. |
88
- | `click_rays` | `/api/v1/heatmaps/click-rays` | View-gated click rays. |
89
- | `flow_links` | `/api/v1/heatmaps/flow` | Gaze→mesh flow links. |
90
- | `top_meshes` | `/api/v1/meshes/top` | Most-interacted meshes. |
91
- | `perf_summary` | `/api/v1/perf` | FPS summary (avg/min/p50). |
92
- | `list_scenes` | `/api/v1/scenes` | Active scenes. |
93
- | `timeseries` | `/api/v1/timeseries` | Event-volume buckets over time. |
94
- | `event_counts` | `/api/v1/event-counts` | Per-event-type counts. |
95
- | `session_meta` | `/api/v1/sessions/:id/meta` | Coarse session descriptor (no raw event stream). |
96
- | `scene_representation` | `/api/v1/scenes/:id/representation` | Registered proxy geometry, if any. |
97
- | `funnel` | `/api/v1/funnel` | Ordered conversion funnel (`steps` JSON, ADR 0038). |
98
- | `aggregate_paths` | `/api/v1/paths` | Crowd-level desire-line routes (ADR 0037). |
99
- | `rendering_technology` | `/api/v1/rendering-technology` | WebGPU/WebGL2 + shading-language mix (ADR 0046). |
100
- | `xr_rotation` | `/api/v1/xr/rotation` | XR head-rotation rate (ADR 0048). |
101
- | `xr_sources` | `/api/v1/xr/sources` | XR input-source usage (ADR 0048). |
102
- | `xr_abandonment` | `/api/v1/xr/abandonment` | XR session abandonment (ADR 0048). |
103
- | `xr_locomotion` | `/api/v1/xr/locomotion` | XR locomotion & comfort (ADR 0048). |
78
+ The catalog is **generated from the semantic metric registry** in `@uptimizr/metrics` (ADR 0051 §1):
79
+ every aggregation the collector serves on a read endpoint is a tool — **69** of them. Each tool's
80
+ description carries the metric's interpretation notes and caveats, and each declares an MCP
81
+ `outputSchema` for the rows it returns (results come back as both `content` text and
82
+ `structuredContent`).
83
+
84
+ The table is **generated** from the collector's semantic metric registry (ADR 0051) — one row per
85
+ registered read metric. Read `uptimizr://capabilities` for each one's result grain, column units,
86
+ row schema and caveats; the same registry drives the collector's `GET /api/v1/openapi.json`.
87
+
88
+ Most tools accept an optional time range (`since` / `until`, epoch ms) and the filters the
89
+ underlying endpoint supports (`scene`, `session`, `source`, `bins`, `cellSize`, `interval`, `type`,
90
+ `limit`, `cameraMode`, `region`, …). `session_meta`, `session_trajectory` and
91
+ `scene_representation` take a required id.
92
+
93
+ <!-- generated:registry-tools:start — generated by `pnpm gen:docs`; edit the metric registry, not this table -->
94
+
95
+ | Tool | Endpoint | Returns | Parameters |
96
+ | ---------------------------- | ---------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
97
+ | `list_sessions` | `/api/v1/sessions` | Recent sessions | `since`, `until`, `bins`, `limit`, `cameraMode`, `format` |
98
+ | `session_meta` | `/api/v1/sessions/:id/meta` | Session descriptor | `session` |
99
+ | `scene_representation` | `/api/v1/scenes/:sceneId/representation` | Scene representation | `scene` |
100
+ | `list_scenes` | `/api/v1/scenes` | Active scenes | `since`, `until`, `limit`, `format` |
101
+ | `timeseries` | `/api/v1/timeseries` | Event volume over time | `since`, `until`, `interval`, `scene`, `type`, `format` |
102
+ | `event_counts` | `/api/v1/event-counts` | Counts per event type | `since`, `until`, `scene`, `format` |
103
+ | `pointer_heatmap` | `/api/v1/heatmaps/pointer` | 2D pointer heatmap | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
104
+ | `mesh_uv_heatmap` | `/api/v1/heatmaps/mesh-uv` | Per-mesh UV (texture-space) heatmap | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `mesh`, `format` |
105
+ | `world_heatmap` | `/api/v1/heatmaps/world` | 3D world-space pointer heatmap | `since`, `until`, `cellSize`, `limit`, `scene`, `source`, `cameraMode`, `region`, `format` |
106
+ | `world_heatmap_stats` | `/api/v1/heatmaps/world/stats` | World heatmap totals | `since`, `until`, `cellSize`, `scene`, `source`, `cameraMode`, `region`, `format` |
107
+ | `gaze_heatmap` | `/api/v1/heatmaps/gaze` | World-space gaze heatmap | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `cameraMode`, `region`, `format` |
108
+ | `gaze_heatmap_stats` | `/api/v1/heatmaps/gaze/stats` | Gaze heatmap totals | `since`, `until`, `cellSize`, `scene`, `session`, `cameraMode`, `region`, `format` |
109
+ | `camera_heatmap` | `/api/v1/heatmaps/camera` | View-direction heatmap | `since`, `until`, `bins`, `limit`, `scene`, `session`, `cameraMode`, `format` |
110
+ | `view_coverage_histogram` | `/api/v1/coverage/view-histogram` | 360° view-coverage histogram | `since`, `until`, `bins`, `limit`, `scene`, `session`, `cameraMode`, `format` |
111
+ | `position_heatmap` | `/api/v1/heatmaps/position` | Floor-plan camera-position heatmap | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `cameraMode`, `region`, `format` |
112
+ | `session_trajectory` | `/api/v1/sessions/:sessionId/trajectory` | Session walked path | `session`, `since`, `until`, `limit`, `scene`, `format` |
113
+ | `aggregate_paths` | `/api/v1/paths` | Aggregate desire-line paths | `since`, `until`, `cellSize`, `limit`, `scene`, `cameraMode`, `format` |
114
+ | `scene_coverage` | `/api/v1/coverage` | Scene coverage / dead zones | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `format` |
115
+ | `camera_distance` | `/api/v1/camera/distance` | Camera distance / zoom distribution | `since`, `until`, `centerX`, `centerY`, `centerZ`, `bucketSize`, `limit`, `scene`, `session`, `format` |
116
+ | `click_rays` | `/api/v1/heatmaps/click-rays` | View-gated click rays | `since`, `until`, `cellSize`, `limit`, `scene`, `source`, `session`, `format` |
117
+ | `flow_links` | `/api/v1/heatmaps/flow` | Gaze → mesh flow links | `since`, `until`, `bins`, `limit`, `scene`, `session`, `cameraMode`, `cellSize`, `groupByOrigin`, `originVoxel`, `format` |
118
+ | `top_meshes` | `/api/v1/meshes/top` | Most-interacted meshes | `since`, `until`, `bins`, `limit`, `session`, `format` |
119
+ | `mesh_sources` | `/api/v1/meshes/sources` | Mesh interactions by input source | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
120
+ | `mesh_trend` | `/api/v1/meshes/trend` | Per-mesh interaction trend | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `interval`, `format` |
121
+ | `mesh_dwell` | `/api/v1/meshes/dwell` | Per-object dwell / attention | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
122
+ | `mesh_blind_spots` | `/api/v1/meshes/blind-spots` | Blind spots / never-noticed meshes | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
123
+ | `mesh_interaction_kinds` | `/api/v1/meshes/kinds` | Interaction kinds per mesh | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
124
+ | `mesh_reachability` | `/api/v1/meshes/reachability` | Mesh reachability by distance | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `bucketSize`, `format` |
125
+ | `dead_clicks` | `/api/v1/clicks/dead` | Dead-click rate | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
126
+ | `rage_clicks` | `/api/v1/clicks/rage` | Rage-click clusters | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `interval`, `minRepeats`, `format` |
127
+ | `hover_dwell` | `/api/v1/hover/dwell` | Hover hesitation per object | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
128
+ | `interaction_sources` | `/api/v1/interactions/sources` | Interactions by input source | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
129
+ | `top_input_actions` | `/api/v1/input-actions/top` | Most-used shortcuts and actions | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
130
+ | `camera_gestures` | `/api/v1/camera-gestures` | Camera navigation gestures | `since`, `until`, `bins`, `limit`, `scene`, `session`, `source`, `cameraMode`, `format` |
131
+ | `navigation_stats` | `/api/v1/navigation` | Navigation effort per session | `since`, `until`, `moveThreshold`, `limit`, `scene`, `session`, `format` |
132
+ | `backtrack_ratio` | `/api/v1/backtrack` | Path retrace / backtracking | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `format` |
133
+ | `perf_summary` | `/api/v1/perf` | Rendering performance summary | `since`, `until`, `bins`, `limit`, `session`, `format` |
134
+ | `render_scale_truth` | `/api/v1/perf/render-scale` | Render-scale truth | `since`, `until`, `bins`, `limit`, `session`, `format` |
135
+ | `perf_distribution` | `/api/v1/perf/distribution` | FPS distribution (per-session) | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
136
+ | `fps_histogram` | `/api/v1/perf/fps-histogram` | Per-session median-FPS histogram | `since`, `until`, `bins`, `limit`, `scene`, `session`, `bucket`, `format` |
137
+ | `frame_time_percentiles` | `/api/v1/perf/frame-time` | Frame-time percentiles | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
138
+ | `jank_rate` | `/api/v1/perf/jank` | Jank rate | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
139
+ | `perf_churn` | `/api/v1/perf/churn` | Perf-correlated churn | `since`, `until`, `bins`, `limit`, `scene`, `session`, `windowMs`, `fpsThreshold`, `stallMs`, `format` |
140
+ | `perf_by_device` | `/api/v1/perf/by-device` | FPS by device class | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
141
+ | `perf_by_scene` | `/api/v1/perf/by-scene` | FPS by scene | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
142
+ | `perf_heatmap` | `/api/v1/heatmaps/perf` | Spatial FPS heatmap | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `format` |
143
+ | `compile_stalls` | `/api/v1/perf/compile-stalls` | Shader / pipeline compile stalls | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
144
+ | `resource_summary` | `/api/v1/perf/resources` | GPU / memory footprint summary | `since`, `until`, `bins`, `limit`, `session`, `format` |
145
+ | `resource_percentiles` | `/api/v1/perf/resource-percentiles` | GPU / memory footprint percentiles | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
146
+ | `stability_counts` | `/api/v1/perf/stability` | Stability incidents | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
147
+ | `graphics_diagnostics` | `/api/v1/graphics-diagnostics` | Engine diagnostic counts | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
148
+ | `error_heatmap` | `/api/v1/heatmaps/errors` | Spatial error heatmap | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `region`, `severity`, `category`, `errorKind`, `format` |
149
+ | `rendering_technology` | `/api/v1/rendering-technology` | Rendering-technology mix | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
150
+ | `capability_changes` | `/api/v1/capabilities` | Capability / fidelity transitions | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
151
+ | `xr_rotation` | `/api/v1/xr/rotation` | XR head-rotation rate | `since`, `until`, `rapidTurn`, `limit`, `scene`, `session`, `format` |
152
+ | `xr_sources` | `/api/v1/xr/sources` | XR input-source usage | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
153
+ | `xr_abandonment` | `/api/v1/xr/abandonment` | XR session abandonment | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
154
+ | `xr_locomotion` | `/api/v1/xr/locomotion` | XR locomotion & comfort | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
155
+ | `xr_tracking_quality` | `/api/v1/xr/tracking` | XR tracking quality | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
156
+ | `boundary_heatmap` | `/api/v1/heatmaps/boundary` | Guardian / boundary-touch heatmap | `since`, `until`, `cellSize`, `limit`, `scene`, `session`, `region`, `format` |
157
+ | `boundary_heatmap_stats` | `/api/v1/heatmaps/boundary/stats` | Boundary heatmap totals | `since`, `until`, `cellSize`, `scene`, `session`, `region`, `format` |
158
+ | `xr_boundary_contacts` | `/api/v1/xr/boundary-contacts` | Boundary contacts per session | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
159
+ | `ar_placement_time_to_place` | `/api/v1/ar/placement/time-to-place` | AR time-to-place distribution | `since`, `until`, `bins`, `limit`, `scene`, `session`, `bucketMs`, `format` |
160
+ | `ar_placement_attempts` | `/api/v1/ar/placement/attempts` | AR re-placement distribution | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
161
+ | `ar_placement_surfaces` | `/api/v1/ar/placement/surfaces` | AR placement surfaces | `since`, `until`, `bins`, `limit`, `scene`, `session`, `format` |
162
+ | `funnel` | `/api/v1/funnel` | Conversion funnel | `since`, `until`, `scene`, `cameraMode`, `steps`, `format` |
163
+ | `scene_retention` | `/api/v1/scene-retention` | Scene-to-scene retention | `since`, `until`, `limit`, `format` |
164
+ | `load_bounce_funnel` | `/api/v1/load-bounce` | Load → bounce funnel | `since`, `until`, `scene`, `bands`, `format` |
165
+ | `variant_leaderboard` | `/api/v1/variant-leaderboard` | Variant → conversion leaderboard | `since`, `until`, `scene`, `cameraMode`, `variant`, `conversion`, `limit`, `format` |
166
+
167
+ <!-- generated:registry-tools:end -->
104
168
 
105
169
  ## Resources & prompts
106
170
 
107
171
  The server also exposes read-only **resources** for self-discovery — `uptimizr://capabilities`
108
- (a machine-readable descriptor of event types, the tool catalog, and parameter semantics) and
172
+ (a machine-readable descriptor of event types, the tool catalog, parameter semantics, and
173
+ `metrics`: the collector's whole semantic metric registry, with each metric's result grain, column
174
+ units, row JSON Schema, row limits, interpretation and caveats — ADR 0051) and
109
175
  `uptimizr://scenes` (live scene ids) — and curated **prompts** (`weekly_scene_health`,
110
176
  `attention_hotspots`, `xr_comfort_review`) that drive the tools above. A remote Streamable HTTP
111
177
  transport is a deferred, auth-gated follow-up (ADR 0050 §7). See the
@@ -1,9 +1,14 @@
1
1
  import { type EventType } from "@uptimizr/schema";
2
+ import { type ColumnSemantics, type DimensionId, type FilterId, type MetricCategory, type MetricComparison, type MetricGrain } from "@uptimizr/metrics";
2
3
  /**
3
4
  * One tool the server exposes, described for self-discovery: its name, a human
4
- * title, what it returns, and the parameter names it accepts. Sourced directly
5
- * from the shared `@uptimizr/agent-core` catalog so it can never drift from the
6
- * tools actually registered (ADR 0050 §7).
5
+ * title, what it returns, and the parameter names it accepts.
6
+ *
7
+ * Derived from the **semantic metric registry** (`@uptimizr/metrics`, ADR
8
+ * 0051 §1) rather than restated here, so the catalog cannot drift from the
9
+ * metrics the collector can actually compute. `params` are the request
10
+ * parameters of the underlying query endpoint — the definitive *input schema*
11
+ * of a registered MCP tool is the one returned by `tools/list`.
7
12
  */
8
13
  export interface CapabilityToolDescriptor {
9
14
  name: string;
@@ -16,11 +21,58 @@ export interface CapabilityParamDescriptor {
16
21
  name: string;
17
22
  description: string;
18
23
  }
24
+ /**
25
+ * One registry metric, serialised for an agent: everything in the registry
26
+ * entry except the SQL `builder` (an implementation detail with no meaning
27
+ * outside `@uptimizr/db`), with the Zod `row` schema replaced by its JSON
28
+ * Schema so a client with no Zod can still validate or shape a result.
29
+ */
30
+ export interface CapabilityMetricDescriptor {
31
+ id: string;
32
+ title: string;
33
+ description: string;
34
+ category: MetricCategory;
35
+ /** What one row represents. */
36
+ grain: MetricGrain;
37
+ /** The collector route it is served on, when it has one. */
38
+ endpoint?: {
39
+ method: "GET";
40
+ path: string;
41
+ pathParams?: readonly FilterId[];
42
+ };
43
+ /** Group-by dimensions the rows are keyed by. */
44
+ dimensions: readonly DimensionId[];
45
+ /** Accepted request parameters. */
46
+ filters: readonly FilterId[];
47
+ /** JSON Schema of one result row. */
48
+ row: Record<string, unknown>;
49
+ /** Per-column semantics: description, unit, which column is the measure/label. */
50
+ columns: Readonly<Record<string, ColumnSemantics>>;
51
+ /** Registry-declared caps, so no consumer asks for an unbounded payload. */
52
+ limits: {
53
+ maxRows: number;
54
+ maxSummaryRows: number;
55
+ };
56
+ /** How to read the result. */
57
+ interpretation: string;
58
+ /** Small-sample, capture-gating and sampling-rate warnings. */
59
+ caveats: readonly string[];
60
+ /** Capture channels (ADR 0012) that must be enabled for it to have data. */
61
+ sourceChannels: readonly EventType[];
62
+ related: readonly string[];
63
+ comparable?: MetricComparison;
64
+ /**
65
+ * `true` for a **resource** read (a single stored object such as a session
66
+ * descriptor) rather than an aggregation over the event stream.
67
+ */
68
+ resource: boolean;
69
+ }
19
70
  /**
20
71
  * Machine-readable capabilities/schema descriptor an agent can read (via the
21
72
  * `uptimizr://capabilities` resource) to learn what it can ask before guessing.
22
73
  * It is strictly a description of the **read-only** surface — event types, the
23
- * tool catalog, and parameter semantics — and never itself queries any data.
74
+ * metric registry, the tool catalog, and parameter semantics — and never itself
75
+ * queries any data.
24
76
  */
25
77
  export interface CapabilitiesDescriptor {
26
78
  /** Wire-format version of the event schema (`@uptimizr/schema`). */
@@ -33,11 +85,16 @@ export interface CapabilitiesDescriptor {
33
85
  params: readonly CapabilityParamDescriptor[];
34
86
  /** The read-only tool catalog (each entry is one aggregate query endpoint). */
35
87
  tools: readonly CapabilityToolDescriptor[];
88
+ /**
89
+ * The full semantic metric registry: units, grain, dimensions, row schema,
90
+ * limits, interpretation and caveats per metric (ADR 0051 §1).
91
+ */
92
+ metrics: readonly CapabilityMetricDescriptor[];
36
93
  /** Human-oriented notes about scope and discovery. */
37
94
  notes: readonly string[];
38
95
  }
39
96
  /**
40
- * Build the capabilities descriptor from the live tool catalog and the event
97
+ * Build the capabilities descriptor from the metric registry and the event
41
98
  * schema. Pure and synchronous — it introspects definitions only, never the
42
99
  * collector, so it is safe to serve as a static resource.
43
100
  */
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG/E;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,EAAE,IAAI,CAAC;IACf,oEAAoE;IACpE,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IACjC,0DAA0D;IAC1D,MAAM,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC7C,+EAA+E;IAC/E,KAAK,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAC3C,sDAAsD;IACtD,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AA0BD;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,sBAAsB,CA6B1D"}
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE/E,OAAO,EAIL,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAErB,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAE3B;;;;;;;;;GASG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,cAAc,CAAC;IACzB,+BAA+B;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;KAAE,CAAC;IAC7E,iDAAiD;IACjD,UAAU,EAAE,SAAS,WAAW,EAAE,CAAC;IACnC,mCAAmC;IACnC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC7B,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,kFAAkF;IAClF,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;IACnD,4EAA4E;IAC5E,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,8BAA8B;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,4EAA4E;IAC5E,cAAc,EAAE,SAAS,SAAS,EAAE,CAAC;IACrC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,EAAE,IAAI,CAAC;IACf,oEAAoE;IACpE,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IACjC,0DAA0D;IAC1D,MAAM,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC7C,+EAA+E;IAC/E,KAAK,EAAE,SAAS,wBAAwB,EAAE,CAAC;IAC3C;;;OAGG;IACH,OAAO,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC/C,sDAAsD;IACtD,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAmCD;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,sBAAsB,CA8C1D"}
@@ -1,58 +1,84 @@
1
1
  import { EVENT_TYPES, SCHEMA_VERSION } from "@uptimizr/schema";
2
- import { readTools } from "@uptimizr/agent-core";
3
- /**
4
- * Semantics for every parameter used across the tool catalog. Kept in one place
5
- * so a param means the same thing everywhere; {@link buildCapabilities} only
6
- * surfaces the entries a tool actually uses, and a unit test asserts coverage.
7
- */
8
- const PARAM_SEMANTICS = {
9
- since: "Start of the time range, epoch milliseconds (inclusive). Omit for all-time.",
10
- until: "End of the time range, epoch milliseconds (exclusive). Omit for up-to-now.",
11
- bins: "Grid resolution per axis for a binned heatmap (1–500).",
12
- limit: "Maximum rows to return (1–1000).",
13
- scene: "Restrict to one developer-assigned scene id (see the uptimizr://scenes resource).",
14
- session: "Scope the aggregate to a single session id.",
15
- cellSize: "Voxel edge length in world units for a spatial (world-space) aggregate.",
16
- interval: "Time-series bucket width in seconds.",
17
- type: "Restrict a time series to one event type (e.g. pointer_click).",
18
- source: "Input source filter: mouse, touch, stylus, pen, xr-controller, hand, gaze, transient, other.",
19
- cameraMode: "Camera navigation mode: 'viewer' (orbit) or 'first-person' (walkable).",
20
- rapidTurn: "Rapid-turn threshold in radians (0..π); XR view turns above this flag discomfort.",
21
- steps: "Funnel steps as a JSON-encoded array of ordered step predicates (ADR 0038).",
22
- sessionId: "The exact session id to describe.",
23
- sceneId: "The exact scene id to fetch.",
24
- };
2
+ import { z } from "zod";
3
+ import { FILTER_TARGETS, allMetrics, isResourceMetric, } from "@uptimizr/metrics";
4
+ /** Every request parameter a metric accepts: its path params, then its filters. */
5
+ function paramsOf(metric) {
6
+ return [...(metric.endpoint?.pathParams ?? []), ...metric.filters];
7
+ }
8
+ /** Serialise one registry entry, dropping `builder` and unwrapping `row`. */
9
+ function toMetricDescriptor(metric) {
10
+ const row = z.toJSONSchema(metric.row, {
11
+ io: "output",
12
+ unrepresentable: "any",
13
+ });
14
+ delete row.$schema;
15
+ return {
16
+ id: metric.id,
17
+ title: metric.title,
18
+ description: metric.description,
19
+ category: metric.category,
20
+ grain: metric.grain,
21
+ ...(metric.endpoint ? { endpoint: metric.endpoint } : {}),
22
+ dimensions: metric.dimensions,
23
+ filters: metric.filters,
24
+ row,
25
+ columns: metric.columns,
26
+ limits: metric.limits,
27
+ interpretation: metric.interpretation,
28
+ caveats: metric.caveats,
29
+ sourceChannels: metric.sourceChannels,
30
+ related: metric.related,
31
+ ...(metric.comparable ? { comparable: metric.comparable } : {}),
32
+ resource: isResourceMetric(metric),
33
+ };
34
+ }
25
35
  /**
26
- * Build the capabilities descriptor from the live tool catalog and the event
36
+ * Build the capabilities descriptor from the metric registry and the event
27
37
  * schema. Pure and synchronous — it introspects definitions only, never the
28
38
  * collector, so it is safe to serve as a static resource.
29
39
  */
30
40
  export function buildCapabilities() {
31
- const tools = readTools.map((tool) => ({
32
- name: tool.name,
33
- title: tool.title,
34
- description: tool.description,
35
- params: Object.keys(tool.inputSchema),
41
+ const metrics = allMetrics();
42
+ const served = metrics.filter((metric) => metric.endpoint != null);
43
+ const tools = served.map((metric) => ({
44
+ name: metric.id,
45
+ title: metric.title,
46
+ description: metric.description,
47
+ params: paramsOf(metric),
36
48
  }));
37
49
  const usedParams = new Set();
38
- for (const tool of tools)
39
- for (const p of tool.params)
40
- usedParams.add(p);
50
+ for (const metric of served)
51
+ for (const param of paramsOf(metric))
52
+ usedParams.add(param);
41
53
  const params = [...usedParams]
42
54
  .sort()
43
- .map((name) => ({ name, description: PARAM_SEMANTICS[name] ?? "" }));
55
+ .map((name) => ({ name, description: FILTER_TARGETS[name].description }));
44
56
  return {
45
57
  schemaVersion: SCHEMA_VERSION,
46
58
  readOnly: true,
47
59
  eventTypes: EVENT_TYPES,
48
60
  params,
49
61
  tools,
62
+ metrics: metrics.map(toMetricDescriptor),
50
63
  notes: [
51
64
  "This MCP surface is strictly read-only: aggregate, privacy-preserving queries only. " +
52
65
  "There are no ingestion, mutation, or raw per-session event tools (ADR 0003 / ADR 0017).",
66
+ "`metrics` is the collector's semantic metric registry (ADR 0051 §1): for each metric it " +
67
+ "gives the result `grain` (what one row is), the `columns` with their units, the JSON " +
68
+ "Schema of a row, `limits`, how to read it (`interpretation`) and how far to trust it " +
69
+ "(`caveats`). Read a metric's caveats before quoting its numbers.",
70
+ "`sourceChannels` names the capture channels (ADR 0012) that feed a metric. If a project " +
71
+ "has that channel disabled or sampled down, the metric is empty or proportional rather " +
72
+ "than exact — say so instead of reporting a zero as a finding.",
73
+ "`tools` lists the registry's served read surface and the request parameters of each " +
74
+ "underlying endpoint. It is exactly the set this server registers, because the tool " +
75
+ "catalog is generated from the same registry (ADR 0051 §1) — the authoritative input " +
76
+ "and output schemas of a registered tool are still the ones returned by `tools/list`.",
53
77
  "Enumerate the concrete scene ids for the `scene` parameter with the uptimizr://scenes " +
54
78
  "resource or the list_scenes tool; enumerate sessions with the list_sessions tool.",
55
79
  "All time ranges use epoch-millisecond `since`/`until`. Omit both for all-time.",
80
+ "The same registry drives the collector's OpenAPI document at GET /api/v1/openapi.json, " +
81
+ "which describes every endpoint below with its parameters and response schema.",
56
82
  ],
57
83
  };
58
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAkB,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AA0CjD;;;;GAIG;AACH,MAAM,eAAe,GAAqC;IACxD,KAAK,EAAE,6EAA6E;IACpF,KAAK,EAAE,4EAA4E;IACnF,IAAI,EAAE,wDAAwD;IAC9D,KAAK,EAAE,kCAAkC;IACzC,KAAK,EAAE,mFAAmF;IAC1F,OAAO,EAAE,6CAA6C;IACtD,QAAQ,EAAE,yEAAyE;IACnF,QAAQ,EAAE,sCAAsC;IAChD,IAAI,EAAE,gEAAgE;IACtE,MAAM,EACJ,8FAA8F;IAChG,UAAU,EAAE,wEAAwE;IACpF,SAAS,EAAE,mFAAmF;IAC9F,KAAK,EAAE,6EAA6E;IACpF,SAAS,EAAE,mCAAmC;IAC9C,OAAO,EAAE,8BAA8B;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,KAAK,GAA+B,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjE,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;KACtC,CAAC,CAAC,CAAC;IAEJ,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAEzE,MAAM,MAAM,GAAgC,CAAC,GAAG,UAAU,CAAC;SACxD,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IAEvE,OAAO;QACL,aAAa,EAAE,cAAc;QAC7B,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,WAAW;QACvB,MAAM;QACN,KAAK;QACL,KAAK,EAAE;YACL,sFAAsF;gBACpF,yFAAyF;YAC3F,wFAAwF;gBACtF,mFAAmF;YACrF,gFAAgF;SACjF;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -7,6 +7,12 @@ import { type CollectorClient } from "@uptimizr/agent-core";
7
7
  * collector's JSON (ADR 0005 / ADR 0017). Alongside the tools it exposes
8
8
  * capability-discovery **resources** and curated analysis **prompts** so agents
9
9
  * can self-orient (ADR 0050 §7).
10
+ *
11
+ * The tool catalog is generated from the `@uptimizr/db` metric registry
12
+ * (ADR 0051 §1), so `tools/list` covers every metric the collector serves on an
13
+ * endpoint. Each tool advertises the registry-derived `outputSchema` and returns
14
+ * both `structuredContent` (the typed `{ rows }` envelope) and the `content`
15
+ * text a client without structured-output support still reads.
10
16
  */
11
17
  export declare function createMcpServer(client: CollectorClient): McpServer;
12
18
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAKvE;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CA+BlE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAsCvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAqClE"}
package/dist/server.js CHANGED
@@ -1,8 +1,42 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
2
3
  import { readTools } from "@uptimizr/agent-core";
3
4
  import { registerResources } from "./resources.js";
4
5
  import { registerPrompts } from "./prompts.js";
5
6
  import { version } from "./version.js";
7
+ /**
8
+ * Normalise a collector response into the `{ rows }` envelope every tool's
9
+ * `outputSchema` declares. Aggregate endpoints already return an array; the
10
+ * single-object reads (a session descriptor, a scene representation, a one-row
11
+ * summary) become a one-element array so a client can treat every tool's
12
+ * structured result the same way. A `204`-style empty body becomes no rows.
13
+ */
14
+ function toRows(data) {
15
+ if (Array.isArray(data))
16
+ return data;
17
+ if (data == null)
18
+ return [];
19
+ return [data];
20
+ }
21
+ /**
22
+ * Validate the rows against the tool's registry-derived output schema and
23
+ * return the **parsed** result as the structured payload.
24
+ *
25
+ * The registry's numeric columns are strict `z.number()`: since ADR 0051 §2 the
26
+ * *collector* guarantees numbers, coercing each dialect's wire format
27
+ * (ClickHouse's string-encoded 64-bit integers, `pg`'s `int8`) at the single
28
+ * point rows leave its driver. So this is a check, not a repair — the advertised
29
+ * schema describes the API, and normalising here would hide a store regression.
30
+ *
31
+ * If the rows do not match the schema the raw rows are passed through; the SDK's
32
+ * own output validation then reports the offending column by name, which is the
33
+ * honest outcome for a collector that is out of contract.
34
+ */
35
+ function structuredRows(outputSchema, data) {
36
+ const rows = toRows(data);
37
+ const parsed = z.object(outputSchema).safeParse({ rows });
38
+ return parsed.success ? parsed.data : { rows };
39
+ }
6
40
  /**
7
41
  * Build the Uptimizr MCP server: a read-only `McpServer` whose tools each wrap
8
42
  * one collector query endpoint via the injected `CollectorClient`. The server
@@ -10,6 +44,12 @@ import { version } from "./version.js";
10
44
  * collector's JSON (ADR 0005 / ADR 0017). Alongside the tools it exposes
11
45
  * capability-discovery **resources** and curated analysis **prompts** so agents
12
46
  * can self-orient (ADR 0050 §7).
47
+ *
48
+ * The tool catalog is generated from the `@uptimizr/db` metric registry
49
+ * (ADR 0051 §1), so `tools/list` covers every metric the collector serves on an
50
+ * endpoint. Each tool advertises the registry-derived `outputSchema` and returns
51
+ * both `structuredContent` (the typed `{ rows }` envelope) and the `content`
52
+ * text a client without structured-output support still reads.
13
53
  */
14
54
  export function createMcpServer(client) {
15
55
  const server = new McpServer({ name: "uptimizr-mcp", version }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
@@ -18,11 +58,18 @@ export function createMcpServer(client) {
18
58
  title: tool.title,
19
59
  description: tool.description,
20
60
  inputSchema: tool.inputSchema,
61
+ ...(tool.outputSchema ? { outputSchema: tool.outputSchema } : {}),
21
62
  }, async (args) => {
22
63
  try {
23
64
  const { path, params } = tool.buildRequest(args);
24
65
  const data = await client.get(path, params);
25
- return { content: [{ type: "text", text: JSON.stringify(data) }] };
66
+ const text = JSON.stringify(data);
67
+ if (!tool.outputSchema)
68
+ return { content: [{ type: "text", text }] };
69
+ return {
70
+ content: [{ type: "text", text }],
71
+ structuredContent: structuredRows(tool.outputSchema, data),
72
+ };
26
73
  }
27
74
  catch (err) {
28
75
  const message = err instanceof Error ? err.message : String(err);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAwB,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,MAAuB;IACrD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,EACjC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAC5D,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,CAAC,YAAY,CACjB,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;YACb,IAAI,CAAC;gBACH,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,IAA+B,CAAC,CAAC;gBAC5E,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC5C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACrE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACnF,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC;IAED,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,eAAe,CAAC,MAAM,CAAC,CAAC;IAExB,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -10,9 +10,72 @@
10
10
  - [Integration & API reference](https://github.com/RaananW/Uptimizr/blob/main/docs/integration.md): the underlying query endpoints.
11
11
  - [Architecture Decision Records](https://github.com/RaananW/Uptimizr/tree/main/docs/adr): privacy model (0003), thin backends (0005), consumer-facing agents (0017).
12
12
 
13
+ ## Tools (read-only)
14
+
15
+ <!-- generated:registry-tool-names:start — generated by `pnpm gen:docs`; edit the metric registry, not this list -->
16
+
17
+ `list_sessions`, `session_meta`, `scene_representation`, `list_scenes`, `timeseries`,
18
+ `event_counts`, `pointer_heatmap`, `mesh_uv_heatmap`, `world_heatmap`, `world_heatmap_stats`,
19
+ `gaze_heatmap`, `gaze_heatmap_stats`, `camera_heatmap`, `view_coverage_histogram`,
20
+ `position_heatmap`, `session_trajectory`, `aggregate_paths`, `scene_coverage`, `camera_distance`,
21
+ `click_rays`, `flow_links`, `top_meshes`, `mesh_sources`, `mesh_trend`, `mesh_dwell`,
22
+ `mesh_blind_spots`, `mesh_interaction_kinds`, `mesh_reachability`, `dead_clicks`, `rage_clicks`,
23
+ `hover_dwell`, `interaction_sources`, `top_input_actions`, `camera_gestures`, `navigation_stats`,
24
+ `backtrack_ratio`, `perf_summary`, `render_scale_truth`, `perf_distribution`, `fps_histogram`,
25
+ `frame_time_percentiles`, `jank_rate`, `perf_churn`, `perf_by_device`, `perf_by_scene`,
26
+ `perf_heatmap`, `compile_stalls`, `resource_summary`, `resource_percentiles`, `stability_counts`,
27
+ `graphics_diagnostics`, `error_heatmap`, `rendering_technology`, `capability_changes`,
28
+ `xr_rotation`, `xr_sources`, `xr_abandonment`, `xr_locomotion`, `xr_tracking_quality`,
29
+ `boundary_heatmap`, `boundary_heatmap_stats`, `xr_boundary_contacts`,
30
+ `ar_placement_time_to_place`, `ar_placement_attempts`, `ar_placement_surfaces`, `funnel`,
31
+ `scene_retention`, `load_bounce_funnel`, `variant_leaderboard`
32
+
33
+ <!-- generated:registry-tool-names:end -->
34
+
35
+ ## Result formats (`format`)
36
+
37
+ Every aggregate tool takes `format` — the envelope its rows arrive in, not a filter (ADR 0051 §2).
38
+
39
+ - `summary` — **prefer this.** A bounded digest: `ranked` top rows, a `series` trend, merged spatial
40
+ `clusters`, or a single `record`, with shares, a sample size, the metric's `caveats` and a
41
+ templated `reading` sentence. Capped at the metric's `limits.maxSummaryRows`, so a 500-bin heatmap
42
+ costs the same as a 5-bin one. `reading` and `caveats` are templated by pure code — no model —
43
+ so identical rows always produce identical words.
44
+ - `table` — `{ meta, rows }`: every row plus the metric, range, applied filters, sample size, row
45
+ count, a truncation flag and the registry limits. Use it when you need the rows *and* the context
46
+ to judge them.
47
+ - `full` — the bare rows, unchanged. Today's catalog default; pass `format` explicitly.
48
+
49
+ Shares appear only where the measure can honestly be summed (an FPS or ratio metric reports
50
+ `total: null` and no shares). Cluster coordinates are grid indices — multiply by the effective
51
+ `cellSize` for world space. `session_meta` and `scene_representation` are stored records, not
52
+ aggregations, and take no `format`.
53
+
54
+ ## Resources and prompts
55
+
56
+ - `uptimizr://capabilities` (`application/json`) — static descriptor: schema version, canonical
57
+ event types, the tool catalog, the parameter-semantics glossary, and `metrics` (the whole registry
58
+ with grain, column units, row JSON Schema, filters, limits, interpretation, caveats, source
59
+ channels). No collector call. Read it first.
60
+ - `uptimizr://scenes` (`application/json`) — the live scene ids with recent activity, i.e. the valid
61
+ values for the `scene` parameter. Fetched through the read-only query API.
62
+ - Prompts: `weekly_scene_health` (optional `scene`), `attention_hotspots` (required `scene`),
63
+ `xr_comfort_review` (optional `scene`) — each renders one user message sequencing the read-only
64
+ tools; they fetch nothing themselves.
65
+
66
+ ## Required key capability
67
+
68
+ `UPTIMIZR_API_KEY` needs the `query` capability, and only that
69
+ (`uptimizr new-key <projectId> --capabilities query --label "mcp-agent"`; `query` is the default).
70
+ `query:raw` is **deliberately not required** — no tool here reads raw per-session, replay or
71
+ live-follow data. `annotate` and `ingest` are never used either. `GET /api/v1/whoami` reports what a
72
+ key holds; a key missing a required capability is refused with `403`.
73
+
13
74
  ## Key exports
14
75
 
15
76
  - `createMcpServer(client)` — build the read-only MCP server.
16
77
  - `createCollectorClient(config)` — the thin GET-only collector client.
17
78
  - `readMcpConfig()` — read `UPTIMIZR_COLLECTOR_URL` + `UPTIMIZR_API_KEY` from the environment.
18
- - `readTools` — the read-only tool catalog (one entry per query endpoint).
79
+ - `readTools` — the read-only tool catalog (one entry per query endpoint), generated from the
80
+ `@uptimizr/metrics` metric registry: 69 tools, each with an input schema, an MCP `outputSchema` and the
81
+ metric's interpretation notes and caveats in its description (ADR 0051).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uptimizr/mcp",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Read-only Model Context Protocol (MCP) server over an Uptimizr collector's query API — let an agent ask questions of your own 3D analytics, on your own infrastructure.",
5
5
  "keywords": [
6
6
  "uptimizr",
@@ -49,8 +49,9 @@
49
49
  "dependencies": {
50
50
  "@modelcontextprotocol/sdk": "^1.30.0",
51
51
  "zod": "^4.5.4",
52
- "@uptimizr/agent-core": "1.0.1",
53
- "@uptimizr/schema": "1.0.1"
52
+ "@uptimizr/agent-core": "1.1.1",
53
+ "@uptimizr/metrics": "0.1.0",
54
+ "@uptimizr/schema": "1.1.0"
54
55
  },
55
56
  "devDependencies": {
56
57
  "@types/node": "^26.4.1",