@uptimizr/mcp 0.1.1 → 0.2.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 +9 -3
- package/README.md +72 -18
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/capabilities.d.ts +45 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +59 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts +4 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +96 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +21 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +46 -0
- package/dist/resources.js.map +1 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +9 -3
- package/dist/server.js.map +1 -1
- package/package.json +7 -5
- package/dist/client.d.ts +0 -23
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -38
- package/dist/client.js.map +0 -1
- package/dist/tools.d.ts +0 -28
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js +0 -203
- package/dist/tools.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -10,6 +10,9 @@ lets an agent query a consumer's **own** 3D analytics in natural language. Each
|
|
|
10
10
|
documented collector read endpoint; the server is a thin wrapper that holds no business logic and
|
|
11
11
|
performs `GET` requests only (ADR 0005, ADR 0017).
|
|
12
12
|
|
|
13
|
+
It connects **only to the collector's HTTP query API** (never to the database directly), so the
|
|
14
|
+
collector remains the single gateway that enforces auth, per-project scoping, and privacy.
|
|
15
|
+
|
|
13
16
|
## Run
|
|
14
17
|
|
|
15
18
|
```bash
|
|
@@ -29,13 +32,16 @@ UPTIMIZR_COLLECTOR_URL="https://collect.example.com" UPTIMIZR_API_KEY="utk_…"
|
|
|
29
32
|
tools here. No data leaves the consumer's infrastructure (ADR 0003).
|
|
30
33
|
- The server talks only to the configured collector with the consumer's `x-api-key`; never hardcode
|
|
31
34
|
or log credentials.
|
|
32
|
-
- Keep it a thin wrapper: a new tool = a new entry in the `readTools`
|
|
33
|
-
documented query endpoint. Do not add aggregation/business
|
|
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.
|
|
34
38
|
- Tool definitions are pure (`buildRequest`) and must stay unit-testable without a live collector.
|
|
35
39
|
|
|
36
40
|
## Programmatic API
|
|
37
41
|
|
|
38
|
-
`readMcpConfig()`, `
|
|
42
|
+
`readMcpConfig()`, `createMcpServer(client)`, and the shared building blocks re-exported from
|
|
43
|
+
[`@uptimizr/agent-core`](https://www.npmjs.com/package/@uptimizr/agent-core):
|
|
44
|
+
`createCollectorClient(config)` and `readTools`.
|
|
39
45
|
|
|
40
46
|
## More
|
|
41
47
|
|
package/README.md
CHANGED
|
@@ -10,6 +10,16 @@ The server is a thin wrapper: each tool maps one-to-one to a documented collecto
|
|
|
10
10
|
performs `GET` requests only — there are **no ingestion, mutation, or raw per-session event
|
|
11
11
|
tools**.
|
|
12
12
|
|
|
13
|
+
## How it connects
|
|
14
|
+
|
|
15
|
+
The server talks **only to your collector's HTTP query API** — it never opens the database
|
|
16
|
+
(DuckDB/ClickHouse/Postgres) directly. The collector stays the single gateway to your data, so an
|
|
17
|
+
agent gets exactly the auth, project-scoping, and privacy guarantees a dashboard user does:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
AI agent ──stdio──▶ @uptimizr/mcp ──HTTPS GET + x-api-key──▶ collector ──▶ store
|
|
21
|
+
```
|
|
22
|
+
|
|
13
23
|
## Run
|
|
14
24
|
|
|
15
25
|
```bash
|
|
@@ -43,26 +53,63 @@ config:
|
|
|
43
53
|
}
|
|
44
54
|
```
|
|
45
55
|
|
|
56
|
+
For **GitHub Copilot CLI**, put the same entry in `~/.copilot/mcp-config.json` with
|
|
57
|
+
`"type": "local"` and `"tools": ["*"]`, then restart the CLI so it loads the tools:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"uptimizr": {
|
|
63
|
+
"type": "local",
|
|
64
|
+
"command": "npx",
|
|
65
|
+
"args": ["-y", "@uptimizr/mcp"],
|
|
66
|
+
"env": {
|
|
67
|
+
"UPTIMIZR_COLLECTOR_URL": "http://localhost:4318",
|
|
68
|
+
"UPTIMIZR_API_KEY": "utk_…"
|
|
69
|
+
},
|
|
70
|
+
"tools": ["*"]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
46
76
|
## Tools
|
|
47
77
|
|
|
48
|
-
|
|
49
|
-
underlying endpoint supports (`scene`, `session`, `source`, `bins`, `cellSize`, `
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
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). |
|
|
104
|
+
|
|
105
|
+
## Resources & prompts
|
|
106
|
+
|
|
107
|
+
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
|
|
109
|
+
`uptimizr://scenes` (live scene ids) — and curated **prompts** (`weekly_scene_health`,
|
|
110
|
+
`attention_hotspots`, `xr_comfort_review`) that drive the tools above. A remote Streamable HTTP
|
|
111
|
+
transport is a deferred, auth-gated follow-up (ADR 0050 §7). See the
|
|
112
|
+
[MCP guide](https://uptimizr.com/docs/guides/mcp/) for details.
|
|
66
113
|
|
|
67
114
|
## Programmatic use
|
|
68
115
|
|
|
@@ -75,6 +122,13 @@ const server = createMcpServer(client);
|
|
|
75
122
|
await server.connect(new StdioServerTransport());
|
|
76
123
|
```
|
|
77
124
|
|
|
125
|
+
The package also exports `readTools`, `CollectorError`, `version`, and the related public types.
|
|
126
|
+
The read-only tool catalog (`readTools`) and the `GET`-only collector client are defined in the
|
|
127
|
+
framework-agnostic [`@uptimizr/agent-core`](../agent-core/README.md) package and re-exported here,
|
|
128
|
+
so the agent tool surface is defined once and shared across the MCP server, the dashboard assistant,
|
|
129
|
+
and the demo assistant (ADR 0050). Building a non-MCP agent? Depend on `@uptimizr/agent-core`
|
|
130
|
+
directly — it also ships a headless provider-adapter interface and tool-calling loop.
|
|
131
|
+
|
|
78
132
|
## Develop
|
|
79
133
|
|
|
80
134
|
```bash
|
package/dist/bin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import { createCollectorClient } from "
|
|
3
|
+
import { createCollectorClient } from "@uptimizr/agent-core";
|
|
4
4
|
import { readMcpConfig } from "./config.js";
|
|
5
5
|
import { createMcpServer } from "./server.js";
|
|
6
6
|
/**
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;;;GAIG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,OAAO,IAAI,CAAC,CAAC;IACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type EventType } from "@uptimizr/schema";
|
|
2
|
+
/**
|
|
3
|
+
* 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).
|
|
7
|
+
*/
|
|
8
|
+
export interface CapabilityToolDescriptor {
|
|
9
|
+
name: string;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
params: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
/** A parameter name and what it means, shared across tools. */
|
|
15
|
+
export interface CapabilityParamDescriptor {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Machine-readable capabilities/schema descriptor an agent can read (via the
|
|
21
|
+
* `uptimizr://capabilities` resource) to learn what it can ask before guessing.
|
|
22
|
+
* 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.
|
|
24
|
+
*/
|
|
25
|
+
export interface CapabilitiesDescriptor {
|
|
26
|
+
/** Wire-format version of the event schema (`@uptimizr/schema`). */
|
|
27
|
+
schemaVersion: string;
|
|
28
|
+
/** The MCP surface is read-only: aggregate queries only, no raw events/PII. */
|
|
29
|
+
readOnly: true;
|
|
30
|
+
/** Canonical analytics event types (the single source of truth). */
|
|
31
|
+
eventTypes: readonly EventType[];
|
|
32
|
+
/** Glossary of every query parameter the tools accept. */
|
|
33
|
+
params: readonly CapabilityParamDescriptor[];
|
|
34
|
+
/** The read-only tool catalog (each entry is one aggregate query endpoint). */
|
|
35
|
+
tools: readonly CapabilityToolDescriptor[];
|
|
36
|
+
/** Human-oriented notes about scope and discovery. */
|
|
37
|
+
notes: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build the capabilities descriptor from the live tool catalog and the event
|
|
41
|
+
* schema. Pure and synchronous — it introspects definitions only, never the
|
|
42
|
+
* collector, so it is safe to serve as a static resource.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildCapabilities(): CapabilitiesDescriptor;
|
|
45
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
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
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Build the capabilities descriptor from the live tool catalog and the event
|
|
27
|
+
* schema. Pure and synchronous — it introspects definitions only, never the
|
|
28
|
+
* collector, so it is safe to serve as a static resource.
|
|
29
|
+
*/
|
|
30
|
+
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),
|
|
36
|
+
}));
|
|
37
|
+
const usedParams = new Set();
|
|
38
|
+
for (const tool of tools)
|
|
39
|
+
for (const p of tool.params)
|
|
40
|
+
usedParams.add(p);
|
|
41
|
+
const params = [...usedParams]
|
|
42
|
+
.sort()
|
|
43
|
+
.map((name) => ({ name, description: PARAM_SEMANTICS[name] ?? "" }));
|
|
44
|
+
return {
|
|
45
|
+
schemaVersion: SCHEMA_VERSION,
|
|
46
|
+
readOnly: true,
|
|
47
|
+
eventTypes: EVENT_TYPES,
|
|
48
|
+
params,
|
|
49
|
+
tools,
|
|
50
|
+
notes: [
|
|
51
|
+
"This MCP surface is strictly read-only: aggregate, privacy-preserving queries only. " +
|
|
52
|
+
"There are no ingestion, mutation, or raw per-session event tools (ADR 0003 / ADR 0017).",
|
|
53
|
+
"Enumerate the concrete scene ids for the `scene` parameter with the uptimizr://scenes " +
|
|
54
|
+
"resource or the list_scenes tool; enumerate sessions with the list_sessions tool.",
|
|
55
|
+
"All time ranges use epoch-millisecond `since`/`until`. Omit both for all-time.",
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { readMcpConfig, type McpConfig } from "./config.js";
|
|
2
|
-
export { createCollectorClient, CollectorError, type CollectorClient, type QueryParams, } from "
|
|
3
|
-
export { readTools, type ReadTool, type ReadToolRequest } from "./tools.js";
|
|
2
|
+
export { createCollectorClient, CollectorError, readTools, type CollectorClient, type CollectorClientConfig, type QueryParams, type ReadTool, type ReadToolRequest, } from "@uptimizr/agent-core";
|
|
4
3
|
export { createMcpServer } from "./server.js";
|
|
4
|
+
export { buildCapabilities, type CapabilitiesDescriptor, type CapabilityToolDescriptor, type CapabilityParamDescriptor, } from "./capabilities.js";
|
|
5
|
+
export { registerResources, CAPABILITIES_URI, SCENES_URI } from "./resources.js";
|
|
6
|
+
export { registerPrompts } from "./prompts.js";
|
|
5
7
|
export { version } from "./version.js";
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,SAAS,EACT,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export { readMcpConfig } from "./config.js";
|
|
2
|
-
export { createCollectorClient, CollectorError, } from "
|
|
3
|
-
export { readTools } from "./tools.js";
|
|
2
|
+
export { createCollectorClient, CollectorError, readTools, } from "@uptimizr/agent-core";
|
|
4
3
|
export { createMcpServer } from "./server.js";
|
|
4
|
+
export { buildCapabilities, } from "./capabilities.js";
|
|
5
|
+
export { registerResources, CAPABILITIES_URI, SCENES_URI } from "./resources.js";
|
|
6
|
+
export { registerPrompts } from "./prompts.js";
|
|
5
7
|
export { version } from "./version.js";
|
|
6
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,SAAS,GAMV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,iBAAiB,GAIlB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAuBzE,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiGvD"}
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Curated prompt templates for common 3D-analytics investigations (ADR 0050 §7).
|
|
4
|
+
* Each renders a single user message that steers the agent to call the existing
|
|
5
|
+
* read-only tools in a sensible order — no data is fetched here; the agent runs
|
|
6
|
+
* the tools. Templates are intentionally tool-agnostic about exact arguments so
|
|
7
|
+
* the agent can adapt (e.g. resolve the current epoch-ms range itself).
|
|
8
|
+
*/
|
|
9
|
+
const sceneArg = z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Optional scene id to scope the analysis to (see the uptimizr://scenes resource).");
|
|
13
|
+
const requiredSceneArg = z
|
|
14
|
+
.string()
|
|
15
|
+
.describe("The scene id to analyse (see the uptimizr://scenes resource).");
|
|
16
|
+
const forScene = (scene) => scene ? `scene "${scene}"` : "the project (all scenes)";
|
|
17
|
+
/** Register the curated prompt templates on the server. */
|
|
18
|
+
export function registerPrompts(server) {
|
|
19
|
+
server.registerPrompt("weekly_scene_health", {
|
|
20
|
+
title: "Weekly scene health",
|
|
21
|
+
description: "A weekly health check for a scene (or the whole project): traffic, event mix, " +
|
|
22
|
+
"performance, and the most-interacted meshes.",
|
|
23
|
+
argsSchema: { scene: sceneArg },
|
|
24
|
+
}, ({ scene }) => ({
|
|
25
|
+
messages: [
|
|
26
|
+
{
|
|
27
|
+
role: "user",
|
|
28
|
+
content: {
|
|
29
|
+
type: "text",
|
|
30
|
+
text: `Give me a weekly health report for ${forScene(scene)} covering the last 7 days.\n\n` +
|
|
31
|
+
"Use these read-only tools and summarise the findings:\n" +
|
|
32
|
+
"- `event_counts` for the per-event-type mix" +
|
|
33
|
+
(scene ? ` (scene="${scene}")` : "") +
|
|
34
|
+
".\n" +
|
|
35
|
+
"- `timeseries` (interval ~86400s) to show the day-by-day event volume and average FPS trend.\n" +
|
|
36
|
+
"- `perf_summary` for avg/min/p50 FPS.\n" +
|
|
37
|
+
"- `top_meshes` for the most-interacted meshes.\n" +
|
|
38
|
+
"- `list_sessions` for how many sessions were recorded.\n\n" +
|
|
39
|
+
"Call out anything unusual (traffic spikes/drops, FPS regressions, error events) and " +
|
|
40
|
+
"end with 2–3 concrete recommendations.",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
}));
|
|
45
|
+
server.registerPrompt("attention_hotspots", {
|
|
46
|
+
title: "Attention hot-spots for a scene",
|
|
47
|
+
description: "Find where visitors look and click in a scene: view-direction concentration, " +
|
|
48
|
+
"gaze→mesh flow, and the objects that draw the most interaction.",
|
|
49
|
+
argsSchema: { scene: requiredSceneArg },
|
|
50
|
+
}, ({ scene }) => ({
|
|
51
|
+
messages: [
|
|
52
|
+
{
|
|
53
|
+
role: "user",
|
|
54
|
+
content: {
|
|
55
|
+
type: "text",
|
|
56
|
+
text: `Where does attention concentrate in scene "${scene}"?\n\n` +
|
|
57
|
+
'Use these read-only tools (all scoped with scene="' +
|
|
58
|
+
scene +
|
|
59
|
+
'") and synthesise the result:\n' +
|
|
60
|
+
"- `camera_heatmap` for the view-direction distribution (what people look at).\n" +
|
|
61
|
+
"- `flow_links` for how gaze flows into clicked meshes.\n" +
|
|
62
|
+
"- `click_rays` for view-gated clicks per voxel/mesh.\n" +
|
|
63
|
+
"- `top_meshes` for the most-interacted objects.\n\n" +
|
|
64
|
+
"Describe the main hot-spots, any ignored/cold areas, and what that implies for the " +
|
|
65
|
+
"scene's layout or call-to-action placement.",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
}));
|
|
70
|
+
server.registerPrompt("xr_comfort_review", {
|
|
71
|
+
title: "XR comfort & drop-off review",
|
|
72
|
+
description: "Review VR/AR comfort signals for a scene (or the whole project): rapid head rotation, " +
|
|
73
|
+
"locomotion style, session abandonment, and input-source mix.",
|
|
74
|
+
argsSchema: { scene: sceneArg },
|
|
75
|
+
}, ({ scene }) => ({
|
|
76
|
+
messages: [
|
|
77
|
+
{
|
|
78
|
+
role: "user",
|
|
79
|
+
content: {
|
|
80
|
+
type: "text",
|
|
81
|
+
text: `Review XR/immersive comfort and drop-off for ${forScene(scene)}.\n\n` +
|
|
82
|
+
"Use these read-only tools" +
|
|
83
|
+
(scene ? ` (scene="${scene}")` : "") +
|
|
84
|
+
" and correlate the signals:\n" +
|
|
85
|
+
"- `xr_rotation` for rapid head/view turns (a motion-sickness proxy).\n" +
|
|
86
|
+
"- `xr_locomotion` for the fly/navigate/teleport mix and session span.\n" +
|
|
87
|
+
"- `xr_abandonment` for short XR sessions that signal headset drop-off.\n" +
|
|
88
|
+
"- `xr_sources` for the hand vs. controller vs. gaze input split.\n\n" +
|
|
89
|
+
"Flag likely-uncomfortable patterns (heavy rapid rotation or continuous locomotion " +
|
|
90
|
+
"paired with early exits) and suggest comfort mitigations.",
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AAEH,MAAM,QAAQ,GAAG,CAAC;KACf,MAAM,EAAE;KACR,QAAQ,EAAE;KACV,QAAQ,CAAC,kFAAkF,CAAC,CAAC;AAEhG,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,EAAE;KACR,QAAQ,CAAC,+DAA+D,CAAC,CAAC;AAE7E,MAAM,QAAQ,GAAG,CAAC,KAAyB,EAAU,EAAE,CACrD,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,0BAA0B,CAAC;AAE1D,2DAA2D;AAC3D,MAAM,UAAU,eAAe,CAAC,MAAiB;IAC/C,MAAM,CAAC,cAAc,CACnB,qBAAqB,EACrB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,gFAAgF;YAChF,8CAA8C;QAChD,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;KAChC,EACD,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EACF,sCAAsC,QAAQ,CAAC,KAAK,CAAC,gCAAgC;wBACrF,yDAAyD;wBACzD,6CAA6C;wBAC7C,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBACpC,KAAK;wBACL,gGAAgG;wBAChG,yCAAyC;wBACzC,kDAAkD;wBAClD,4DAA4D;wBAC5D,sFAAsF;wBACtF,wCAAwC;iBAC3C;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,oBAAoB,EACpB;QACE,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,+EAA+E;YAC/E,iEAAiE;QACnE,UAAU,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE;KACxC,EACD,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EACF,8CAA8C,KAAK,QAAQ;wBAC3D,oDAAoD;wBACpD,KAAK;wBACL,iCAAiC;wBACjC,iFAAiF;wBACjF,0DAA0D;wBAC1D,wDAAwD;wBACxD,qDAAqD;wBACrD,qFAAqF;wBACrF,6CAA6C;iBAChD;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,cAAc,CACnB,mBAAmB,EACnB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,wFAAwF;YACxF,8DAA8D;QAChE,UAAU,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE;KAChC,EACD,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE;oBACP,IAAI,EAAE,MAAM;oBACZ,IAAI,EACF,gDAAgD,QAAQ,CAAC,KAAK,CAAC,OAAO;wBACtE,2BAA2B;wBAC3B,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBACpC,+BAA+B;wBAC/B,wEAAwE;wBACxE,yEAAyE;wBACzE,0EAA0E;wBAC1E,sEAAsE;wBACtE,oFAAoF;wBACpF,2DAA2D;iBAC9D;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { CollectorClient } from "@uptimizr/agent-core";
|
|
3
|
+
/** URI of the static, machine-readable capabilities/schema descriptor. */
|
|
4
|
+
export declare const CAPABILITIES_URI = "uptimizr://capabilities";
|
|
5
|
+
/** URI of the live list of scenes with recent activity. */
|
|
6
|
+
export declare const SCENES_URI = "uptimizr://scenes";
|
|
7
|
+
/**
|
|
8
|
+
* Register read-only MCP resources so an agent can **self-discover** the surface
|
|
9
|
+
* (ADR 0050 §7):
|
|
10
|
+
*
|
|
11
|
+
* - `uptimizr://capabilities` — a static descriptor (event types, tool catalog,
|
|
12
|
+
* parameter semantics) built from the shared catalog + `@uptimizr/schema`. No
|
|
13
|
+
* collector call; it documents *what can be asked*.
|
|
14
|
+
* - `uptimizr://scenes` — the live set of scene ids with activity, fetched via
|
|
15
|
+
* the read-only collector client, so the `scene` parameter can be filled in
|
|
16
|
+
* with real values.
|
|
17
|
+
*
|
|
18
|
+
* Both are read-only; resources never mutate or expose raw per-session events.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerResources(server: McpServer, client: CollectorClient): void;
|
|
21
|
+
//# sourceMappingURL=resources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,2DAA2D;AAC3D,eAAO,MAAM,UAAU,sBAAsB,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAuClF"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { buildCapabilities } from "./capabilities.js";
|
|
2
|
+
/** URI of the static, machine-readable capabilities/schema descriptor. */
|
|
3
|
+
export const CAPABILITIES_URI = "uptimizr://capabilities";
|
|
4
|
+
/** URI of the live list of scenes with recent activity. */
|
|
5
|
+
export const SCENES_URI = "uptimizr://scenes";
|
|
6
|
+
/**
|
|
7
|
+
* Register read-only MCP resources so an agent can **self-discover** the surface
|
|
8
|
+
* (ADR 0050 §7):
|
|
9
|
+
*
|
|
10
|
+
* - `uptimizr://capabilities` — a static descriptor (event types, tool catalog,
|
|
11
|
+
* parameter semantics) built from the shared catalog + `@uptimizr/schema`. No
|
|
12
|
+
* collector call; it documents *what can be asked*.
|
|
13
|
+
* - `uptimizr://scenes` — the live set of scene ids with activity, fetched via
|
|
14
|
+
* the read-only collector client, so the `scene` parameter can be filled in
|
|
15
|
+
* with real values.
|
|
16
|
+
*
|
|
17
|
+
* Both are read-only; resources never mutate or expose raw per-session events.
|
|
18
|
+
*/
|
|
19
|
+
export function registerResources(server, client) {
|
|
20
|
+
server.registerResource("capabilities", CAPABILITIES_URI, {
|
|
21
|
+
title: "Uptimizr capabilities",
|
|
22
|
+
description: "Machine-readable descriptor of the read-only analytics surface: event types, the tool " +
|
|
23
|
+
"catalog, and parameter semantics. Read this first to learn what you can ask.",
|
|
24
|
+
mimeType: "application/json",
|
|
25
|
+
}, async (uri) => ({
|
|
26
|
+
contents: [
|
|
27
|
+
{
|
|
28
|
+
uri: uri.href,
|
|
29
|
+
mimeType: "application/json",
|
|
30
|
+
text: JSON.stringify(buildCapabilities(), null, 2),
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
}));
|
|
34
|
+
server.registerResource("scenes", SCENES_URI, {
|
|
35
|
+
title: "Active scenes",
|
|
36
|
+
description: "Live list of developer-assigned scene ids with recent activity — the valid values for " +
|
|
37
|
+
"the `scene` parameter across the tools.",
|
|
38
|
+
mimeType: "application/json",
|
|
39
|
+
}, async (uri) => {
|
|
40
|
+
const data = await client.get("api/v1/scenes", {});
|
|
41
|
+
return {
|
|
42
|
+
contents: [{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(data) }],
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=resources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAC1D,2DAA2D;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,mBAAmB,CAAC;AAE9C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAuB;IAC1E,MAAM,CAAC,gBAAgB,CACrB,cAAc,EACd,gBAAgB,EAChB;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,wFAAwF;YACxF,8EAA8E;QAChF,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,GAAG,CAAC,IAAI;gBACb,QAAQ,EAAE,kBAAkB;gBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;aACnD;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,gBAAgB,CACrB,QAAQ,EACR,UAAU,EACV;QACE,KAAK,EAAE,eAAe;QACtB,WAAW,EACT,wFAAwF;YACxF,yCAAyC;QAC3C,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QACnD,OAAO;YACL,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;SACxF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type CollectorClient } from "@uptimizr/agent-core";
|
|
3
3
|
/**
|
|
4
4
|
* Build the Uptimizr MCP server: a read-only `McpServer` whose tools each wrap
|
|
5
5
|
* one collector query endpoint via the injected `CollectorClient`. The server
|
|
6
6
|
* holds no business logic — it forwards validated arguments and returns the
|
|
7
|
-
* collector's JSON (ADR 0005 / ADR 0017).
|
|
7
|
+
* collector's JSON (ADR 0005 / ADR 0017). Alongside the tools it exposes
|
|
8
|
+
* capability-discovery **resources** and curated analysis **prompts** so agents
|
|
9
|
+
* can self-orient (ADR 0050 §7).
|
|
8
10
|
*/
|
|
9
11
|
export declare function createMcpServer(client: CollectorClient): McpServer;
|
|
10
12
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -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,KAAK,
|
|
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"}
|
package/dist/server.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { readTools } from "
|
|
2
|
+
import { readTools } from "@uptimizr/agent-core";
|
|
3
|
+
import { registerResources } from "./resources.js";
|
|
4
|
+
import { registerPrompts } from "./prompts.js";
|
|
3
5
|
import { version } from "./version.js";
|
|
4
6
|
/**
|
|
5
7
|
* Build the Uptimizr MCP server: a read-only `McpServer` whose tools each wrap
|
|
6
8
|
* one collector query endpoint via the injected `CollectorClient`. The server
|
|
7
9
|
* holds no business logic — it forwards validated arguments and returns the
|
|
8
|
-
* collector's JSON (ADR 0005 / ADR 0017).
|
|
10
|
+
* collector's JSON (ADR 0005 / ADR 0017). Alongside the tools it exposes
|
|
11
|
+
* capability-discovery **resources** and curated analysis **prompts** so agents
|
|
12
|
+
* can self-orient (ADR 0050 §7).
|
|
9
13
|
*/
|
|
10
14
|
export function createMcpServer(client) {
|
|
11
|
-
const server = new McpServer({ name: "uptimizr-mcp", version });
|
|
15
|
+
const server = new McpServer({ name: "uptimizr-mcp", version }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
|
|
12
16
|
for (const tool of readTools) {
|
|
13
17
|
server.registerTool(tool.name, {
|
|
14
18
|
title: tool.title,
|
|
@@ -26,6 +30,8 @@ export function createMcpServer(client) {
|
|
|
26
30
|
}
|
|
27
31
|
});
|
|
28
32
|
}
|
|
33
|
+
registerResources(server, client);
|
|
34
|
+
registerPrompts(server);
|
|
29
35
|
return server;
|
|
30
36
|
}
|
|
31
37
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uptimizr/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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",
|
|
@@ -48,12 +48,14 @@
|
|
|
48
48
|
"sideEffects": false,
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
51
|
-
"zod": "^4.
|
|
51
|
+
"zod": "^4.4.3",
|
|
52
|
+
"@uptimizr/agent-core": "0.2.1",
|
|
53
|
+
"@uptimizr/schema": "0.5.1"
|
|
52
54
|
},
|
|
53
55
|
"devDependencies": {
|
|
54
|
-
"@types/node": "^
|
|
55
|
-
"tsx": "^4.
|
|
56
|
-
"vitest": "^4.1.
|
|
56
|
+
"@types/node": "^26.1.0",
|
|
57
|
+
"tsx": "^4.23.0",
|
|
58
|
+
"vitest": "^4.1.10"
|
|
57
59
|
},
|
|
58
60
|
"engines": {
|
|
59
61
|
"node": ">=22"
|
package/dist/client.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { McpConfig } from "./config.js";
|
|
2
|
-
/** A query-string parameter map. `undefined` values are omitted from the request. */
|
|
3
|
-
export type QueryParams = Record<string, string | number | undefined>;
|
|
4
|
-
/**
|
|
5
|
-
* A minimal **read-only** HTTP client over the collector query API. It performs
|
|
6
|
-
* `GET` requests only and holds no business logic — it is a thin transport that
|
|
7
|
-
* mirrors the dashboard's `CollectorApi` so an agent reads the same aggregated
|
|
8
|
-
* results a human would (ADR 0005 / ADR 0017).
|
|
9
|
-
*/
|
|
10
|
-
export interface CollectorClient {
|
|
11
|
-
get(path: string, params?: QueryParams): Promise<unknown>;
|
|
12
|
-
}
|
|
13
|
-
/** Thrown when the collector responds with a non-2xx status. */
|
|
14
|
-
export declare class CollectorError extends Error {
|
|
15
|
-
readonly status: number;
|
|
16
|
-
constructor(message: string, status: number);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Build a read-only collector client bound to one `(collectorUrl, apiKey)` pair.
|
|
20
|
-
* `fetchImpl` is injectable for testing; it defaults to the global `fetch`.
|
|
21
|
-
*/
|
|
22
|
-
export declare function createCollectorClient(config: McpConfig, fetchImpl?: typeof fetch): CollectorClient;
|
|
23
|
-
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,qFAAqF;AACrF,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,gEAAgE;AAChE,qBAAa,cAAe,SAAQ,KAAK;IAGrC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBADvB,OAAO,EAAE,MAAM,EACN,MAAM,EAAE,MAAM;CAK1B;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,SAAS,EACjB,SAAS,GAAE,OAAO,KAAa,GAC9B,eAAe,CAmBjB"}
|
package/dist/client.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/** Thrown when the collector responds with a non-2xx status. */
|
|
2
|
-
export class CollectorError extends Error {
|
|
3
|
-
status;
|
|
4
|
-
constructor(message, status) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.status = status;
|
|
7
|
-
this.name = "CollectorError";
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
function ensureTrailingSlash(url) {
|
|
11
|
-
return url.endsWith("/") ? url : `${url}/`;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Build a read-only collector client bound to one `(collectorUrl, apiKey)` pair.
|
|
15
|
-
* `fetchImpl` is injectable for testing; it defaults to the global `fetch`.
|
|
16
|
-
*/
|
|
17
|
-
export function createCollectorClient(config, fetchImpl = fetch) {
|
|
18
|
-
const base = ensureTrailingSlash(config.collectorUrl);
|
|
19
|
-
return {
|
|
20
|
-
async get(path, params = {}) {
|
|
21
|
-
const url = new URL(path.replace(/^\//, ""), base);
|
|
22
|
-
for (const [key, value] of Object.entries(params)) {
|
|
23
|
-
if (value != null)
|
|
24
|
-
url.searchParams.set(key, String(value));
|
|
25
|
-
}
|
|
26
|
-
const res = await fetchImpl(url, {
|
|
27
|
-
method: "GET",
|
|
28
|
-
headers: { "x-api-key": config.apiKey },
|
|
29
|
-
});
|
|
30
|
-
if (!res.ok) {
|
|
31
|
-
const body = await res.text().catch(() => "");
|
|
32
|
-
throw new CollectorError(body || res.statusText, res.status);
|
|
33
|
-
}
|
|
34
|
-
return res.json();
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAeA,gEAAgE;AAChE,MAAM,OAAO,cAAe,SAAQ,KAAK;IAG5B;IAFX,YACE,OAAe,EACN,MAAc;QAEvB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFN,WAAM,GAAN,MAAM,CAAQ;QAGvB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED,SAAS,mBAAmB,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAiB,EACjB,YAA0B,KAAK;IAE/B,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IACtD,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,IAAY,EAAE,SAAsB,EAAE;YAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;YACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClD,IAAI,KAAK,IAAI,IAAI;oBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAC9D,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;gBAC/B,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE;aACxC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC9C,MAAM,IAAI,cAAc,CAAC,IAAI,IAAI,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/dist/tools.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { QueryParams } from "./client.js";
|
|
3
|
-
/** A resolved read request: the collector path and its query parameters. */
|
|
4
|
-
export interface ReadToolRequest {
|
|
5
|
-
path: string;
|
|
6
|
-
params: QueryParams;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* A read-only tool definition. `inputSchema` is a Zod raw shape the MCP runtime
|
|
10
|
-
* uses to validate arguments; `buildRequest` maps validated arguments to a
|
|
11
|
-
* `GET` against the collector. Definitions are pure and unit-testable without a
|
|
12
|
-
* live collector.
|
|
13
|
-
*/
|
|
14
|
-
export interface ReadTool {
|
|
15
|
-
name: string;
|
|
16
|
-
title: string;
|
|
17
|
-
description: string;
|
|
18
|
-
inputSchema: z.ZodRawShape;
|
|
19
|
-
buildRequest: (args: Record<string, unknown>) => ReadToolRequest;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* The catalog of read-only tools. Each wraps one documented collector query
|
|
23
|
-
* endpoint (docs/integration.md §Query). There are intentionally **no**
|
|
24
|
-
* ingestion, mutation, or raw per-session event tools — the surface is
|
|
25
|
-
* aggregate, read-only, and privacy-preserving (ADR 0003 / ADR 0017).
|
|
26
|
-
*/
|
|
27
|
-
export declare const readTools: readonly ReadTool[];
|
|
28
|
-
//# sourceMappingURL=tools.d.ts.map
|
package/dist/tools.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC,WAAW,CAAC;IAC3B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,eAAe,CAAC;CAClE;AAiCD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,SAAS,QAAQ,EAsKxC,CAAC"}
|
package/dist/tools.js
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
const num = (v) => (typeof v === "number" ? v : undefined);
|
|
3
|
-
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
4
|
-
// Shared, reusable input fields (all optional unless a tool needs otherwise).
|
|
5
|
-
const since = z.number().int().optional().describe("Start of the time range, epoch milliseconds.");
|
|
6
|
-
const until = z.number().int().optional().describe("End of the time range, epoch milliseconds.");
|
|
7
|
-
const bins = z.number().int().positive().max(500).optional().describe("Grid resolution per axis.");
|
|
8
|
-
const limit = z.number().int().positive().max(1000).optional().describe("Maximum rows to return.");
|
|
9
|
-
const scene = z.string().optional().describe("Restrict to one developer-assigned scene id.");
|
|
10
|
-
const session = z.string().optional().describe("Scope the aggregate to a single session id.");
|
|
11
|
-
const cellSize = z.number().positive().max(1000).optional().describe("Voxel size in world units.");
|
|
12
|
-
const interval = z
|
|
13
|
-
.number()
|
|
14
|
-
.int()
|
|
15
|
-
.positive()
|
|
16
|
-
.optional()
|
|
17
|
-
.describe("Time-series bucket width, seconds.");
|
|
18
|
-
const eventType = z
|
|
19
|
-
.string()
|
|
20
|
-
.optional()
|
|
21
|
-
.describe("Restrict to a single event type, e.g. pointer_click.");
|
|
22
|
-
const source = z
|
|
23
|
-
.enum(["mouse", "touch", "stylus", "pen", "xr-controller", "hand", "gaze", "transient", "other"])
|
|
24
|
-
.optional()
|
|
25
|
-
.describe("Restrict a pointer/world heatmap to one input source.");
|
|
26
|
-
/** Build the common `{ since, until }` range params from validated args. */
|
|
27
|
-
function range(args) {
|
|
28
|
-
return { since: num(args.since), until: num(args.until) };
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* The catalog of read-only tools. Each wraps one documented collector query
|
|
32
|
-
* endpoint (docs/integration.md §Query). There are intentionally **no**
|
|
33
|
-
* ingestion, mutation, or raw per-session event tools — the surface is
|
|
34
|
-
* aggregate, read-only, and privacy-preserving (ADR 0003 / ADR 0017).
|
|
35
|
-
*/
|
|
36
|
-
export const readTools = [
|
|
37
|
-
{
|
|
38
|
-
name: "list_sessions",
|
|
39
|
-
title: "List recent sessions",
|
|
40
|
-
description: "Recent sessions with id, visitor, event count, and start/end times.",
|
|
41
|
-
inputSchema: { since, until, limit },
|
|
42
|
-
buildRequest: (args) => ({
|
|
43
|
-
path: "api/v1/sessions",
|
|
44
|
-
params: { ...range(args), limit: num(args.limit) },
|
|
45
|
-
}),
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
name: "pointer_heatmap",
|
|
49
|
-
title: "2D pointer heatmap",
|
|
50
|
-
description: "Binned 2D pointer-position heatmap (screen-normalized).",
|
|
51
|
-
inputSchema: { since, until, bins, scene, source, session },
|
|
52
|
-
buildRequest: (args) => ({
|
|
53
|
-
path: "api/v1/heatmaps/pointer",
|
|
54
|
-
params: {
|
|
55
|
-
...range(args),
|
|
56
|
-
bins: num(args.bins),
|
|
57
|
-
scene: str(args.scene),
|
|
58
|
-
source: str(args.source),
|
|
59
|
-
session: str(args.session),
|
|
60
|
-
},
|
|
61
|
-
}),
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: "world_heatmap",
|
|
65
|
-
title: "3D world-space pointer heatmap",
|
|
66
|
-
description: "Voxelized world-space pointer heatmap.",
|
|
67
|
-
inputSchema: { since, until, cellSize, limit, scene, source },
|
|
68
|
-
buildRequest: (args) => ({
|
|
69
|
-
path: "api/v1/heatmaps/world",
|
|
70
|
-
params: {
|
|
71
|
-
...range(args),
|
|
72
|
-
cellSize: num(args.cellSize),
|
|
73
|
-
limit: num(args.limit),
|
|
74
|
-
scene: str(args.scene),
|
|
75
|
-
source: str(args.source),
|
|
76
|
-
},
|
|
77
|
-
}),
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
name: "camera_heatmap",
|
|
81
|
-
title: "View-direction heatmap",
|
|
82
|
-
description: "Camera view-direction distribution as spherical bins.",
|
|
83
|
-
inputSchema: { since, until, bins, scene, session },
|
|
84
|
-
buildRequest: (args) => ({
|
|
85
|
-
path: "api/v1/heatmaps/camera",
|
|
86
|
-
params: {
|
|
87
|
-
...range(args),
|
|
88
|
-
bins: num(args.bins),
|
|
89
|
-
scene: str(args.scene),
|
|
90
|
-
session: str(args.session),
|
|
91
|
-
},
|
|
92
|
-
}),
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
name: "click_rays",
|
|
96
|
-
title: "View-gated click rays",
|
|
97
|
-
description: "Clicks ASOF-joined to their nearest camera sample, per voxel and clicked mesh.",
|
|
98
|
-
inputSchema: { since, until, cellSize, limit, scene, source, session },
|
|
99
|
-
buildRequest: (args) => ({
|
|
100
|
-
path: "api/v1/heatmaps/click-rays",
|
|
101
|
-
params: {
|
|
102
|
-
...range(args),
|
|
103
|
-
cellSize: num(args.cellSize),
|
|
104
|
-
limit: num(args.limit),
|
|
105
|
-
scene: str(args.scene),
|
|
106
|
-
source: str(args.source),
|
|
107
|
-
session: str(args.session),
|
|
108
|
-
},
|
|
109
|
-
}),
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
name: "flow_links",
|
|
113
|
-
title: "Gaze→mesh flow links",
|
|
114
|
-
description: "Aggregate links from camera-direction bins to clicked meshes.",
|
|
115
|
-
inputSchema: { since, until, bins, limit, scene, session },
|
|
116
|
-
buildRequest: (args) => ({
|
|
117
|
-
path: "api/v1/heatmaps/flow",
|
|
118
|
-
params: {
|
|
119
|
-
...range(args),
|
|
120
|
-
bins: num(args.bins),
|
|
121
|
-
limit: num(args.limit),
|
|
122
|
-
scene: str(args.scene),
|
|
123
|
-
session: str(args.session),
|
|
124
|
-
},
|
|
125
|
-
}),
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: "top_meshes",
|
|
129
|
-
title: "Most-interacted meshes",
|
|
130
|
-
description: "Meshes ranked by interaction count.",
|
|
131
|
-
inputSchema: { since, until, limit, session },
|
|
132
|
-
buildRequest: (args) => ({
|
|
133
|
-
path: "api/v1/meshes/top",
|
|
134
|
-
params: { ...range(args), limit: num(args.limit), session: str(args.session) },
|
|
135
|
-
}),
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
name: "perf_summary",
|
|
139
|
-
title: "Rendering performance summary",
|
|
140
|
-
description: "Sample count and avg/min/p50 FPS over the range.",
|
|
141
|
-
inputSchema: { since, until, session },
|
|
142
|
-
buildRequest: (args) => ({
|
|
143
|
-
path: "api/v1/perf",
|
|
144
|
-
params: { ...range(args), session: str(args.session) },
|
|
145
|
-
}),
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
name: "list_scenes",
|
|
149
|
-
title: "List active scenes",
|
|
150
|
-
description: "Distinct developer-assigned scenes with activity.",
|
|
151
|
-
inputSchema: { since, until, limit },
|
|
152
|
-
buildRequest: (args) => ({
|
|
153
|
-
path: "api/v1/scenes",
|
|
154
|
-
params: { ...range(args), limit: num(args.limit) },
|
|
155
|
-
}),
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
name: "timeseries",
|
|
159
|
-
title: "Event-volume time series",
|
|
160
|
-
description: "Event-volume buckets over time, with average FPS per bucket.",
|
|
161
|
-
inputSchema: { since, until, interval, scene, type: eventType },
|
|
162
|
-
buildRequest: (args) => ({
|
|
163
|
-
path: "api/v1/timeseries",
|
|
164
|
-
params: {
|
|
165
|
-
...range(args),
|
|
166
|
-
interval: num(args.interval),
|
|
167
|
-
scene: str(args.scene),
|
|
168
|
-
type: str(args.type),
|
|
169
|
-
},
|
|
170
|
-
}),
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
name: "event_counts",
|
|
174
|
-
title: "Per-event-type counts",
|
|
175
|
-
description: "Counts per event type over the range (scene-health panel).",
|
|
176
|
-
inputSchema: { since, until, scene },
|
|
177
|
-
buildRequest: (args) => ({
|
|
178
|
-
path: "api/v1/event-counts",
|
|
179
|
-
params: { ...range(args), scene: str(args.scene) },
|
|
180
|
-
}),
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
name: "session_meta",
|
|
184
|
-
title: "Session descriptor",
|
|
185
|
-
description: "Coarse descriptor for one session (device/scene/user). No raw event stream.",
|
|
186
|
-
inputSchema: { sessionId: z.string().min(1).describe("The session id to describe.") },
|
|
187
|
-
buildRequest: (args) => ({
|
|
188
|
-
path: `api/v1/sessions/${encodeURIComponent(str(args.sessionId) ?? "")}/meta`,
|
|
189
|
-
params: {},
|
|
190
|
-
}),
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
name: "scene_representation",
|
|
194
|
-
title: "Scene representation",
|
|
195
|
-
description: "Registered proxy geometry (bounds/meshes) for one scene, if any.",
|
|
196
|
-
inputSchema: { sceneId: z.string().min(1).describe("The scene id to fetch.") },
|
|
197
|
-
buildRequest: (args) => ({
|
|
198
|
-
path: `api/v1/scenes/${encodeURIComponent(str(args.sceneId) ?? "")}/representation`,
|
|
199
|
-
params: {},
|
|
200
|
-
}),
|
|
201
|
-
},
|
|
202
|
-
];
|
|
203
|
-
//# sourceMappingURL=tools.js.map
|
package/dist/tools.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|