@mcp-audit-gateway/core 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/.github/workflows/npm-publish.yml +21 -0
- package/CONTRIBUTING.md +41 -0
- package/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/attestation/audit-log.d.ts +25 -0
- package/dist/attestation/audit-log.d.ts.map +1 -0
- package/dist/attestation/audit-log.js +95 -0
- package/dist/attestation/audit-log.js.map +1 -0
- package/dist/attestation/bugfix.test.d.ts +2 -0
- package/dist/attestation/bugfix.test.d.ts.map +1 -0
- package/dist/attestation/bugfix.test.js +103 -0
- package/dist/attestation/bugfix.test.js.map +1 -0
- package/dist/attestation/chain.test.d.ts +2 -0
- package/dist/attestation/chain.test.d.ts.map +1 -0
- package/dist/attestation/chain.test.js +153 -0
- package/dist/attestation/chain.test.js.map +1 -0
- package/dist/attestation/keygen.d.ts +5 -0
- package/dist/attestation/keygen.d.ts.map +1 -0
- package/dist/attestation/keygen.js +12 -0
- package/dist/attestation/keygen.js.map +1 -0
- package/dist/attestation/signer.d.ts +25 -0
- package/dist/attestation/signer.d.ts.map +1 -0
- package/dist/attestation/signer.js +93 -0
- package/dist/attestation/signer.js.map +1 -0
- package/dist/attestation/signer.test.d.ts +2 -0
- package/dist/attestation/signer.test.d.ts.map +1 -0
- package/dist/attestation/signer.test.js +62 -0
- package/dist/attestation/signer.test.js.map +1 -0
- package/dist/attestation/verify.d.ts +26 -0
- package/dist/attestation/verify.d.ts.map +1 -0
- package/dist/attestation/verify.js +104 -0
- package/dist/attestation/verify.js.map +1 -0
- package/dist/attestation/verify.test.d.ts +2 -0
- package/dist/attestation/verify.test.d.ts.map +1 -0
- package/dist/attestation/verify.test.js +79 -0
- package/dist/attestation/verify.test.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +364 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.test.d.ts +2 -0
- package/dist/integration.test.d.ts.map +1 -0
- package/dist/integration.test.js +88 -0
- package/dist/integration.test.js.map +1 -0
- package/dist/policy/engine.d.ts +24 -0
- package/dist/policy/engine.d.ts.map +1 -0
- package/dist/policy/engine.js +130 -0
- package/dist/policy/engine.js.map +1 -0
- package/dist/policy/engine.test.d.ts +2 -0
- package/dist/policy/engine.test.d.ts.map +1 -0
- package/dist/policy/engine.test.js +80 -0
- package/dist/policy/engine.test.js.map +1 -0
- package/dist/proxy/gateway.d.ts +54 -0
- package/dist/proxy/gateway.d.ts.map +1 -0
- package/dist/proxy/gateway.js +245 -0
- package/dist/proxy/gateway.js.map +1 -0
- package/dist/proxy/gateway.test.d.ts +2 -0
- package/dist/proxy/gateway.test.d.ts.map +1 -0
- package/dist/proxy/gateway.test.js +93 -0
- package/dist/proxy/gateway.test.js.map +1 -0
- package/dist/proxy/mcp-server-adapter.d.ts +21 -0
- package/dist/proxy/mcp-server-adapter.d.ts.map +1 -0
- package/dist/proxy/mcp-server-adapter.js +98 -0
- package/dist/proxy/mcp-server-adapter.js.map +1 -0
- package/dist/proxy/mcp-server-adapter.test.d.ts +2 -0
- package/dist/proxy/mcp-server-adapter.test.d.ts.map +1 -0
- package/dist/proxy/mcp-server-adapter.test.js +160 -0
- package/dist/proxy/mcp-server-adapter.test.js.map +1 -0
- package/dist/proxy/upstream-manager.d.ts +49 -0
- package/dist/proxy/upstream-manager.d.ts.map +1 -0
- package/dist/proxy/upstream-manager.js +246 -0
- package/dist/proxy/upstream-manager.js.map +1 -0
- package/dist/proxy/upstream-manager.test.d.ts +2 -0
- package/dist/proxy/upstream-manager.test.d.ts.map +1 -0
- package/dist/proxy/upstream-manager.test.js +413 -0
- package/dist/proxy/upstream-manager.test.js.map +1 -0
- package/dist/telemetry/logger.d.ts +26 -0
- package/dist/telemetry/logger.d.ts.map +1 -0
- package/dist/telemetry/logger.js +48 -0
- package/dist/telemetry/logger.js.map +1 -0
- package/dist/telemetry/logger.test.d.ts +2 -0
- package/dist/telemetry/logger.test.d.ts.map +1 -0
- package/dist/telemetry/logger.test.js +124 -0
- package/dist/telemetry/logger.test.js.map +1 -0
- package/dist/telemetry/metrics.d.ts +41 -0
- package/dist/telemetry/metrics.d.ts.map +1 -0
- package/dist/telemetry/metrics.js +64 -0
- package/dist/telemetry/metrics.js.map +1 -0
- package/dist/telemetry/metrics.test.d.ts +2 -0
- package/dist/telemetry/metrics.test.d.ts.map +1 -0
- package/dist/telemetry/metrics.test.js +93 -0
- package/dist/telemetry/metrics.test.js.map +1 -0
- package/dist/telemetry/tracer.d.ts +16 -0
- package/dist/telemetry/tracer.d.ts.map +1 -0
- package/dist/telemetry/tracer.js +71 -0
- package/dist/telemetry/tracer.js.map +1 -0
- package/dist/types.d.ts +477 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +68 -0
- package/dist/types.js.map +1 -0
- package/dist/wrap/proxy.d.ts +2 -0
- package/dist/wrap/proxy.d.ts.map +1 -0
- package/dist/wrap/proxy.js +152 -0
- package/dist/wrap/proxy.js.map +1 -0
- package/dist/wrap/proxy.test.d.ts +2 -0
- package/dist/wrap/proxy.test.d.ts.map +1 -0
- package/dist/wrap/proxy.test.js +155 -0
- package/dist/wrap/proxy.test.js.map +1 -0
- package/examples/README.md +33 -0
- package/examples/claude-desktop.json +50 -0
- package/examples/multi-agent-production.json +72 -0
- package/gateway.config.example.json +61 -0
- package/package.json +49 -0
- package/src/attestation/audit-log.ts +126 -0
- package/src/attestation/bugfix.test.ts +113 -0
- package/src/attestation/chain.test.ts +188 -0
- package/src/attestation/keygen.ts +18 -0
- package/src/attestation/signer.test.ts +75 -0
- package/src/attestation/signer.ts +105 -0
- package/src/attestation/verify.test.ts +86 -0
- package/src/attestation/verify.ts +131 -0
- package/src/cli.ts +407 -0
- package/src/index.ts +21 -0
- package/src/integration.test.ts +108 -0
- package/src/policy/engine.test.ts +95 -0
- package/src/policy/engine.ts +162 -0
- package/src/proxy/gateway.test.ts +108 -0
- package/src/proxy/gateway.ts +328 -0
- package/src/proxy/mcp-server-adapter.test.ts +197 -0
- package/src/proxy/mcp-server-adapter.ts +140 -0
- package/src/proxy/upstream-manager.test.ts +534 -0
- package/src/proxy/upstream-manager.ts +326 -0
- package/src/telemetry/logger.test.ts +139 -0
- package/src/telemetry/logger.ts +72 -0
- package/src/telemetry/metrics.test.ts +125 -0
- package/src/telemetry/metrics.ts +83 -0
- package/src/telemetry/tracer.ts +90 -0
- package/src/types.ts +113 -0
- package/src/wrap/proxy.test.ts +175 -0
- package/src/wrap/proxy.ts +192 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
2
|
+
import { Logger } from "./logger.js";
|
|
3
|
+
describe("Logger", () => {
|
|
4
|
+
let lines;
|
|
5
|
+
let logger;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
lines = [];
|
|
8
|
+
logger = new Logger({
|
|
9
|
+
component: "test",
|
|
10
|
+
level: "debug",
|
|
11
|
+
output: (line) => lines.push(line),
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
describe("structured output", () => {
|
|
15
|
+
it("outputs valid JSON lines", () => {
|
|
16
|
+
logger.info("hello world");
|
|
17
|
+
expect(lines).toHaveLength(1);
|
|
18
|
+
const parsed = JSON.parse(lines[0]);
|
|
19
|
+
expect(parsed).toHaveProperty("timestamp");
|
|
20
|
+
expect(parsed).toHaveProperty("level", "info");
|
|
21
|
+
expect(parsed).toHaveProperty("component", "test");
|
|
22
|
+
expect(parsed).toHaveProperty("message", "hello world");
|
|
23
|
+
});
|
|
24
|
+
it("includes ISO 8601 timestamp", () => {
|
|
25
|
+
logger.info("msg");
|
|
26
|
+
const parsed = JSON.parse(lines[0]);
|
|
27
|
+
expect(() => new Date(parsed.timestamp)).not.toThrow();
|
|
28
|
+
expect(parsed.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/);
|
|
29
|
+
});
|
|
30
|
+
it("includes arbitrary context fields", () => {
|
|
31
|
+
logger.info("tool call", { tool: "my_tool", durationMs: 42, upstream: "server-a" });
|
|
32
|
+
const parsed = JSON.parse(lines[0]);
|
|
33
|
+
expect(parsed.tool).toBe("my_tool");
|
|
34
|
+
expect(parsed.durationMs).toBe(42);
|
|
35
|
+
expect(parsed.upstream).toBe("server-a");
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe("log levels", () => {
|
|
39
|
+
it("outputs debug messages when level is debug", () => {
|
|
40
|
+
logger.debug("trace msg");
|
|
41
|
+
expect(lines).toHaveLength(1);
|
|
42
|
+
expect(JSON.parse(lines[0]).level).toBe("debug");
|
|
43
|
+
});
|
|
44
|
+
it("outputs info messages", () => {
|
|
45
|
+
logger.info("info msg");
|
|
46
|
+
expect(lines).toHaveLength(1);
|
|
47
|
+
expect(JSON.parse(lines[0]).level).toBe("info");
|
|
48
|
+
});
|
|
49
|
+
it("outputs warn messages", () => {
|
|
50
|
+
logger.warn("warning");
|
|
51
|
+
expect(lines).toHaveLength(1);
|
|
52
|
+
expect(JSON.parse(lines[0]).level).toBe("warn");
|
|
53
|
+
});
|
|
54
|
+
it("outputs error messages", () => {
|
|
55
|
+
logger.error("failure");
|
|
56
|
+
expect(lines).toHaveLength(1);
|
|
57
|
+
expect(JSON.parse(lines[0]).level).toBe("error");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("level filtering", () => {
|
|
61
|
+
it("suppresses debug when level is info", () => {
|
|
62
|
+
const infoLogger = new Logger({
|
|
63
|
+
component: "test",
|
|
64
|
+
level: "info",
|
|
65
|
+
output: (line) => lines.push(line),
|
|
66
|
+
});
|
|
67
|
+
infoLogger.debug("should not appear");
|
|
68
|
+
infoLogger.info("should appear");
|
|
69
|
+
expect(lines).toHaveLength(1);
|
|
70
|
+
expect(JSON.parse(lines[0]).message).toBe("should appear");
|
|
71
|
+
});
|
|
72
|
+
it("suppresses info and debug when level is warn", () => {
|
|
73
|
+
const warnLogger = new Logger({
|
|
74
|
+
component: "test",
|
|
75
|
+
level: "warn",
|
|
76
|
+
output: (line) => lines.push(line),
|
|
77
|
+
});
|
|
78
|
+
warnLogger.debug("no");
|
|
79
|
+
warnLogger.info("no");
|
|
80
|
+
warnLogger.warn("yes");
|
|
81
|
+
warnLogger.error("yes");
|
|
82
|
+
expect(lines).toHaveLength(2);
|
|
83
|
+
});
|
|
84
|
+
it("only outputs error when level is error", () => {
|
|
85
|
+
const errorLogger = new Logger({
|
|
86
|
+
component: "test",
|
|
87
|
+
level: "error",
|
|
88
|
+
output: (line) => lines.push(line),
|
|
89
|
+
});
|
|
90
|
+
errorLogger.debug("no");
|
|
91
|
+
errorLogger.info("no");
|
|
92
|
+
errorLogger.warn("no");
|
|
93
|
+
errorLogger.error("yes");
|
|
94
|
+
expect(lines).toHaveLength(1);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
describe("child logger", () => {
|
|
98
|
+
it("creates child with different component", () => {
|
|
99
|
+
const child = logger.child({ component: "sub-system" });
|
|
100
|
+
child.info("child message");
|
|
101
|
+
const parsed = JSON.parse(lines[0]);
|
|
102
|
+
expect(parsed.component).toBe("sub-system");
|
|
103
|
+
});
|
|
104
|
+
it("child inherits parent output", () => {
|
|
105
|
+
const child = logger.child({ component: "child" });
|
|
106
|
+
child.warn("from child");
|
|
107
|
+
expect(lines).toHaveLength(1);
|
|
108
|
+
expect(JSON.parse(lines[0]).component).toBe("child");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
describe("default output", () => {
|
|
112
|
+
it("writes to stderr by default", () => {
|
|
113
|
+
const stderrWrite = vi.spyOn(process.stderr, "write").mockImplementation(() => true);
|
|
114
|
+
const defaultLogger = new Logger({ component: "default-test", level: "info" });
|
|
115
|
+
defaultLogger.info("stderr test");
|
|
116
|
+
expect(stderrWrite).toHaveBeenCalled();
|
|
117
|
+
const written = stderrWrite.mock.calls[0][0];
|
|
118
|
+
expect(written).toContain("stderr test");
|
|
119
|
+
expect(written.endsWith("\n")).toBe(true);
|
|
120
|
+
stderrWrite.mockRestore();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=logger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.test.js","sourceRoot":"","sources":["../../src/telemetry/logger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Counter, Histogram, Gauge } from "@opentelemetry/api";
|
|
2
|
+
import type { TelemetryConfig } from "../types.js";
|
|
3
|
+
export interface MetricLabels {
|
|
4
|
+
toolCall: {
|
|
5
|
+
namespace: string;
|
|
6
|
+
tool: string;
|
|
7
|
+
principal: string;
|
|
8
|
+
success: string;
|
|
9
|
+
};
|
|
10
|
+
duration: {
|
|
11
|
+
namespace: string;
|
|
12
|
+
upstream: string;
|
|
13
|
+
};
|
|
14
|
+
upstreamStatus: {
|
|
15
|
+
upstream: string;
|
|
16
|
+
status: string;
|
|
17
|
+
};
|
|
18
|
+
policyDenial: {
|
|
19
|
+
principal: string;
|
|
20
|
+
tool: string;
|
|
21
|
+
reason: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export declare class GatewayMetrics {
|
|
25
|
+
private meter;
|
|
26
|
+
private _toolCallsTotal;
|
|
27
|
+
private _toolCallDurationMs;
|
|
28
|
+
private _upstreamStatus;
|
|
29
|
+
private _policyDenialsTotal;
|
|
30
|
+
private _enabled;
|
|
31
|
+
constructor(config: TelemetryConfig);
|
|
32
|
+
recordToolCall(labels: MetricLabels["toolCall"]): void;
|
|
33
|
+
recordDuration(durationMs: number, labels: MetricLabels["duration"]): void;
|
|
34
|
+
setUpstreamStatus(upstream: string, status: string, value: number): void;
|
|
35
|
+
recordPolicyDenial(labels: MetricLabels["policyDenial"]): void;
|
|
36
|
+
get toolCallsTotal(): Counter;
|
|
37
|
+
get toolCallDurationMs(): Histogram;
|
|
38
|
+
get upstreamStatus(): Gauge;
|
|
39
|
+
get policyDenialsTotal(): Counter;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/telemetry/metrics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAS,MAAM,oBAAoB,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAInD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,cAAc,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,YAAY,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,mBAAmB,CAAY;IACvC,OAAO,CAAC,eAAe,CAAQ;IAC/B,OAAO,CAAC,mBAAmB,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAU;gBAEd,MAAM,EAAE,eAAe;IA0BnC,cAAc,CAAC,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI;IAKtD,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,UAAU,CAAC,GAAG,IAAI;IAK1E,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKxE,kBAAkB,CAAC,MAAM,EAAE,YAAY,CAAC,cAAc,CAAC,GAAG,IAAI;IAK9D,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,IAAI,kBAAkB,IAAI,SAAS,CAElC;IAED,IAAI,cAAc,IAAI,KAAK,CAE1B;IAED,IAAI,kBAAkB,IAAI,OAAO,CAEhC;CACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { metrics, ValueType } from "@opentelemetry/api";
|
|
2
|
+
const METER_NAME = "mcp-audit-gateway";
|
|
3
|
+
export class GatewayMetrics {
|
|
4
|
+
meter;
|
|
5
|
+
_toolCallsTotal;
|
|
6
|
+
_toolCallDurationMs;
|
|
7
|
+
_upstreamStatus;
|
|
8
|
+
_policyDenialsTotal;
|
|
9
|
+
_enabled;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this._enabled = config.enabled;
|
|
12
|
+
this.meter = metrics.getMeter(METER_NAME, "0.1.0");
|
|
13
|
+
this._toolCallsTotal = this.meter.createCounter("mcp.gateway.tool_calls_total", {
|
|
14
|
+
description: "Total number of tool calls processed by the gateway",
|
|
15
|
+
valueType: ValueType.INT,
|
|
16
|
+
});
|
|
17
|
+
this._toolCallDurationMs = this.meter.createHistogram("mcp.gateway.tool_call_duration_ms", {
|
|
18
|
+
description: "Duration of tool call execution in milliseconds",
|
|
19
|
+
unit: "ms",
|
|
20
|
+
valueType: ValueType.DOUBLE,
|
|
21
|
+
});
|
|
22
|
+
this._upstreamStatus = this.meter.createGauge("mcp.gateway.upstream_status", {
|
|
23
|
+
description: "Current status of upstream servers (1=healthy, 0=unhealthy)",
|
|
24
|
+
valueType: ValueType.INT,
|
|
25
|
+
});
|
|
26
|
+
this._policyDenialsTotal = this.meter.createCounter("mcp.gateway.policy_denials_total", {
|
|
27
|
+
description: "Total number of policy denials",
|
|
28
|
+
valueType: ValueType.INT,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
recordToolCall(labels) {
|
|
32
|
+
if (!this._enabled)
|
|
33
|
+
return;
|
|
34
|
+
this._toolCallsTotal.add(1, labels);
|
|
35
|
+
}
|
|
36
|
+
recordDuration(durationMs, labels) {
|
|
37
|
+
if (!this._enabled)
|
|
38
|
+
return;
|
|
39
|
+
this._toolCallDurationMs.record(durationMs, labels);
|
|
40
|
+
}
|
|
41
|
+
setUpstreamStatus(upstream, status, value) {
|
|
42
|
+
if (!this._enabled)
|
|
43
|
+
return;
|
|
44
|
+
this._upstreamStatus.record(value, { upstream, status });
|
|
45
|
+
}
|
|
46
|
+
recordPolicyDenial(labels) {
|
|
47
|
+
if (!this._enabled)
|
|
48
|
+
return;
|
|
49
|
+
this._policyDenialsTotal.add(1, labels);
|
|
50
|
+
}
|
|
51
|
+
get toolCallsTotal() {
|
|
52
|
+
return this._toolCallsTotal;
|
|
53
|
+
}
|
|
54
|
+
get toolCallDurationMs() {
|
|
55
|
+
return this._toolCallDurationMs;
|
|
56
|
+
}
|
|
57
|
+
get upstreamStatus() {
|
|
58
|
+
return this._upstreamStatus;
|
|
59
|
+
}
|
|
60
|
+
get policyDenialsTotal() {
|
|
61
|
+
return this._policyDenialsTotal;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/telemetry/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,UAAU,GAAG,mBAAmB,CAAC;AASvC,MAAM,OAAO,cAAc;IACjB,KAAK,CAAQ;IACb,eAAe,CAAU;IACzB,mBAAmB,CAAY;IAC/B,eAAe,CAAQ;IACvB,mBAAmB,CAAU;IAC7B,QAAQ,CAAU;IAE1B,YAAY,MAAuB;QACjC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,8BAA8B,EAAE;YAC9E,WAAW,EAAE,qDAAqD;YAClE,SAAS,EAAE,SAAS,CAAC,GAAG;SACzB,CAAC,CAAC;QAEH,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,mCAAmC,EAAE;YACzF,WAAW,EAAE,iDAAiD;YAC9D,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,SAAS,CAAC,MAAM;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,6BAA6B,EAAE;YAC3E,WAAW,EAAE,6DAA6D;YAC1E,SAAS,EAAE,SAAS,CAAC,GAAG;SACzB,CAAC,CAAC;QAEH,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,kCAAkC,EAAE;YACtF,WAAW,EAAE,gCAAgC;YAC7C,SAAS,EAAE,SAAS,CAAC,GAAG;SACzB,CAAC,CAAC;IACL,CAAC;IAED,cAAc,CAAC,MAAgC;QAC7C,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,cAAc,CAAC,UAAkB,EAAE,MAAgC;QACjE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAED,iBAAiB,CAAC,QAAgB,EAAE,MAAc,EAAE,KAAa;QAC/D,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,kBAAkB,CAAC,MAAoC;QACrD,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC3B,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;IAED,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,mBAAmB,CAAC;IAClC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.test.d.ts","sourceRoot":"","sources":["../../src/telemetry/metrics.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
2
|
+
import { metrics } from "@opentelemetry/api";
|
|
3
|
+
import { GatewayMetrics } from "./metrics.js";
|
|
4
|
+
const testConfig = {
|
|
5
|
+
enabled: true,
|
|
6
|
+
serviceName: "test-gateway",
|
|
7
|
+
sampleRate: 1.0,
|
|
8
|
+
};
|
|
9
|
+
describe("GatewayMetrics", () => {
|
|
10
|
+
let gatewayMetrics;
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
gatewayMetrics = new GatewayMetrics(testConfig);
|
|
13
|
+
});
|
|
14
|
+
describe("construction", () => {
|
|
15
|
+
it("creates all metric instruments", () => {
|
|
16
|
+
expect(gatewayMetrics.toolCallsTotal).toBeDefined();
|
|
17
|
+
expect(gatewayMetrics.toolCallDurationMs).toBeDefined();
|
|
18
|
+
expect(gatewayMetrics.upstreamStatus).toBeDefined();
|
|
19
|
+
expect(gatewayMetrics.policyDenialsTotal).toBeDefined();
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe("recordToolCall", () => {
|
|
23
|
+
it("increments tool_calls_total counter without throwing", () => {
|
|
24
|
+
expect(() => gatewayMetrics.recordToolCall({
|
|
25
|
+
namespace: "test",
|
|
26
|
+
tool: "test/my_tool",
|
|
27
|
+
principal: "agent:user1",
|
|
28
|
+
success: "true",
|
|
29
|
+
})).not.toThrow();
|
|
30
|
+
});
|
|
31
|
+
it("accepts different label combinations", () => {
|
|
32
|
+
expect(() => gatewayMetrics.recordToolCall({
|
|
33
|
+
namespace: "prod",
|
|
34
|
+
tool: "prod/fetch_data",
|
|
35
|
+
principal: "anonymous",
|
|
36
|
+
success: "false",
|
|
37
|
+
})).not.toThrow();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("recordDuration", () => {
|
|
41
|
+
it("records duration histogram without throwing", () => {
|
|
42
|
+
expect(() => gatewayMetrics.recordDuration(42.5, {
|
|
43
|
+
namespace: "test",
|
|
44
|
+
upstream: "my-server",
|
|
45
|
+
})).not.toThrow();
|
|
46
|
+
});
|
|
47
|
+
it("handles zero duration", () => {
|
|
48
|
+
expect(() => gatewayMetrics.recordDuration(0, {
|
|
49
|
+
namespace: "test",
|
|
50
|
+
upstream: "fast-server",
|
|
51
|
+
})).not.toThrow();
|
|
52
|
+
});
|
|
53
|
+
it("handles large durations", () => {
|
|
54
|
+
expect(() => gatewayMetrics.recordDuration(30000, {
|
|
55
|
+
namespace: "test",
|
|
56
|
+
upstream: "slow-server",
|
|
57
|
+
})).not.toThrow();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
describe("setUpstreamStatus", () => {
|
|
61
|
+
it("records gauge value for healthy status", () => {
|
|
62
|
+
expect(() => gatewayMetrics.setUpstreamStatus("my-upstream", "healthy", 1)).not.toThrow();
|
|
63
|
+
});
|
|
64
|
+
it("records gauge value for unhealthy status", () => {
|
|
65
|
+
expect(() => gatewayMetrics.setUpstreamStatus("my-upstream", "unavailable", 0)).not.toThrow();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe("recordPolicyDenial", () => {
|
|
69
|
+
it("increments policy_denials_total counter without throwing", () => {
|
|
70
|
+
expect(() => gatewayMetrics.recordPolicyDenial({
|
|
71
|
+
principal: "agent:blocked",
|
|
72
|
+
tool: "test/dangerous_tool",
|
|
73
|
+
reason: "unauthorized",
|
|
74
|
+
})).not.toThrow();
|
|
75
|
+
});
|
|
76
|
+
it("records denial with rate limit reason", () => {
|
|
77
|
+
expect(() => gatewayMetrics.recordPolicyDenial({
|
|
78
|
+
principal: "agent:heavy",
|
|
79
|
+
tool: "test/expensive_tool",
|
|
80
|
+
reason: "rate_limit_exceeded",
|
|
81
|
+
})).not.toThrow();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("with custom MeterProvider", () => {
|
|
85
|
+
it("uses the global meter provider", () => {
|
|
86
|
+
const getMeterSpy = vi.spyOn(metrics, "getMeter");
|
|
87
|
+
new GatewayMetrics(testConfig);
|
|
88
|
+
expect(getMeterSpy).toHaveBeenCalledWith("mcp-audit-gateway", "0.1.0");
|
|
89
|
+
getMeterSpy.mockRestore();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=metrics.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.test.js","sourceRoot":"","sources":["../../src/telemetry/metrics.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C,MAAM,UAAU,GAAoB;IAClC,OAAO,EAAE,IAAI;IACb,WAAW,EAAE,cAAc;IAC3B,UAAU,EAAE,GAAG;CAChB,CAAC;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,IAAI,cAA8B,CAAC;IAEnC,UAAU,CAAC,GAAG,EAAE;QACd,cAAc,GAAG,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC;YACpD,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC;YACxD,MAAM,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC,WAAW,EAAE,CAAC;YACpD,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;YAC9D,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,cAAc,CAAC;gBAC5B,SAAS,EAAE,MAAM;gBACjB,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,aAAa;gBACxB,OAAO,EAAE,MAAM;aAChB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,cAAc,CAAC;gBAC5B,SAAS,EAAE,MAAM;gBACjB,IAAI,EAAE,iBAAiB;gBACvB,SAAS,EAAE,WAAW;gBACtB,OAAO,EAAE,OAAO;aACjB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,cAAc,CAAC,IAAI,EAAE;gBAClC,SAAS,EAAE,MAAM;gBACjB,QAAQ,EAAE,WAAW;aACtB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,cAAc,CAAC,CAAC,EAAE;gBAC/B,SAAS,EAAE,MAAM;gBACjB,QAAQ,EAAE,aAAa;aACxB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;YACjC,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,cAAc,CAAC,KAAK,EAAE;gBACnC,SAAS,EAAE,MAAM;gBACjB,QAAQ,EAAE,aAAa;aACxB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,iBAAiB,CAAC,aAAa,EAAE,SAAS,EAAE,CAAC,CAAC,CAC9D,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,iBAAiB,CAAC,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAClE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;YAClE,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,kBAAkB,CAAC;gBAChC,SAAS,EAAE,eAAe;gBAC1B,IAAI,EAAE,qBAAqB;gBAC3B,MAAM,EAAE,cAAc;aACvB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,CAAC,GAAG,EAAE,CACV,cAAc,CAAC,kBAAkB,CAAC;gBAChC,SAAS,EAAE,aAAa;gBACxB,IAAI,EAAE,qBAAqB;gBAC3B,MAAM,EAAE,qBAAqB;aAC9B,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACzC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,WAAW,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAClD,IAAI,cAAc,CAAC,UAAU,CAAC,CAAC;YAC/B,MAAM,CAAC,WAAW,CAAC,CAAC,oBAAoB,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;YACvE,WAAW,CAAC,WAAW,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Span } from "@opentelemetry/api";
|
|
2
|
+
import type { TelemetryConfig } from "../types.js";
|
|
3
|
+
export declare class GatewayTracer {
|
|
4
|
+
private config;
|
|
5
|
+
private tracer;
|
|
6
|
+
constructor(config: TelemetryConfig);
|
|
7
|
+
startRouteSpan(method: string, toolName: string | undefined, upstream: string, traceContext?: {
|
|
8
|
+
traceparent?: string;
|
|
9
|
+
tracestate?: string;
|
|
10
|
+
}): Span;
|
|
11
|
+
endSpan(span: Span, success: boolean, errorCode?: number): void;
|
|
12
|
+
recordDuration(span: Span, durationMs: number): void;
|
|
13
|
+
getTraceParent(span: Span): string;
|
|
14
|
+
private extractContext;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=tracer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../../src/telemetry/tracer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAuB,MAAM,oBAAoB,CAAC;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAkBnD,qBAAa,aAAa;IAGZ,OAAO,CAAC,MAAM;IAF1B,OAAO,CAAC,MAAM,CAAS;gBAEH,MAAM,EAAE,eAAe;IAI3C,cAAc,CACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3D,IAAI;IA+BP,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAU/D,cAAc,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAIpD,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAMlC,OAAO,CAAC,cAAc;CAMvB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { trace, context, SpanKind, SpanStatusCode, propagation, INVALID_SPAN_CONTEXT } from "@opentelemetry/api";
|
|
2
|
+
const NOOP_SPAN = {
|
|
3
|
+
spanContext() { return INVALID_SPAN_CONTEXT; },
|
|
4
|
+
setAttribute() { return this; },
|
|
5
|
+
setAttributes() { return this; },
|
|
6
|
+
addEvent() { return this; },
|
|
7
|
+
addLink() { return this; },
|
|
8
|
+
addLinks() { return this; },
|
|
9
|
+
setStatus() { return this; },
|
|
10
|
+
updateName() { return this; },
|
|
11
|
+
end() { },
|
|
12
|
+
isRecording() { return false; },
|
|
13
|
+
recordException() { },
|
|
14
|
+
};
|
|
15
|
+
const TRACER_NAME = "mcp-audit-gateway";
|
|
16
|
+
export class GatewayTracer {
|
|
17
|
+
config;
|
|
18
|
+
tracer;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.tracer = trace.getTracer(TRACER_NAME, "0.1.0");
|
|
22
|
+
}
|
|
23
|
+
startRouteSpan(method, toolName, upstream, traceContext) {
|
|
24
|
+
if (!this.config.enabled)
|
|
25
|
+
return NOOP_SPAN;
|
|
26
|
+
const spanName = toolName
|
|
27
|
+
? `mcp.gateway/route ${upstream}`
|
|
28
|
+
: `mcp.${method}`;
|
|
29
|
+
const parentContext = traceContext?.traceparent
|
|
30
|
+
? this.extractContext(traceContext)
|
|
31
|
+
: context.active();
|
|
32
|
+
const span = this.tracer.startSpan(spanName, {
|
|
33
|
+
kind: SpanKind.INTERNAL,
|
|
34
|
+
attributes: {
|
|
35
|
+
"mcp.method": method,
|
|
36
|
+
"mcp.gateway.name": this.config.serviceName,
|
|
37
|
+
"mcp.gateway.route.target": upstream,
|
|
38
|
+
},
|
|
39
|
+
}, parentContext);
|
|
40
|
+
if (toolName) {
|
|
41
|
+
span.setAttribute("mcp.tool.name", toolName);
|
|
42
|
+
}
|
|
43
|
+
return span;
|
|
44
|
+
}
|
|
45
|
+
endSpan(span, success, errorCode) {
|
|
46
|
+
if (!success) {
|
|
47
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
48
|
+
if (errorCode != null) {
|
|
49
|
+
span.setAttribute("mcp.error.code", errorCode);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
span.end();
|
|
53
|
+
}
|
|
54
|
+
recordDuration(span, durationMs) {
|
|
55
|
+
span.setAttribute("mcp.duration_ms", durationMs);
|
|
56
|
+
}
|
|
57
|
+
getTraceParent(span) {
|
|
58
|
+
const spanContext = span.spanContext();
|
|
59
|
+
const flags = spanContext.traceFlags.toString(16).padStart(2, "0");
|
|
60
|
+
return `00-${spanContext.traceId}-${spanContext.spanId}-${flags}`;
|
|
61
|
+
}
|
|
62
|
+
extractContext(traceContext) {
|
|
63
|
+
const carrier = {};
|
|
64
|
+
if (traceContext.traceparent)
|
|
65
|
+
carrier["traceparent"] = traceContext.traceparent;
|
|
66
|
+
if (traceContext.tracestate)
|
|
67
|
+
carrier["tracestate"] = traceContext.tracestate;
|
|
68
|
+
return propagation.extract(context.active(), carrier);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=tracer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracer.js","sourceRoot":"","sources":["../../src/telemetry/tracer.ts"],"names":[],"mappings":"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"}
|