qyl-mcp-server 7.6.1 → 8.0.0
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/README.md +89 -89
- package/dist/analysis-budget.d.ts +8 -0
- package/dist/analysis-budget.js +73 -0
- package/dist/analysis-budget.js.map +1 -0
- package/dist/analysis-client.d.ts +5 -0
- package/dist/analysis-client.js +46 -0
- package/dist/analysis-client.js.map +1 -0
- package/dist/analysis-summary.d.ts +2 -0
- package/dist/analysis-summary.js +54 -0
- package/dist/analysis-summary.js.map +1 -0
- package/dist/analysis-tools.d.ts +3 -0
- package/dist/analysis-tools.js +167 -0
- package/dist/analysis-tools.js.map +1 -0
- package/dist/authorization.d.ts +2 -0
- package/dist/authorization.js +8 -6
- package/dist/authorization.js.map +1 -1
- package/dist/ci.d.ts +2 -23
- package/dist/ci.js +7 -108
- package/dist/ci.js.map +1 -1
- package/dist/collector-resources.d.ts +17 -25
- package/dist/collector-resources.js +33 -147
- package/dist/collector-resources.js.map +1 -1
- package/dist/collector.d.ts +7 -43
- package/dist/collector.js +22 -172
- package/dist/collector.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.js +2 -2
- package/dist/contract-handshake.js +0 -6
- package/dist/contract-handshake.js.map +1 -1
- package/dist/contract-validation.d.ts +0 -1
- package/dist/contract-validation.js +0 -1
- package/dist/contract-validation.js.map +1 -1
- package/dist/data.d.ts +3 -69
- package/dist/data.js +6 -182
- package/dist/data.js.map +1 -1
- package/dist/events-authorization.d.ts +1 -1
- package/dist/events.d.ts +3 -2
- package/dist/events.js +1 -1
- package/dist/events.js.map +1 -1
- package/dist/main.d.ts +1 -8
- package/dist/main.js +6 -10
- package/dist/main.js.map +1 -1
- package/dist/mcp-app.html +2 -3
- package/dist/mcp-dashboard.html +3 -4
- package/dist/mcp-home.html +1 -1
- package/dist/metrics-tools.d.ts +0 -14
- package/dist/metrics-tools.js +14 -71
- package/dist/metrics-tools.js.map +1 -1
- package/dist/request-scope.d.ts +3 -0
- package/dist/request-scope.js +7 -3
- package/dist/request-scope.js.map +1 -1
- package/dist/secret-redactor.js +13 -0
- package/dist/secret-redactor.js.map +1 -1
- package/dist/server.d.ts +3 -16
- package/dist/server.js +24 -123
- package/dist/server.js.map +1 -1
- package/dist/summaries.d.ts +2 -45
- package/dist/summaries.js +1 -207
- package/dist/summaries.js.map +1 -1
- package/dist/tool-scopes.js +2 -14
- package/dist/tool-scopes.js.map +1 -1
- package/dist/tools.d.ts +0 -4
- package/dist/tools.js +18 -170
- package/dist/tools.js.map +1 -1
- package/dist/write-tools.d.ts +12 -4
- package/dist/write-tools.js +21 -75
- package/dist/write-tools.js.map +1 -1
- package/package.json +13 -8
- package/dist/demo.d.ts +0 -41
- package/dist/demo.js +0 -941
- package/dist/demo.js.map +0 -1
- package/dist/metrics.d.ts +0 -35
- package/dist/metrics.js +0 -266
- package/dist/metrics.js.map +0 -1
- package/dist/paging.d.ts +0 -16
- package/dist/paging.js +0 -33
- package/dist/paging.js.map +0 -1
- package/dist/stats.d.ts +0 -18
- package/dist/stats.js +0 -144
- package/dist/stats.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@ logs, metrics, sessions and CI runs, plus the Trace Explorer and MCP Dashboard
|
|
|
5
5
|
viewers for hosts that render MCP Apps.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
bunx qyl-mcp-server --stdio # stdio MCP server
|
|
9
|
+
bunx qyl-mcp-server # Streamable HTTP on 127.0.0.1:3001
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Use a modern or 2025-era MCP client. Point it at a collector:
|
|
@@ -27,7 +27,6 @@ its own.
|
|
|
27
27
|
Both use MCP TypeScript SDK v2: Streamable HTTP through `createMcpHandler`
|
|
28
28
|
and stdio through `serveStdio`, with their documented compatibility defaults.
|
|
29
29
|
One factory serves revision `2026-07-28` and supported 2025-era requests.
|
|
30
|
-
Events require `2026-07-28`.
|
|
31
30
|
The HTTP server serves a product page at `/`; `/mcp` is the only protocol
|
|
32
31
|
endpoint.
|
|
33
32
|
|
|
@@ -39,7 +38,8 @@ with PKCE S256, both `private_key_jwt` and `none` for ChatGPT CIMD compatibility
|
|
|
39
38
|
issuance; this server validates resource-bound RFC 9068 access tokens on every
|
|
40
39
|
MCP request. It rejects malformed/query credentials, invalid tokens and
|
|
41
40
|
insufficient scopes with distinct 400/401/403 responses. Every request needs
|
|
42
|
-
`qyl:read
|
|
41
|
+
`qyl:read`. The initial 401 requests `qyl:read qyl:write qyl:delete` so new
|
|
42
|
+
connections can authorize the complete tool set. A write tool called without `qyl:write` or `qyl:delete` gets a
|
|
43
43
|
`403` with `error="insufficient_scope"` naming the scopes to request, in both
|
|
44
44
|
protocol eras, before the handler runs.
|
|
45
45
|
|
|
@@ -63,81 +63,55 @@ an enabled module proves a client has been provisioned.
|
|
|
63
63
|
|
|
64
64
|
## Tools
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
`list_traces` filters by a `start_time`/`end_time` window (RFC 3339, start
|
|
70
|
-
inclusive, end exclusive), `service_name` (traces with a span from that
|
|
71
|
-
service) and `errors_only`. `list_sessions` filters by `active_only` and the
|
|
72
|
-
same window on the session start. `search_logs` filters by `trace_id`,
|
|
73
|
-
`session_id`, `service_name`, `severity_min`, a body substring `query` and the
|
|
74
|
-
window. Every list tool pages the same way: the output carries `has_more` and,
|
|
75
|
-
when more exist, `next_cursor`; pass it back as `cursor` with the same filters
|
|
76
|
-
for the next page. A cursor is opaque; one that is not ours is refused with
|
|
77
|
-
`invalid_argument` rather than answered with the first page again.
|
|
78
|
-
|
|
79
|
-
`get_trace` returns every span by default. `errors_only` selects error spans;
|
|
80
|
-
`max_spans` (1–1000) caps the result after filtering in Collector order.
|
|
81
|
-
`include_attributes=false` omits span, resource, event, link and instrumentation
|
|
82
|
-
scope attribute collections, including any returned root-span copy. Trace
|
|
83
|
-
totals remain the Collector's totals; the text reports matching and returned
|
|
84
|
-
counts. `ci_log.service_prefix` is case-sensitive, defaults to `qyl-ci`, and
|
|
85
|
-
filters both recent runs and individual phase spans.
|
|
86
|
-
|
|
87
|
-
**Metrics** — `list_metrics`, `get_metric_series`, `query_metric`. Read in that
|
|
88
|
-
order: the catalog gives you an exact instrument name and how many attribute
|
|
89
|
-
streams it has, series discovery tells you which attribute keys are worth
|
|
90
|
-
grouping or filtering on, and the range query answers the actual question —
|
|
91
|
-
a window, a bucket width in whole milliseconds (`step_ms`), a reducer (`avg`,
|
|
92
|
-
`min`, `max`, `sum`, `count`, `last`, `p50`, `p90`, `p95`, `p99`), optional
|
|
93
|
-
`group_by` keys, and optional `matchers`, each `{ key, op, value }` with `op`
|
|
94
|
-
`eq` (exact) or `prefix`; the server serializes them to the Collector's
|
|
95
|
-
`attr` / `attr_prefix` parameters. One bucket spanning the whole window
|
|
96
|
-
collapses the answer to a single number. The catalog and the series list page
|
|
97
|
-
with `cursor` like the telemetry lists.
|
|
98
|
-
|
|
99
|
-
**App-only** — `fetch_telemetry` is called by the bundled MCP Apps, not by a
|
|
100
|
-
model. Its input is one of four shapes selected by `view` (`traces`, `trace`,
|
|
101
|
-
`logs`, `mcp_stats`); the `trace` view requires `trace_id` at the schema layer.
|
|
102
|
-
|
|
103
|
-
**Writes** — `create_annotation`, `update_annotation`, `create_saved_query`,
|
|
104
|
-
`update_saved_query` and `delete` change only objects users create in qyl, in
|
|
105
|
-
the caller's Collector project: annotations (plain-text notes of at most 2000
|
|
106
|
-
characters on a trace, span or session) and saved queries (named filters for
|
|
107
|
-
traces, logs or metrics). `delete` takes `kind` (`annotation` or
|
|
108
|
-
`saved_query`; alert rules follow with Contract 11.7.0), `id` and `etag`. No
|
|
109
|
-
tool deletes or edits traces, logs or metrics; retention removes telemetry.
|
|
110
|
-
Updates and deletes send the `etag` as `If-Match`: a stale one fails with
|
|
111
|
-
`precondition_failed`, a duplicate saved-query name with `conflict`.
|
|
112
|
-
`list_saved_queries` and `run_saved_query` read saved queries; `get_trace` and
|
|
113
|
-
`list_sessions` return the annotations on what they read. Demo mode keeps none
|
|
114
|
-
of these objects and refuses these tools.
|
|
115
|
-
|
|
116
|
-
**Failures** — every failed call returns `isError: true`, the message as text,
|
|
117
|
-
and `structuredContent.error = { code, message, retryable }` with the
|
|
118
|
-
contract's `ToolErrorCode`.
|
|
119
|
-
|
|
120
|
-
The thirteen read tools carry `readOnlyHint: true` and only query the
|
|
121
|
-
configured collector. The create tools carry `destructiveHint: false` and
|
|
122
|
-
`idempotentHint: false`; the update tools and `delete` carry
|
|
123
|
-
`destructiveHint: true` and `idempotentHint: true`. On the hosted server
|
|
124
|
-
`qyl:read` covers the read tools, `qyl:write` adds the create and update tools,
|
|
125
|
-
and `qyl:delete` adds `delete`.
|
|
126
|
-
|
|
127
|
-
The `display_*` tools return MCP Apps UI resources as single-file viewers.
|
|
128
|
-
|
|
129
|
-
Every tool runs inside its request scope. Cancellation: a
|
|
130
|
-
`notifications/cancelled` for the request, or a closed connection, aborts the
|
|
131
|
-
in-flight collector fetch instead of waiting out its timeout. Progress: a
|
|
132
|
-
request that carries a `progressToken` gets `notifications/progress` per
|
|
133
|
-
completed step, one per collector round trip plus a final "Result ready"
|
|
134
|
-
(`ci_log` with a `run_id` reports the flatten into legs as a step of its own).
|
|
135
|
-
Logging: the server declares no `logging` capability and sends no
|
|
136
|
-
`notifications/message`, including when a client supplies a log level.
|
|
137
|
-
Operational error diagnostics go to stderr; native tool timing/status telemetry
|
|
138
|
-
uses OpenTelemetry. Requested progress and cancellation remain available.
|
|
139
|
-
[Source and test commands/output, 2026-10-08](https://github.com/ANcpLua/qyl.mcp/blob/main/docs/evidence/2026-10-08-followup-01.md).
|
|
66
|
+
The server publishes 32 tools, including one app-only read tool. Reads use the collector's
|
|
67
|
+
analysis queries and the generated qyl API contracts.
|
|
140
68
|
|
|
69
|
+
| Purpose | Tools |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| Investigate failures | `triage`, `list_failures`, `get_failure_context`, `compare_groups`, `compare_traces`, `verify_fix` |
|
|
72
|
+
| Explore telemetry | `aggregate_telemetry`, `discover_attributes`, `get_agent_run`, `list_releases`, `get_service_map`, `check_telemetry_health`, `get_mcp_stats` |
|
|
73
|
+
| Read executions | `list_sessions`, `list_traces`, `get_trace`, `search_logs`, `ci_log` |
|
|
74
|
+
| Read metrics | `list_metrics`, `get_metric_series`, `query_metric` |
|
|
75
|
+
| Saved questions | `list_saved_queries`, `run_saved_query` |
|
|
76
|
+
| Interactive views | `display_traces`, `display_mcp_dashboard`, `fetch_telemetry` (app-only) |
|
|
77
|
+
| Write project records | `create_annotation`, `update_annotation`, `create_saved_query`, `update_saved_query`, `delete`, `update_failure_status` |
|
|
78
|
+
|
|
79
|
+
Read tools accept an absolute RFC 3339 time window or `lookback_minutes` and report the
|
|
80
|
+
resolved `window` and `coverage`: examined, matched and returned counts, truncation,
|
|
81
|
+
scan completeness and observation time. Unknown counts are null. Filtering happens before
|
|
82
|
+
pagination; reuse an opaque `next_cursor` with the same filters to continue a page.
|
|
83
|
+
|
|
84
|
+
Shared matchers support `eq`, `neq`, `in`, `prefix`, `contains`, `exists`, `gt`, `gte`,
|
|
85
|
+
`lt` and `lte`, with span, resource or log scope. Span durations are milliseconds;
|
|
86
|
+
metrics retain their recorded units. Histogram percentiles identify their approximation,
|
|
87
|
+
and cumulative counter changes account for resets. Verification reports insufficient
|
|
88
|
+
traffic as pending rather than calling an unobserved failure fixed.
|
|
89
|
+
|
|
90
|
+
`get_trace` supports all spans, errors, errors with ancestors, or the critical path,
|
|
91
|
+
selected attributes and correlated logs. `display_traces` preserves the selected span
|
|
92
|
+
and can compare two executions. Notes and bookmarks are created only through explicit
|
|
93
|
+
viewer actions. `display_mcp_dashboard` uses the same MCP aggregates as `get_mcp_stats`,
|
|
94
|
+
shows the numerator and denominator behind rates, classifies failures, and opens matching
|
|
95
|
+
calls from aggregate selections. `fetch_telemetry` serves five app-only views: traces,
|
|
96
|
+
trace, logs, MCP statistics and comparison, with incremental refresh and field selection.
|
|
97
|
+
|
|
98
|
+
The 26 read tools carry `readOnlyHint: true`. Six write tools change annotations, saved
|
|
99
|
+
queries or failure status in the caller's project. An annotation can target a trace, span,
|
|
100
|
+
session or failure and has optional labels and a classification. A bookmark is a note
|
|
101
|
+
labelled `bookmark`. Updates and deletes require the current `etag`; stale writes are
|
|
102
|
+
rejected. Create calls reuse the stored result for 24 hours. Without an explicit
|
|
103
|
+
`idempotency_key`, the server derives one from the project, operation and request
|
|
104
|
+
body, so identical retries are safe. Supply a different key to deliberately create
|
|
105
|
+
another identical record. No tool edits or deletes recorded telemetry.
|
|
106
|
+
|
|
107
|
+
`qyl:read` covers reads, `qyl:write` adds creation and updates, and `qyl:delete` permits
|
|
108
|
+
`delete`. A missing scope returns the supported OAuth step-up challenge. Failed calls
|
|
109
|
+
carry a stable code, retryability, the problem type and field-level validation details
|
|
110
|
+
when available. Secrets are redacted before model text or structured content is returned.
|
|
111
|
+
|
|
112
|
+
Every tool runs inside its request scope, forwarding cancellation to the collector.
|
|
113
|
+
Requested progress reports completion; no logging notifications are sent to clients.
|
|
114
|
+
Analysis reads require a live collector. Synthetic data is used only by test fixtures, and is never substituted when a collector fails.
|
|
141
115
|
|
|
142
116
|
Every inbound `tools/call` on a local server — `--stdio`, or HTTP without
|
|
143
117
|
`MCP_PUBLIC_URL` — records only its tool name, timing, status and error type,
|
|
@@ -155,14 +129,13 @@ multi-tenant audit log.
|
|
|
155
129
|
| --- | --- |
|
|
156
130
|
| `QYL_COLLECTOR_URL` | Collector read API base; default `http://127.0.0.1:5100`. Also the OTLP base when set. |
|
|
157
131
|
| `QYL_API_KEY` | Collector credential for reads and OTLP; the write tools need the Collector's `write` and `delete` roles on it. Outgoing only. |
|
|
158
|
-
| `QYL_PROJECT` | Server-owned collector project scope. Unset, the server sends no project-scope header, so the Collector's default project applies
|
|
132
|
+
| `QYL_PROJECT` | Server-owned collector project scope. Unset, the server sends no project-scope header, so the Collector's default project applies. Never accepted as tool input. This is the only place that states the default; other documents link here. |
|
|
159
133
|
| `MCP_COLLECTOR_PROJECTS` | Optional secret JSON mapping validated Auth0 subjects to project-bound Collector keys; see account isolation below. |
|
|
160
134
|
| `QYL_OTLP_ENDPOINT` | Optional OTLP base for self-telemetry. |
|
|
161
|
-
| `QYL_DEMO=1` | Explicit, visibly labelled demo telemetry. A collector failure never silently substitutes demo data. |
|
|
162
135
|
| `QYL_MCP_TELEMETRY=0` | Disable MCP spans, metrics, and operation logs. |
|
|
163
136
|
| `QYL_MCP_CAPTURE_CONTENT=1` | Workbench content capture; native incoming tool-call telemetry never supplies request or response bodies. |
|
|
164
137
|
| `QYL_MCP_NATIVE_STATE_PATH` | Override the native execution-evidence path. |
|
|
165
|
-
| `MCP_EVENTS_STORE` |
|
|
138
|
+
| `MCP_EVENTS_STORE` | Optional internal Events subscription file; leave unset for the shared ChatGPT/Claude deployment. |
|
|
166
139
|
| `MCP_EVENTS_AUTH0_CLIENT_ID` / `MCP_EVENTS_AUTH0_CLIENT_SECRET` | Dedicated Management API application with `read:users`, `read:clients`, `read:client_grants`, `read:grants`; resolves CIMD identities and keeps access checks current without storing subscriber tokens. |
|
|
167
140
|
| `MCP_EVENTS_POLL_MS` | Collector polling interval, at least 5000 ms; default 30000 ms. |
|
|
168
141
|
| `PORT` | HTTP listener port; default `3001`. |
|
|
@@ -170,9 +143,8 @@ multi-tenant audit log.
|
|
|
170
143
|
Secrets are redacted before results reach the model, structured content, or
|
|
171
144
|
durable evidence.
|
|
172
145
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
so serving it requires Bun.
|
|
146
|
+
`npx` and `pnpm dlx` also work when Bun 1.4 or newer is installed.
|
|
147
|
+
Both the HTTP and stdio executables use Bun 1.4 or newer.
|
|
176
148
|
|
|
177
149
|
### Account isolation for hosted Auth0
|
|
178
150
|
|
|
@@ -202,20 +174,48 @@ existing deployment-wide credential behavior is retained.
|
|
|
202
174
|
|
|
203
175
|
Only the verified SDK `AuthInfo.extra.subject` selects the project. Tool inputs
|
|
204
176
|
and request metadata cannot override it. All telemetry tools, viewer refreshes
|
|
205
|
-
|
|
206
|
-
assignment revokes its Events subscription on the next access check. Project
|
|
177
|
+
use that account's project credential. Project
|
|
207
178
|
keys are redacted from text and structured results, including keys nested in
|
|
208
179
|
this JSON configuration. Keep the map in host secrets and out of the plugin ZIP.
|
|
209
180
|
|
|
210
181
|
`bun run smoke:projects` from the repository root checks every tool, the
|
|
211
|
-
writes included, viewer query paths
|
|
212
|
-
real local Collector with two temporary projects.
|
|
213
|
-
|
|
182
|
+
writes included, viewer query paths and both protocol eras against a
|
|
183
|
+
real local Collector with two temporary projects. It reuses the completed Release
|
|
184
|
+
build; set `QYL_COLLECTOR_DLL` for another build. The script uses local test identities
|
|
214
185
|
and an in-process signed webhook receiver; the hosted reviewer OAuth login and
|
|
215
186
|
real ChatGPT demonstration are separate checks before upload.
|
|
216
187
|
|
|
188
|
+
### Seeded analysis verification
|
|
189
|
+
|
|
190
|
+
`bun run --cwd server test:answer-key` starts a fresh temporary collector database,
|
|
191
|
+
seeds real OTLP, and runs the 32 analysis checks through MCP and generated validators.
|
|
192
|
+
It reuses the collector's completed build; set `QYL_COLLECTOR_DLL` when its location
|
|
193
|
+
or configuration differs. `mise run check` includes this verification and the quiet
|
|
194
|
+
SSE check. No pre-existing temporary file or manually seeded database is required.
|
|
195
|
+
|
|
196
|
+
`QYL_BIN=/path/to/installed/qyl node live-tools-smoke.mjs` additionally checks
|
|
197
|
+
all 32 tools against an isolated collector started by the published CLI.
|
|
198
|
+
|
|
217
199
|
## Release notes
|
|
218
200
|
|
|
201
|
+
### 8.0.0
|
|
202
|
+
|
|
203
|
+
- The executable now requires Bun 1.4 or later, including stdio. Library subpaths remain usable on Node 24; TypeScript 7 continues to emit the package.
|
|
204
|
+
- Start HTTP explicitly with a 60-second idle timeout so quiet SSE responses survive the SDK keep-alive. Stop the HTTP server during shutdown.
|
|
205
|
+
- Request read, write and delete scopes at initial sign-in; step-up challenges name only missing scopes.
|
|
206
|
+
- Return useful text summaries, bounded evidence and continuations; validate failure updates and make create retries idempotent by default.
|
|
207
|
+
- Use collector contract 12.1.1 for corrected analysis paging, coverage and failure timestamps. Remove the obsolete demo runtime and duplicate read implementations.
|
|
208
|
+
- Pin SemanticConventions 9.9.1, including the canonical `qyl.gen_ai.tool.call.arguments_hash` definition used by collector 12.1.1 for repeated-call analysis.
|
|
209
|
+
- Preserve note drafts, render trace drill-down results and use consistent dashboard filters. Gate the real OTLP answer-key and Bun quiet-stream regressions.
|
|
210
|
+
|
|
211
|
+
### 7.7.0
|
|
212
|
+
|
|
213
|
+
- Expand to 32 tools: failure triage and lifecycle, trace/group comparisons, fix verification, telemetry aggregation and discovery, agent runs, releases, service maps, telemetry health and MCP statistics.
|
|
214
|
+
- Use the collector's shared typed analysis contracts for filtering, pagination, coverage and saved-query execution; retain official SDKs/exporters and project-scoped authorization.
|
|
215
|
+
- Add responsive trace comparison, explicit note/bookmark controls, dashboard filters and drill-downs, with denominator counts behind rates.
|
|
216
|
+
- Preserve numeric agent token usage during secret redaction, and verify the new surface against real OTLP fixtures plus both protocol eras.
|
|
217
|
+
|
|
218
|
+
|
|
219
219
|
### 7.6.1
|
|
220
220
|
|
|
221
221
|
- Manage existing Auth0 API permissions, client grants and mapped-user permissions with scoped tenant configuration and a drift check.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/server";
|
|
2
|
+
export declare const ANALYSIS_RESPONSE_BYTES = 24000;
|
|
3
|
+
export declare const responseBytes: (result: object) => number;
|
|
4
|
+
/** Final compaction for a single large record, after the Collector has paged it.
|
|
5
|
+
* Stable identities, counts and signed continuations are preserved. Bulk text and
|
|
6
|
+
* nested evidence can be omitted; totals and the text response explain the loss.
|
|
7
|
+
*/
|
|
8
|
+
export declare function compactAnalysisResult(operation: string, original: object): CallToolResult;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { analysisSummary } from "./analysis-summary.js";
|
|
2
|
+
import { telemetryToolResult } from "./telemetry-redaction.js";
|
|
3
|
+
export const ANALYSIS_RESPONSE_BYTES = 24_000;
|
|
4
|
+
export const responseBytes = (result) => Buffer.byteLength(JSON.stringify(result), "utf8");
|
|
5
|
+
/** Final compaction for a single large record, after the Collector has paged it.
|
|
6
|
+
* Stable identities, counts and signed continuations are preserved. Bulk text and
|
|
7
|
+
* nested evidence can be omitted; totals and the text response explain the loss.
|
|
8
|
+
*/
|
|
9
|
+
export function compactAnalysisResult(operation, original) {
|
|
10
|
+
const output = structuredClone(original);
|
|
11
|
+
const totals = { ...output.page_totals };
|
|
12
|
+
let omitted = 0;
|
|
13
|
+
let shortened = 0;
|
|
14
|
+
const coverage = { ...output.coverage, truncated: true, returned: null };
|
|
15
|
+
output.coverage = coverage;
|
|
16
|
+
output.page_totals = totals;
|
|
17
|
+
const result = () => telemetryToolResult(`${analysisSummary(operation, output)}\nResponse budget: ${omitted} other evidence item(s) omitted; ${shortened} text field(s) shortened. Narrow the filters or use the continuation for more evidence.`, output);
|
|
18
|
+
// These fields are descriptions/content, never identifiers, credentials or cursors.
|
|
19
|
+
const textFields = new Set(["body", "text", "message", "status_message", "description", "brief", "summary", "pattern", "value", "name"]);
|
|
20
|
+
function trimText(value, cap) {
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
for (const item of value)
|
|
23
|
+
trimText(item, cap);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (value === null || typeof value !== "object")
|
|
27
|
+
return;
|
|
28
|
+
for (const [key, item] of Object.entries(value)) {
|
|
29
|
+
if (typeof item === "string" && item.length > cap && textFields.has(key)) {
|
|
30
|
+
value[key] = `${Array.from(item).slice(0, cap).join("")}…`;
|
|
31
|
+
shortened++;
|
|
32
|
+
}
|
|
33
|
+
else
|
|
34
|
+
trimText(item, cap);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
trimText(output, 512);
|
|
38
|
+
for (let iteration = 0; responseBytes(result()) > ANALYSIS_RESPONSE_BYTES && iteration < 128; iteration++) {
|
|
39
|
+
const arrays = [];
|
|
40
|
+
function collect(value, path) {
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
if (value.length > 0)
|
|
43
|
+
arrays.push({ values: value, path, bytes: responseBytes(value) });
|
|
44
|
+
value.forEach((item, index) => collect(item, `${path}.${index}`));
|
|
45
|
+
}
|
|
46
|
+
else if (value !== null && typeof value === "object") {
|
|
47
|
+
for (const [key, item] of Object.entries(value)) {
|
|
48
|
+
if (key !== "page_totals" && key !== "coverage")
|
|
49
|
+
collect(item, path ? `${path}.${key}` : key);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
collect(output, "");
|
|
54
|
+
// Prefer removing bulk inside a trace over removing the trace itself.
|
|
55
|
+
arrays.sort((a, b) => (b.path.split(".").length > 1 ? b.bytes : b.bytes / 4) - (a.path.split(".").length > 1 ? a.bytes : a.bytes / 4));
|
|
56
|
+
const candidate = arrays[0];
|
|
57
|
+
if (!candidate) {
|
|
58
|
+
trimText(output, 64);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
const removed = candidate.values.splice(Math.floor(candidate.values.length / 2)).length;
|
|
62
|
+
omitted += removed;
|
|
63
|
+
totals[`other.${candidate.path}`] = (totals[`other.${candidate.path}`] ?? 0) + removed;
|
|
64
|
+
}
|
|
65
|
+
// A cursor can encode large filters. Keeping it must not defeat the response cap.
|
|
66
|
+
if (responseBytes(result()) > ANALYSIS_RESPONSE_BYTES) {
|
|
67
|
+
delete output.next_cursor;
|
|
68
|
+
delete output.next_phase_cursor;
|
|
69
|
+
trimText(output, 64);
|
|
70
|
+
}
|
|
71
|
+
return result();
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=analysis-budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysis-budget.js","sourceRoot":"","sources":["../src/analysis-budget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Shared HTTP transport; every callable analysis operation is registered by name. */
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/server";
|
|
3
|
+
import type * as z from "zod/v4";
|
|
4
|
+
import type { ToolScope } from "./request-scope.js";
|
|
5
|
+
export declare function queryAnalysis<Input extends object, Output extends object>(operation: string, input: Input, schema: z.ZodType<Output>, scope: ToolScope): Promise<CallToolResult>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { CollectorError, collectorPost, parseCollectorBody } from "./collector.js";
|
|
2
|
+
import { ANALYSIS_RESPONSE_BYTES, compactAnalysisResult, responseBytes } from "./analysis-budget.js";
|
|
3
|
+
import { analysisSummary } from "./analysis-summary.js";
|
|
4
|
+
import { telemetryToolResult } from "./telemetry-redaction.js";
|
|
5
|
+
export async function queryAnalysis(operation, input, schema, scope) {
|
|
6
|
+
const path = `/api/v1/analysis/${operation}`;
|
|
7
|
+
const deadline = Date.now() + 55_000;
|
|
8
|
+
let query = input;
|
|
9
|
+
let previousPageSize = Infinity;
|
|
10
|
+
for (;;) {
|
|
11
|
+
const remaining = deadline - Date.now();
|
|
12
|
+
if (remaining <= 0)
|
|
13
|
+
throw new CollectorError("The query exceeded its time budget; narrow the time window and matchers.");
|
|
14
|
+
const response = await collectorPost(path, query, { ...scope.collector, timeoutMs: remaining });
|
|
15
|
+
const output = parseCollectorBody(response, path, schema);
|
|
16
|
+
const result = telemetryToolResult(analysisSummary(operation, output), output);
|
|
17
|
+
// Bytes give a conservative upper bound even for token-dense identifiers.
|
|
18
|
+
const bytes = responseBytes(result);
|
|
19
|
+
if (bytes <= ANALYSIS_RESPONSE_BYTES) {
|
|
20
|
+
await scope.step(`Queried ${operation}`);
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
// Re-query the collector so its cursor, coverage and totals describe the
|
|
24
|
+
// smaller page. Never slice a response and leave its paging metadata stale.
|
|
25
|
+
const args = query;
|
|
26
|
+
const page = output;
|
|
27
|
+
const traceView = operation === "get_trace" || operation === "fetch_telemetry" && args.view === "trace";
|
|
28
|
+
const sizeKey = traceView ? "max_spans" : operation === "query_metric" ? "series_limit" : operation === "get_agent_run" ? "max_steps" : "limit";
|
|
29
|
+
const trace = page.trace;
|
|
30
|
+
const observed = page.observed;
|
|
31
|
+
const sizes = [trace?.spans?.length, observed?.error_spans?.length, observed?.logs?.length,
|
|
32
|
+
...Object.values(page).filter(Array.isArray).map((items) => items.length)].filter((size) => size !== undefined);
|
|
33
|
+
const pageSize = Math.max(0, ...sizes);
|
|
34
|
+
if (pageSize > 1 && pageSize < previousPageSize) {
|
|
35
|
+
previousPageSize = pageSize;
|
|
36
|
+
const limit = Math.max(1, Math.floor(pageSize * ANALYSIS_RESPONSE_BYTES / bytes * 0.8));
|
|
37
|
+
// The collector creates the smaller page and its continuation together.
|
|
38
|
+
query = { ...args, ...page.window, [sizeKey]: limit,
|
|
39
|
+
...(operation === "get_failure_context" ? { max_spans: limit, max_logs: limit } : {}) };
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
await scope.step(`Queried ${operation}; large evidence compacted`);
|
|
43
|
+
return compactAnalysisResult(operation, output);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=analysis-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysis-client.js","sourceRoot":"","sources":["../src/analysis-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Compact evidence for hosts that show text without expanding structuredContent. */
|
|
2
|
+
export function analysisSummary(operation, output) {
|
|
3
|
+
const data = output;
|
|
4
|
+
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
5
|
+
const short = (value) => (value == null ? "unknown" : typeof value === "string" ? value : JSON.stringify(value) ?? "unknown").replace(/\s+/gu, " ").slice(0, 180);
|
|
6
|
+
const lines = [operation.replaceAll("_", " ")];
|
|
7
|
+
const coverage = record(data.coverage);
|
|
8
|
+
if (Object.keys(coverage).length)
|
|
9
|
+
lines.push(`Matched ${short(coverage.matched)}; returned ${short(coverage.returned)}. ${coverage.scan_complete === true ? "Scan complete." : "Scan incomplete; totals may be unknown."}`);
|
|
10
|
+
for (const key of ["verdict", "reason", "settled", "method", "unit", "approximate"]) {
|
|
11
|
+
if (data[key] !== undefined)
|
|
12
|
+
lines.push(`${key}: ${short(data[key])}`);
|
|
13
|
+
}
|
|
14
|
+
const totals = record(data.totals ?? record(data.stats).totals);
|
|
15
|
+
if (totals.requests !== undefined)
|
|
16
|
+
lines.push(`${short(totals.errors)} errors / ${short(totals.requests)} requests; p95 ${short(totals.p95_ms)} ms.`);
|
|
17
|
+
const trace = record(data.trace);
|
|
18
|
+
if (trace.trace_id)
|
|
19
|
+
lines.push(`Trace ${short(trace.trace_id)}: ${short(trace.span_count)} spans${trace.has_error ? ", contains errors" : ""}.`);
|
|
20
|
+
const cause = record(record(data.observed).root_cause_span);
|
|
21
|
+
if (cause.name)
|
|
22
|
+
lines.push(`Recorded failure: ${short(cause.service)} / ${short(cause.name)} — ${short(record(cause.exception).message ?? cause.status)}`);
|
|
23
|
+
const collections = ["failures", "regressions", "groups", "steps", "traces", "sessions", "logs", "items", "attributes", "releases", "nodes", "runs", "phases", "saved_queries"];
|
|
24
|
+
let evidence = 0;
|
|
25
|
+
for (const field of collections) {
|
|
26
|
+
const rows = data[field];
|
|
27
|
+
if (!Array.isArray(rows))
|
|
28
|
+
continue;
|
|
29
|
+
lines.push(`${field.replaceAll("_", " ")}: ${rows.length} on this page.`);
|
|
30
|
+
for (const value of rows) {
|
|
31
|
+
if (evidence >= 3)
|
|
32
|
+
break;
|
|
33
|
+
const row = record(value);
|
|
34
|
+
const title = row.normalized_message ?? row.name ?? row.operation ?? row.key ?? row.root_span_name ?? row.body ?? row.service ?? row.session_id;
|
|
35
|
+
if (title === undefined)
|
|
36
|
+
continue;
|
|
37
|
+
const label = typeof title === "object" ? JSON.stringify(title) : title;
|
|
38
|
+
const stats = row.count ?? row.requests ?? row.status ?? row.change;
|
|
39
|
+
const id = row.failure_id ?? row.trace_id;
|
|
40
|
+
lines.push(`- ${short(label)}${stats === undefined ? "" : ` (${short(stats)})`}${id === undefined ? "" : ` · ${short(id)}`}`);
|
|
41
|
+
evidence++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (data.has_more === true && typeof data.next_cursor === "string")
|
|
45
|
+
lines.push("More results: repeat with next_cursor and the same filters.");
|
|
46
|
+
else if (data.has_more === true && typeof data.next_phase_cursor === "string")
|
|
47
|
+
lines.push("More phases: repeat with next_phase_cursor as phase_cursor and the same filters.");
|
|
48
|
+
else if (data.has_more === true)
|
|
49
|
+
lines.push("More evidence exists; narrow the filters to retrieve it.");
|
|
50
|
+
else if (coverage.truncated === true)
|
|
51
|
+
lines.push("Evidence is truncated; narrow the query for more detail.");
|
|
52
|
+
return lines.slice(0, 14).join("\n");
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=analysis-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analysis-summary.js","sourceRoot":"","sources":["../src/analysis-summary.ts"],"names":[],"mappings":"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"}
|