qyl-mcp-server 0.1.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/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/atomic-json-store.d.ts +37 -0
- package/dist/atomic-json-store.js +143 -0
- package/dist/atomic-json-store.js.map +1 -0
- package/dist/ci.d.ts +51 -0
- package/dist/ci.js +158 -0
- package/dist/ci.js.map +1 -0
- package/dist/collector.d.ts +43 -0
- package/dist/collector.js +163 -0
- package/dist/collector.js.map +1 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.js +39 -0
- package/dist/config.js.map +1 -0
- package/dist/contract-validation.d.ts +146 -0
- package/dist/contract-validation.js +350 -0
- package/dist/contract-validation.js.map +1 -0
- package/dist/data.d.ts +46 -0
- package/dist/data.js +138 -0
- package/dist/data.js.map +1 -0
- package/dist/demo.d.ts +23 -0
- package/dist/demo.js +836 -0
- package/dist/demo.js.map +1 -0
- package/dist/execution-evidence.d.ts +13 -0
- package/dist/execution-evidence.js +81 -0
- package/dist/execution-evidence.js.map +1 -0
- package/dist/execution-result.d.ts +5 -0
- package/dist/execution-result.js +17 -0
- package/dist/execution-result.js.map +1 -0
- package/dist/http-security.d.ts +36 -0
- package/dist/http-security.js +101 -0
- package/dist/http-security.js.map +1 -0
- package/dist/log-body.d.ts +3 -0
- package/dist/log-body.js +12 -0
- package/dist/log-body.js.map +1 -0
- package/dist/main.d.ts +51 -0
- package/dist/main.js +215 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp-app.html +218 -0
- package/dist/mcp-dashboard.html +223 -0
- package/dist/mcp-errors.d.ts +5 -0
- package/dist/mcp-errors.js +15 -0
- package/dist/mcp-errors.js.map +1 -0
- package/dist/mcp-semconv.d.ts +68 -0
- package/dist/mcp-semconv.js +208 -0
- package/dist/mcp-semconv.js.map +1 -0
- package/dist/native-execution.d.ts +132 -0
- package/dist/native-execution.js +508 -0
- package/dist/native-execution.js.map +1 -0
- package/dist/observability-suppression.d.ts +8 -0
- package/dist/observability-suppression.js +15 -0
- package/dist/observability-suppression.js.map +1 -0
- package/dist/secret-redactor.d.ts +30 -0
- package/dist/secret-redactor.js +255 -0
- package/dist/secret-redactor.js.map +1 -0
- package/dist/server.d.ts +25 -0
- package/dist/server.js +207 -0
- package/dist/server.js.map +1 -0
- package/dist/stats.d.ts +18 -0
- package/dist/stats.js +141 -0
- package/dist/stats.js.map +1 -0
- package/dist/summaries.d.ts +14 -0
- package/dist/summaries.js +128 -0
- package/dist/summaries.js.map +1 -0
- package/dist/telemetry-redaction.d.ts +6 -0
- package/dist/telemetry-redaction.js +28 -0
- package/dist/telemetry-redaction.js.map +1 -0
- package/dist/telemetry.d.ts +72 -0
- package/dist/telemetry.js +362 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tools.d.ts +17 -0
- package/dist/tools.js +111 -0
- package/dist/tools.js.map +1 -0
- package/dist/wire.d.ts +10 -0
- package/dist/wire.js +7 -0
- package/dist/wire.js.map +1 -0
- package/package.json +91 -0
package/dist/stats.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP dashboard aggregation — shared verbatim by the demo and live paths so
|
|
3
|
+
* the demo dataset exercises exactly the code that renders production stats.
|
|
4
|
+
*/
|
|
5
|
+
export function spanAttr(span, key) {
|
|
6
|
+
const attr = span.attributes?.find((a) => a.key === key);
|
|
7
|
+
return attr === undefined || attr.value === undefined
|
|
8
|
+
? undefined
|
|
9
|
+
: String(attr.value);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Pick a clean bucket size that tiles the window into 24–48 buckets.
|
|
13
|
+
* For every integer hours in 1–168 the resulting count lands in range.
|
|
14
|
+
*/
|
|
15
|
+
export function pickBucketMs(windowMs) {
|
|
16
|
+
const MINUTE = 60_000;
|
|
17
|
+
const candidates = [
|
|
18
|
+
MINUTE, 2 * MINUTE, 5 * MINUTE, 10 * MINUTE, 15 * MINUTE, 30 * MINUTE,
|
|
19
|
+
60 * MINUTE, 120 * MINUTE, 180 * MINUTE, 240 * MINUTE, 360 * MINUTE,
|
|
20
|
+
];
|
|
21
|
+
for (const candidate of candidates) {
|
|
22
|
+
if (Math.ceil(windowMs / candidate) <= 48)
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
return candidates[candidates.length - 1];
|
|
26
|
+
}
|
|
27
|
+
const round2 = (n) => Math.round(n * 100) / 100;
|
|
28
|
+
const round4 = (n) => Math.round(n * 10_000) / 10_000;
|
|
29
|
+
/** Nearest-rank 95th percentile of an ascending-sorted array. */
|
|
30
|
+
function nearestRankP95(sortedAsc) {
|
|
31
|
+
return sortedAsc[Math.max(0, Math.ceil(sortedAsc.length * 0.95) - 1)];
|
|
32
|
+
}
|
|
33
|
+
const MCP_METHOD_NAME_RE = /^(initialize|ping|tools\/(?:call|list)|resources\/(?:read|list|templates\/list|subscribe|unsubscribe)|prompts\/(?:get|list)|completion\/complete|logging\/setLevel|notifications\/[\w/]+)(?:\s+(.+))?$/;
|
|
34
|
+
/**
|
|
35
|
+
* Classify a span as MCP traffic. Attributes win (full-fidelity emitters); the
|
|
36
|
+
* span-name fallback ("tools/call get_trace") recovers method and tool when a
|
|
37
|
+
* collector redacts incubating MCP attributes.
|
|
38
|
+
*/
|
|
39
|
+
function classifyMcpSpan(span) {
|
|
40
|
+
const attrMethod = spanAttr(span, "mcp.method.name");
|
|
41
|
+
const nameMatch = MCP_METHOD_NAME_RE.exec(span.name ?? "");
|
|
42
|
+
const method = attrMethod ?? nameMatch?.[1];
|
|
43
|
+
if (method === undefined)
|
|
44
|
+
return null;
|
|
45
|
+
const target = nameMatch?.[2];
|
|
46
|
+
const tool = spanAttr(span, "gen_ai.tool.name") ??
|
|
47
|
+
(method === "tools/call" ? target : undefined);
|
|
48
|
+
return { method, tool };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Aggregate flattened spans into McpDashboardStats (minus mode/truncated,
|
|
52
|
+
* which depend on the data source). Classified MCP spans starting inside
|
|
53
|
+
* [windowStart, windowEnd] count; durations come from the span nano fields;
|
|
54
|
+
* error = status.code 2.
|
|
55
|
+
*/
|
|
56
|
+
export function aggregateMcpStats(spans, windowStart, windowEnd, bucketMs) {
|
|
57
|
+
const startNano = windowStart * 1e6;
|
|
58
|
+
const endNano = windowEnd * 1e6;
|
|
59
|
+
const mcpSpans = [];
|
|
60
|
+
for (const s of spans) {
|
|
61
|
+
if (s.start_time_unix_nano < startNano || s.start_time_unix_nano > endNano)
|
|
62
|
+
continue;
|
|
63
|
+
const cls = classifyMcpSpan(s);
|
|
64
|
+
if (cls)
|
|
65
|
+
mcpSpans.push({ span: s, cls });
|
|
66
|
+
}
|
|
67
|
+
const bucketCount = Math.max(1, Math.ceil((windowEnd - windowStart) / bucketMs));
|
|
68
|
+
const buckets = Array.from({ length: bucketCount }, (_, i) => ({
|
|
69
|
+
start: new Date(windowStart + i * bucketMs).toISOString(),
|
|
70
|
+
requests: 0,
|
|
71
|
+
errors: 0,
|
|
72
|
+
}));
|
|
73
|
+
const byServer = new Map();
|
|
74
|
+
const byTransport = new Map();
|
|
75
|
+
const byMethod = new Map();
|
|
76
|
+
const toolAcc = new Map();
|
|
77
|
+
const bump = (map, name) => map.set(name, (map.get(name) ?? 0) + 1);
|
|
78
|
+
const accumulate = (map, name, error, ms) => {
|
|
79
|
+
let acc = map.get(name);
|
|
80
|
+
if (!acc)
|
|
81
|
+
map.set(name, (acc = { requests: 0, errors: 0, durations: [] }));
|
|
82
|
+
acc.requests++;
|
|
83
|
+
if (error)
|
|
84
|
+
acc.errors++;
|
|
85
|
+
acc.durations.push(ms);
|
|
86
|
+
};
|
|
87
|
+
let totalErrors = 0;
|
|
88
|
+
for (const { span, cls } of mcpSpans) {
|
|
89
|
+
const error = span.status.code === 2;
|
|
90
|
+
if (error)
|
|
91
|
+
totalErrors++;
|
|
92
|
+
const ms = (span.end_time_unix_nano - span.start_time_unix_nano) / 1e6;
|
|
93
|
+
const startMs = span.start_time_unix_nano / 1e6;
|
|
94
|
+
const index = Math.min(bucketCount - 1, Math.max(0, Math.floor((startMs - windowStart) / bucketMs)));
|
|
95
|
+
buckets[index].requests++;
|
|
96
|
+
if (error)
|
|
97
|
+
buckets[index].errors++;
|
|
98
|
+
bump(byServer, spanAttr(span, "service.peer.name") ?? "unknown");
|
|
99
|
+
bump(byTransport, spanAttr(span, "network.transport") ?? "unknown");
|
|
100
|
+
bump(byMethod, cls.method);
|
|
101
|
+
if (cls.tool !== undefined)
|
|
102
|
+
accumulate(toolAcc, cls.tool, error, ms);
|
|
103
|
+
}
|
|
104
|
+
const toNameRequests = (map) => [...map]
|
|
105
|
+
.map(([name, requests]) => ({ name, requests }))
|
|
106
|
+
.sort((a, b) => b.requests - a.requests);
|
|
107
|
+
const toRows = (map) => [...map]
|
|
108
|
+
.map(([name, acc]) => {
|
|
109
|
+
const sorted = [...acc.durations].sort((a, b) => a - b);
|
|
110
|
+
const sum = sorted.reduce((total, d) => total + d, 0);
|
|
111
|
+
return {
|
|
112
|
+
name,
|
|
113
|
+
requests: acc.requests,
|
|
114
|
+
errors: acc.errors,
|
|
115
|
+
error_rate: round4(acc.errors / acc.requests),
|
|
116
|
+
avg_ms: round2(sum / sorted.length),
|
|
117
|
+
p95_ms: round2(nearestRankP95(sorted)),
|
|
118
|
+
};
|
|
119
|
+
})
|
|
120
|
+
.sort((a, b) => b.requests - a.requests);
|
|
121
|
+
const requests = mcpSpans.length;
|
|
122
|
+
return {
|
|
123
|
+
window: {
|
|
124
|
+
start: new Date(windowStart).toISOString(),
|
|
125
|
+
end: new Date(windowEnd).toISOString(),
|
|
126
|
+
bucket_ms: bucketMs,
|
|
127
|
+
},
|
|
128
|
+
buckets,
|
|
129
|
+
totals: {
|
|
130
|
+
requests,
|
|
131
|
+
errors: totalErrors,
|
|
132
|
+
error_rate: requests > 0 ? round4(totalErrors / requests) : 0,
|
|
133
|
+
},
|
|
134
|
+
by_server: toNameRequests(byServer),
|
|
135
|
+
by_transport: toNameRequests(byTransport),
|
|
136
|
+
by_method: toNameRequests(byMethod),
|
|
137
|
+
tools: toRows(toolAcc),
|
|
138
|
+
span_count_analyzed: requests,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text summaries (compact and model-friendly) for tool results.
|
|
3
|
+
*/
|
|
4
|
+
import type { McpDashboardStats, Mode, QylLogRecord, QylSession, QylTrace } from "./wire.js";
|
|
5
|
+
/** Humanize a nanosecond duration: "1.24 s" / "87 ms" / "640 µs". */
|
|
6
|
+
export declare function humanizeNs(ns: number): string;
|
|
7
|
+
export declare function shortId(id: string): string;
|
|
8
|
+
/** Root span name, or the earliest span when no root is identified. */
|
|
9
|
+
export declare function rootSpanName(trace: QylTrace): string;
|
|
10
|
+
export declare function summarizeTraceTable(traces: QylTrace[], mode: Mode): string;
|
|
11
|
+
export declare function summarizeTrace(trace: QylTrace, mode: Mode): string;
|
|
12
|
+
export declare function summarizeSessions(sessions: QylSession[], mode: Mode): string;
|
|
13
|
+
export declare function summarizeLogs(logs: QylLogRecord[], mode: Mode): string;
|
|
14
|
+
export declare function summarizeMcpStats(stats: McpDashboardStats, hours: number): string;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text summaries (compact and model-friendly) for tool results.
|
|
3
|
+
*/
|
|
4
|
+
import { logBodyText } from "./log-body.js";
|
|
5
|
+
/** Humanize a nanosecond duration: "1.24 s" / "87 ms" / "640 µs". */
|
|
6
|
+
export function humanizeNs(ns) {
|
|
7
|
+
if (ns >= 1e9)
|
|
8
|
+
return `${(ns / 1e9).toFixed(2)} s`;
|
|
9
|
+
if (ns >= 1e6)
|
|
10
|
+
return `${Math.round(ns / 1e6)} ms`;
|
|
11
|
+
return `${Math.round(ns / 1e3)} µs`;
|
|
12
|
+
}
|
|
13
|
+
export function shortId(id) {
|
|
14
|
+
return id.length > 8 ? `${id.slice(0, 8)}…` : id;
|
|
15
|
+
}
|
|
16
|
+
/** Root span name, or the earliest span when no root is identified. */
|
|
17
|
+
export function rootSpanName(trace) {
|
|
18
|
+
if (trace.root_span?.name)
|
|
19
|
+
return trace.root_span.name;
|
|
20
|
+
const earliest = [...(trace.spans ?? [])].sort((a, b) => a.start_time_unix_nano - b.start_time_unix_nano)[0];
|
|
21
|
+
return earliest?.name ?? "unknown";
|
|
22
|
+
}
|
|
23
|
+
function serviceOf(span) {
|
|
24
|
+
return String(span.resource?.["service.name"] ?? "unknown");
|
|
25
|
+
}
|
|
26
|
+
function modeNote(mode) {
|
|
27
|
+
return mode === "demo" ? " [demo data]" : "";
|
|
28
|
+
}
|
|
29
|
+
export function summarizeTraceTable(traces, mode) {
|
|
30
|
+
const lines = [
|
|
31
|
+
`Traces (${traces.length})${modeNote(mode)}`,
|
|
32
|
+
"",
|
|
33
|
+
"| Trace | Root span | Spans | Duration | Status | Services |",
|
|
34
|
+
"|-------|-----------|-------|----------|--------|----------|",
|
|
35
|
+
];
|
|
36
|
+
for (const trace of traces) {
|
|
37
|
+
const services = trace.services.slice(0, 3).join(", ") +
|
|
38
|
+
(trace.services.length > 3 ? ` +${trace.services.length - 3}` : "");
|
|
39
|
+
lines.push(`| ${shortId(trace.trace_id)} | ${rootSpanName(trace)} | ${trace.span_count} | ` +
|
|
40
|
+
`${humanizeNs(trace.duration_ns)} | ${trace.has_error ? "ERROR" : "OK"} | ${services} |`);
|
|
41
|
+
}
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|
|
44
|
+
export function summarizeTrace(trace, mode) {
|
|
45
|
+
const spansByService = new Map();
|
|
46
|
+
for (const span of trace.spans) {
|
|
47
|
+
const service = serviceOf(span);
|
|
48
|
+
spansByService.set(service, (spansByService.get(service) ?? 0) + 1);
|
|
49
|
+
}
|
|
50
|
+
const perService = [...spansByService]
|
|
51
|
+
.map(([service, count]) => `${service} ×${count}`)
|
|
52
|
+
.join(", ");
|
|
53
|
+
const lines = [
|
|
54
|
+
`Trace ${trace.trace_id}${modeNote(mode)}`,
|
|
55
|
+
`Root: ${rootSpanName(trace)} — ${humanizeNs(trace.duration_ns)}, ` +
|
|
56
|
+
`${trace.span_count} spans, started ${trace.start_time}`,
|
|
57
|
+
`Spans by service: ${perService}`,
|
|
58
|
+
];
|
|
59
|
+
const errorSpans = trace.spans.filter((s) => s.status.code === 2);
|
|
60
|
+
if (errorSpans.length > 0) {
|
|
61
|
+
lines.push(`Error spans (${errorSpans.length}):`);
|
|
62
|
+
for (const span of errorSpans) {
|
|
63
|
+
lines.push(`- ${span.name} (${serviceOf(span)})` +
|
|
64
|
+
(span.status.message ? ` — ${span.status.message}` : ""));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return lines.join("\n");
|
|
68
|
+
}
|
|
69
|
+
export function summarizeSessions(sessions, mode) {
|
|
70
|
+
const lines = [
|
|
71
|
+
`Sessions (${sessions.length})${modeNote(mode)}`,
|
|
72
|
+
"",
|
|
73
|
+
"| Session | State | Traces | Spans | Errors | Duration | GenAI |",
|
|
74
|
+
"|---------|-------|--------|-------|--------|----------|-------|",
|
|
75
|
+
];
|
|
76
|
+
for (const session of sessions) {
|
|
77
|
+
const duration = session.duration_ms !== undefined
|
|
78
|
+
? humanizeNs(session.duration_ms * 1e6)
|
|
79
|
+
: "—";
|
|
80
|
+
const genai = session.genai_usage
|
|
81
|
+
? `${session.genai_usage.request_count} req, ` +
|
|
82
|
+
`${session.genai_usage.total_input_tokens}/${session.genai_usage.total_output_tokens} tok`
|
|
83
|
+
: "—";
|
|
84
|
+
lines.push(`| ${session["session.id"]} | ${session.state} | ${session.trace_count} | ` +
|
|
85
|
+
`${session.span_count} | ${session.error_count} | ${duration} | ${genai} |`);
|
|
86
|
+
}
|
|
87
|
+
return lines.join("\n");
|
|
88
|
+
}
|
|
89
|
+
export function summarizeLogs(logs, mode) {
|
|
90
|
+
if (logs.length === 0)
|
|
91
|
+
return `No logs matched${modeNote(mode)}.`;
|
|
92
|
+
const lines = logs.map((record) => {
|
|
93
|
+
const time = new Date(record.time_unix_nano / 1e6)
|
|
94
|
+
.toISOString()
|
|
95
|
+
.slice(11, 23);
|
|
96
|
+
const severity = record.severity_text ?? String(record.severity_number);
|
|
97
|
+
const renderedBody = logBodyText(record.body).replace(/\s+/g, " ");
|
|
98
|
+
const body = renderedBody.length > 140
|
|
99
|
+
? `${renderedBody.slice(0, 140)}…`
|
|
100
|
+
: renderedBody;
|
|
101
|
+
const correlation = record.trace_id
|
|
102
|
+
? ` (trace ${shortId(record.trace_id)})`
|
|
103
|
+
: "";
|
|
104
|
+
return `- ${time} ${severity} [${String(record.resource["service.name"] ?? "unknown")}] ${body}${correlation}`;
|
|
105
|
+
});
|
|
106
|
+
return `Logs (${logs.length})${modeNote(mode)}\n${lines.join("\n")}`;
|
|
107
|
+
}
|
|
108
|
+
export function summarizeMcpStats(stats, hours) {
|
|
109
|
+
const pct = (rate) => `${(rate * 100).toFixed(1)}%`;
|
|
110
|
+
const nameList = (rows) => rows.map((r) => `${r.name} ×${r.requests}`).join(", ") || "—";
|
|
111
|
+
const lines = [
|
|
112
|
+
`MCP traffic — last ${hours}h${modeNote(stats.mode)}` +
|
|
113
|
+
(stats.truncated ? " (truncated at the 1000-trace fetch cap)" : ""),
|
|
114
|
+
`Requests: ${stats.totals.requests}, errors: ${stats.totals.errors} ` +
|
|
115
|
+
`(${pct(stats.totals.error_rate)})`,
|
|
116
|
+
`Servers: ${nameList(stats.by_server)}`,
|
|
117
|
+
`Transports: ${nameList(stats.by_transport)}`,
|
|
118
|
+
`Methods: ${nameList(stats.by_method)}`,
|
|
119
|
+
];
|
|
120
|
+
if (stats.tools.length > 0) {
|
|
121
|
+
lines.push("", "| Tool | Requests | Error rate | p95 |", "|------|----------|------------|-----|");
|
|
122
|
+
for (const tool of stats.tools.slice(0, 5)) {
|
|
123
|
+
lines.push(`| ${tool.name} | ${tool.requests} | ${pct(tool.error_rate)} | ${tool.p95_ms} ms |`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return lines.join("\n");
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=summaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summaries.js","sourceRoot":"","sources":["../src/summaries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
/** Redact already-validated telemetry while preserving its published shape. */
|
|
3
|
+
export declare function redactTelemetry<T>(value: T): T;
|
|
4
|
+
export declare function redactTelemetryText(value: string): string;
|
|
5
|
+
/** Final MCP result guard for both model text and structured telemetry. */
|
|
6
|
+
export declare function telemetryToolResult<T extends object>(text: string, output: T): CallToolResult;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isCredentialKey, SecretRedactor } from "./secret-redactor.js";
|
|
2
|
+
// The standalone server and the runner share this implementation through the
|
|
3
|
+
// server package export. Keep one process-local instance so configured secret
|
|
4
|
+
// values remain available for every result path without ever being serialized.
|
|
5
|
+
const redactor = new SecretRedactor({ environment: process.env });
|
|
6
|
+
function registerCurrentEnvironmentSecrets() {
|
|
7
|
+
redactor.registerSecretValues(Object.entries(process.env)
|
|
8
|
+
.filter(([name, value]) => value !== undefined && isCredentialKey(name))
|
|
9
|
+
.map(([, value]) => value));
|
|
10
|
+
}
|
|
11
|
+
/** Redact already-validated telemetry while preserving its published shape. */
|
|
12
|
+
export function redactTelemetry(value) {
|
|
13
|
+
registerCurrentEnvironmentSecrets();
|
|
14
|
+
return redactor.redact(value);
|
|
15
|
+
}
|
|
16
|
+
export function redactTelemetryText(value) {
|
|
17
|
+
registerCurrentEnvironmentSecrets();
|
|
18
|
+
return redactor.redactText(value);
|
|
19
|
+
}
|
|
20
|
+
/** Final MCP result guard for both model text and structured telemetry. */
|
|
21
|
+
export function telemetryToolResult(text, output) {
|
|
22
|
+
const safeOutput = redactTelemetry(output);
|
|
23
|
+
return {
|
|
24
|
+
content: [{ type: "text", text: redactTelemetryText(text) }],
|
|
25
|
+
structuredContent: safeOutput,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=telemetry-redaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-redaction.js","sourceRoot":"","sources":["../src/telemetry-redaction.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEvE,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAElE,SAAS,iCAAiC;IACxC,QAAQ,CAAC,oBAAoB,CAC3B,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;SACvE,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAe,CAAC,CACvC,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAI,KAAQ;IACzC,iCAAiC,EAAE,CAAC;IACpC,OAAO,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAM,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,iCAAiC,EAAE,CAAC;IACpC,OAAO,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,MAAS;IAET,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5D,iBAAiB,EAAE,UAAgD;KACpE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** MCP self-telemetry exported through the official OpenTelemetry SDK. */
|
|
2
|
+
import { type Tracer } from "@opentelemetry/api";
|
|
3
|
+
import { type McpPropagationCarrier, type McpOperationInput, type McpSessionInput } from "./mcp-semconv.js";
|
|
4
|
+
import { SecretRedactor } from "./secret-redactor.js";
|
|
5
|
+
export { WorkbenchTelemetryAttributes, describeMcpOperationMetric, describeMcpOperationSpan, describeMcpSessionMetric, type McpOperationInput, type McpPropagationCarrier, type McpSessionInput, } from "./mcp-semconv.js";
|
|
6
|
+
export declare const MCP_DURATION_EXPLICIT_BUCKET_BOUNDARIES: readonly [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300];
|
|
7
|
+
export interface McpSpanCorrelation {
|
|
8
|
+
traceId: string;
|
|
9
|
+
spanId: string;
|
|
10
|
+
}
|
|
11
|
+
export type McpOperationStartInput = Omit<McpOperationInput, "endTimeMs" | "errorType" | "rpcResponseStatusCode" | "jsonRpcRequestId">;
|
|
12
|
+
export interface McpOperationCompletion {
|
|
13
|
+
endTimeMs: number;
|
|
14
|
+
errorType?: string;
|
|
15
|
+
rpcResponseStatusCode?: string;
|
|
16
|
+
jsonRpcRequestId?: string | number;
|
|
17
|
+
protocolVersion?: string;
|
|
18
|
+
mcpSessionId?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ActiveMcpOperation {
|
|
21
|
+
readonly correlation?: McpSpanCorrelation;
|
|
22
|
+
readonly propagation?: McpPropagationCarrier;
|
|
23
|
+
/** Compatibility view of the standard W3C field in `propagation`. */
|
|
24
|
+
readonly traceparent?: string;
|
|
25
|
+
run<T>(operation: () => T): T;
|
|
26
|
+
end(completion: McpOperationCompletion): McpSpanCorrelation | undefined;
|
|
27
|
+
}
|
|
28
|
+
export interface McpTelemetryOptions {
|
|
29
|
+
/** Test/embedding seam; production creates its isolated OTLP tracer. */
|
|
30
|
+
tracer?: Tracer;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Carries one explicitly-created MCP operation through SDK dispatch without
|
|
34
|
+
* installing a global OpenTelemetry provider or context manager. A null store
|
|
35
|
+
* deliberately clears any outer operation so unrelated requests cannot inherit
|
|
36
|
+
* stale propagation state.
|
|
37
|
+
*/
|
|
38
|
+
export declare function runWithMcpPropagation<T>(carrier: McpPropagationCarrier | undefined, operation: () => T): T;
|
|
39
|
+
/** Compatibility wrapper for callers that only have a W3C traceparent. */
|
|
40
|
+
export declare function runWithMcpTraceparent<T>(traceparent: string | undefined, operation: () => T): T;
|
|
41
|
+
/** Current execution-local propagation carrier, if an MCP operation exists. */
|
|
42
|
+
export declare function currentMcpPropagation(): McpPropagationCarrier | undefined;
|
|
43
|
+
/** Current execution-local W3C trace parent, if a client operation span exists. */
|
|
44
|
+
export declare function currentMcpTraceparent(): string | undefined;
|
|
45
|
+
export declare function signalEndpoint(env: Readonly<Record<string, string | undefined>>, signal: "traces" | "metrics"): string;
|
|
46
|
+
/**
|
|
47
|
+
* Records completed MCP operations and sessions without installing global SDK
|
|
48
|
+
* providers. Signal-specific descriptors prevent span-only identifiers from
|
|
49
|
+
* appearing on duration histograms.
|
|
50
|
+
*/
|
|
51
|
+
export declare class McpTelemetry {
|
|
52
|
+
private readonly traceProvider?;
|
|
53
|
+
private readonly metricProvider?;
|
|
54
|
+
private tracer?;
|
|
55
|
+
private readonly histograms;
|
|
56
|
+
private readonly redactor;
|
|
57
|
+
get operationTracingEnabled(): boolean;
|
|
58
|
+
constructor(env?: Readonly<Record<string, string | undefined>>, redactor?: SecretRedactor, options?: McpTelemetryOptions);
|
|
59
|
+
/**
|
|
60
|
+
* Start an MCP operation before the SDK call so its trace context can be
|
|
61
|
+
* propagated. Completion-only attributes are applied immediately before
|
|
62
|
+
* ending the span, and the metric is recorded exactly once at completion.
|
|
63
|
+
*/
|
|
64
|
+
startOperation(input: McpOperationStartInput): ActiveMcpOperation;
|
|
65
|
+
/** Record one already-completed client or server operation. Never throws. */
|
|
66
|
+
recordOperation(input: McpOperationInput): McpSpanCorrelation | undefined;
|
|
67
|
+
/** Record one completed client or server session histogram. Never throws. */
|
|
68
|
+
recordSession(input: McpSessionInput): void;
|
|
69
|
+
/** Flush and stop both SDK providers during runner shutdown. */
|
|
70
|
+
close(): Promise<void>;
|
|
71
|
+
private recordOperationMetric;
|
|
72
|
+
}
|