@mongodb-js/mcp-logging 3.0.0-prerelease.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/dist/compositeLogger.test.d.ts +2 -0
- package/dist/compositeLogger.test.d.ts.map +1 -0
- package/dist/compositeLogger.test.js +99 -0
- package/dist/compositeLogger.test.js.map +1 -0
- package/dist/consoleLogger.d.ts +9 -0
- package/dist/consoleLogger.d.ts.map +1 -0
- package/dist/consoleLogger.js +20 -0
- package/dist/consoleLogger.js.map +1 -0
- package/dist/diskLogger.d.ts +14 -0
- package/dist/diskLogger.d.ts.map +1 -0
- package/dist/diskLogger.js +37 -0
- package/dist/diskLogger.js.map +1 -0
- package/dist/diskLogger.test.d.ts +2 -0
- package/dist/diskLogger.test.d.ts.map +1 -0
- package/dist/diskLogger.test.js +82 -0
- package/dist/diskLogger.test.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/loggerBase.test.d.ts +2 -0
- package/dist/loggerBase.test.d.ts.map +1 -0
- package/dist/loggerBase.test.js +170 -0
- package/dist/loggerBase.test.js.map +1 -0
- package/dist/mcpLogger.d.ts +20 -0
- package/dist/mcpLogger.d.ts.map +1 -0
- package/dist/mcpLogger.js +45 -0
- package/dist/mcpLogger.js.map +1 -0
- package/dist/mcpLogger.test.d.ts +2 -0
- package/dist/mcpLogger.test.d.ts.map +1 -0
- package/dist/mcpLogger.test.js +55 -0
- package/dist/mcpLogger.test.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compositeLogger.test.d.ts","sourceRoot":"","sources":["../src/compositeLogger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, beforeEach, afterEach, vi, it, expect } from "vitest";
|
|
2
|
+
import { CompositeLogger, LogId } from "@mongodb-js/mcp-core";
|
|
3
|
+
import { ConsoleLogger } from "./consoleLogger.js";
|
|
4
|
+
import { McpLogger } from "./mcpLogger.js";
|
|
5
|
+
import { Keychain } from "@mongodb-js/mcp-core";
|
|
6
|
+
describe("CompositeLogger", () => {
|
|
7
|
+
let consoleErrorSpy;
|
|
8
|
+
let consoleLogger;
|
|
9
|
+
let keychain;
|
|
10
|
+
let mcpLoggerSpy;
|
|
11
|
+
let mcpLogger;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
14
|
+
keychain = Keychain.root;
|
|
15
|
+
consoleLogger = new ConsoleLogger({ keychain });
|
|
16
|
+
mcpLoggerSpy = vi.fn();
|
|
17
|
+
mcpLogger = new McpLogger({
|
|
18
|
+
server: {
|
|
19
|
+
sendLoggingMessage: mcpLoggerSpy,
|
|
20
|
+
isConnected: () => true,
|
|
21
|
+
},
|
|
22
|
+
options: { logLevel: "debug" },
|
|
23
|
+
keychain,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
keychain.clearAllSecrets();
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
const getLastConsoleMessage = () => {
|
|
31
|
+
return consoleErrorSpy.mock.lastCall?.[0];
|
|
32
|
+
};
|
|
33
|
+
const getLastMcpLogMessage = () => {
|
|
34
|
+
return (mcpLoggerSpy.mock.lastCall?.[0]).data;
|
|
35
|
+
};
|
|
36
|
+
describe("with attributes", () => {
|
|
37
|
+
it("propagates attributes to child loggers", () => {
|
|
38
|
+
const compositeLogger = new CompositeLogger({ loggers: [consoleLogger, mcpLogger] });
|
|
39
|
+
compositeLogger.setAttribute("foo", "bar");
|
|
40
|
+
compositeLogger.info({
|
|
41
|
+
id: LogId.serverInitialized,
|
|
42
|
+
context: "test",
|
|
43
|
+
message: "Test message with attributes",
|
|
44
|
+
});
|
|
45
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
46
|
+
expect(getLastConsoleMessage()).toContain("foo=bar");
|
|
47
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
48
|
+
expect(getLastMcpLogMessage()).not.toContain("foo=bar");
|
|
49
|
+
});
|
|
50
|
+
it("merges attributes with payload attributes", () => {
|
|
51
|
+
const compositeLogger = new CompositeLogger({ loggers: [consoleLogger, mcpLogger] });
|
|
52
|
+
compositeLogger.setAttribute("foo", "bar");
|
|
53
|
+
compositeLogger.info({
|
|
54
|
+
id: LogId.serverInitialized,
|
|
55
|
+
context: "test",
|
|
56
|
+
message: "Test message with attributes",
|
|
57
|
+
attributes: { baz: "qux" },
|
|
58
|
+
});
|
|
59
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
60
|
+
expect(getLastConsoleMessage()).toContain("foo=bar");
|
|
61
|
+
expect(getLastConsoleMessage()).toContain("baz=qux");
|
|
62
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
63
|
+
expect(getLastMcpLogMessage()).not.toContain("foo=bar");
|
|
64
|
+
expect(getLastMcpLogMessage()).not.toContain("baz=qux");
|
|
65
|
+
});
|
|
66
|
+
it("doesn't impact base logger's attributes", () => {
|
|
67
|
+
const childComposite = new CompositeLogger({ loggers: [consoleLogger] });
|
|
68
|
+
const attributedComposite = new CompositeLogger({ loggers: [consoleLogger, childComposite] });
|
|
69
|
+
attributedComposite.setAttribute("foo", "bar");
|
|
70
|
+
attributedComposite.info({
|
|
71
|
+
id: LogId.serverInitialized,
|
|
72
|
+
context: "test",
|
|
73
|
+
message: "Test message with attributes",
|
|
74
|
+
});
|
|
75
|
+
// We include the console logger twice - once in the attributedComposite
|
|
76
|
+
// and another time in the childComposite, so we expect to have 2 console.error
|
|
77
|
+
// calls.
|
|
78
|
+
expect(consoleErrorSpy).toHaveBeenCalledTimes(2);
|
|
79
|
+
expect(getLastConsoleMessage()).toContain("foo=bar");
|
|
80
|
+
// The base logger should not have the attribute set
|
|
81
|
+
consoleLogger.debug({
|
|
82
|
+
id: LogId.serverInitialized,
|
|
83
|
+
context: "test",
|
|
84
|
+
message: "Another message without attributes",
|
|
85
|
+
});
|
|
86
|
+
expect(consoleErrorSpy).toHaveBeenCalledTimes(3);
|
|
87
|
+
expect(getLastConsoleMessage()).not.toContain("foo=bar");
|
|
88
|
+
// The child composite should not have the attribute set
|
|
89
|
+
childComposite.error({
|
|
90
|
+
id: LogId.serverInitialized,
|
|
91
|
+
context: "test",
|
|
92
|
+
message: "Another message without attributes",
|
|
93
|
+
});
|
|
94
|
+
expect(consoleErrorSpy).toHaveBeenCalledTimes(4);
|
|
95
|
+
expect(getLastConsoleMessage()).not.toContain("foo=bar");
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
//# sourceMappingURL=compositeLogger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compositeLogger.test.js","sourceRoot":"","sources":["../src/compositeLogger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LoggerConfig, LoggerType, LogLevel, LogPayload } from "@mongodb-js/mcp-types";
|
|
2
|
+
import { LoggerBase } from "@mongodb-js/mcp-core";
|
|
3
|
+
export declare class ConsoleLogger extends LoggerBase {
|
|
4
|
+
protected readonly type: LoggerType;
|
|
5
|
+
constructor(options: LoggerConfig);
|
|
6
|
+
protected logCore(level: LogLevel, payload: LogPayload): void;
|
|
7
|
+
private serializeAttributes;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=consoleLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleLogger.d.ts","sourceRoot":"","sources":["../src/consoleLogger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,qBAAa,aAAc,SAAQ,UAAU;IACzC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAa;gBAE7B,OAAO,EAAE,YAAY;IAIxC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAO7D,OAAO,CAAC,mBAAmB;CAQ9B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LoggerBase } from "@mongodb-js/mcp-core";
|
|
2
|
+
export class ConsoleLogger extends LoggerBase {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
super(options);
|
|
5
|
+
this.type = "console";
|
|
6
|
+
}
|
|
7
|
+
logCore(level, payload) {
|
|
8
|
+
const { id, context, message } = payload;
|
|
9
|
+
console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message}${this.serializeAttributes(payload.attributes)}`);
|
|
10
|
+
}
|
|
11
|
+
serializeAttributes(attributes) {
|
|
12
|
+
if (!attributes || Object.keys(attributes).length === 0) {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
return ` (${Object.entries(attributes)
|
|
16
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
17
|
+
.join(", ")})`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=consoleLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consoleLogger.js","sourceRoot":"","sources":["../src/consoleLogger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,OAAO,aAAc,SAAQ,UAAU;IAGzC,YAAmB,OAAqB;QACpC,KAAK,CAAC,OAAO,CAAC,CAAC;QAHA,SAAI,GAAe,SAAS,CAAC;IAIhD,CAAC;IAES,OAAO,CAAC,KAAe,EAAE,OAAmB;QAClD,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACzC,OAAO,CAAC,KAAK,CACT,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC,OAAO,MAAM,OAAO,KAAK,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CACnH,CAAC;IACN,CAAC;IAEO,mBAAmB,CAAC,UAAmC;QAC3D,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,OAAO,EAAE,CAAC;QACd,CAAC;QACD,OAAO,KAAK,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;aACjC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;aACxC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IACvB,CAAC;CACJ"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { LoggerBase } from "@mongodb-js/mcp-core";
|
|
2
|
+
import type { LogLevel, LogPayload, LoggerType, LogWriter, LoggerConfig } from "@mongodb-js/mcp-types";
|
|
3
|
+
export type DiskLoggerOptions = {
|
|
4
|
+
logWriter: LogWriter;
|
|
5
|
+
} & LoggerConfig;
|
|
6
|
+
export declare class DiskLogger extends LoggerBase {
|
|
7
|
+
private readonly logWriter;
|
|
8
|
+
constructor(options: DiskLoggerOptions);
|
|
9
|
+
protected readonly type: LoggerType;
|
|
10
|
+
protected logCore(level: LogLevel, payload: LogPayload): void;
|
|
11
|
+
flush(): Promise<PromiseSettledResult<void>[]>;
|
|
12
|
+
protected mapToMongoDBLogLevel(level: LogLevel): "info" | "warn" | "error" | "debug" | "fatal";
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=diskLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diskLogger.d.ts","sourceRoot":"","sources":["../src/diskLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEvG,MAAM,MAAM,iBAAiB,GAAG;IAC5B,SAAS,EAAE,SAAS,CAAC;CACxB,GAAG,YAAY,CAAC;AAEjB,qBAAa,UAAW,SAAQ,UAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAEnB,OAAO,EAAE,iBAAiB;IAM7C,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAU;IAE7C,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAOvC,KAAK,IAAI,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;IAIpE,SAAS,CAAC,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO;CAmBjG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { LoggerBase } from "@mongodb-js/mcp-core";
|
|
2
|
+
export class DiskLogger extends LoggerBase {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
const { logWriter, ...loggerOptions } = options;
|
|
5
|
+
super(loggerOptions);
|
|
6
|
+
this.type = "disk";
|
|
7
|
+
this.logWriter = logWriter;
|
|
8
|
+
}
|
|
9
|
+
logCore(level, payload) {
|
|
10
|
+
const { id, context, message } = payload;
|
|
11
|
+
const mongoDBLevel = this.mapToMongoDBLogLevel(level);
|
|
12
|
+
this.logWriter[mongoDBLevel]("MONGODB-MCP", id, context, message, payload.attributes);
|
|
13
|
+
}
|
|
14
|
+
async flush() {
|
|
15
|
+
return Promise.allSettled([this.logWriter.flush()]);
|
|
16
|
+
}
|
|
17
|
+
mapToMongoDBLogLevel(level) {
|
|
18
|
+
switch (level) {
|
|
19
|
+
case "info":
|
|
20
|
+
return "info";
|
|
21
|
+
case "warning":
|
|
22
|
+
return "warn";
|
|
23
|
+
case "error":
|
|
24
|
+
return "error";
|
|
25
|
+
case "notice":
|
|
26
|
+
case "debug":
|
|
27
|
+
return "debug";
|
|
28
|
+
case "critical":
|
|
29
|
+
case "alert":
|
|
30
|
+
case "emergency":
|
|
31
|
+
return "fatal";
|
|
32
|
+
default:
|
|
33
|
+
return "info";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=diskLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diskLogger.js","sourceRoot":"","sources":["../src/diskLogger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAOlD,MAAM,OAAO,UAAW,SAAQ,UAAU;IAGtC,YAAmB,OAA0B;QACzC,MAAM,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;QAChD,KAAK,CAAC,aAAa,CAAC,CAAC;QAIN,SAAI,GAAe,MAAM,CAAC;QAHzC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;IAIS,OAAO,CAAC,KAAe,EAAE,OAAmB;QAClD,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QACzC,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAEtD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,aAAa,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1F,CAAC;IAEe,KAAK,CAAC,KAAK;QACvB,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxD,CAAC;IAES,oBAAoB,CAAC,KAAe;QAC1C,QAAQ,KAAK,EAAE,CAAC;YACZ,KAAK,MAAM;gBACP,OAAO,MAAM,CAAC;YAClB,KAAK,SAAS;gBACV,OAAO,MAAM,CAAC;YAClB,KAAK,OAAO;gBACR,OAAO,OAAO,CAAC;YACnB,KAAK,QAAQ,CAAC;YACd,KAAK,OAAO;gBACR,OAAO,OAAO,CAAC;YACnB,KAAK,UAAU,CAAC;YAChB,KAAK,OAAO,CAAC;YACb,KAAK,WAAW;gBACZ,OAAO,OAAO,CAAC;YACnB;gBACI,OAAO,MAAM,CAAC;QACtB,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diskLogger.test.d.ts","sourceRoot":"","sources":["../src/diskLogger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, afterEach, beforeEach, vi, it, expect } from "vitest";
|
|
2
|
+
import { Keychain, LogId } from "@mongodb-js/mcp-core";
|
|
3
|
+
import { DiskLogger } from "./diskLogger.js";
|
|
4
|
+
const createMockLogWriter = () => {
|
|
5
|
+
const calls = [];
|
|
6
|
+
const writer = {};
|
|
7
|
+
const flushMock = vi.fn().mockResolvedValue(undefined);
|
|
8
|
+
for (const level of ["info", "warn", "error", "debug", "fatal"]) {
|
|
9
|
+
writer[level] = vi.fn((component, id, context, message, attributes) => {
|
|
10
|
+
calls.push({ level, component, id, context, message, attributes });
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
writer.flush = flushMock;
|
|
14
|
+
return { writer, calls, flushMock };
|
|
15
|
+
};
|
|
16
|
+
describe("DiskLogger", () => {
|
|
17
|
+
let keychain;
|
|
18
|
+
let mock;
|
|
19
|
+
let diskLogger;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
keychain = Keychain.root;
|
|
22
|
+
mock = createMockLogWriter();
|
|
23
|
+
diskLogger = new DiskLogger({ logWriter: mock.writer, keychain });
|
|
24
|
+
});
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
keychain.clearAllSecrets();
|
|
27
|
+
vi.restoreAllMocks();
|
|
28
|
+
});
|
|
29
|
+
describe("log level mapping", () => {
|
|
30
|
+
const cases = [
|
|
31
|
+
["info", "info"],
|
|
32
|
+
["warning", "warn"],
|
|
33
|
+
["error", "error"],
|
|
34
|
+
["notice", "debug"],
|
|
35
|
+
["debug", "debug"],
|
|
36
|
+
["critical", "fatal"],
|
|
37
|
+
["alert", "fatal"],
|
|
38
|
+
["emergency", "fatal"],
|
|
39
|
+
];
|
|
40
|
+
it.each(cases)("maps %s to the MongoDB log level %s", (level, expectedLevel) => {
|
|
41
|
+
diskLogger.log(level, {
|
|
42
|
+
id: LogId.serverInitialized,
|
|
43
|
+
context: "test",
|
|
44
|
+
message: "Test message",
|
|
45
|
+
});
|
|
46
|
+
expect(mock.calls).toHaveLength(1);
|
|
47
|
+
expect(mock.calls[0]?.level).toBe(expectedLevel);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it("delegates the log entry to the underlying log writer", () => {
|
|
51
|
+
diskLogger.error({
|
|
52
|
+
id: LogId.serverInitialized,
|
|
53
|
+
context: "test",
|
|
54
|
+
message: "Test message",
|
|
55
|
+
attributes: { foo: "bar" },
|
|
56
|
+
});
|
|
57
|
+
expect(mock.calls).toHaveLength(1);
|
|
58
|
+
expect(mock.calls[0]).toMatchObject({
|
|
59
|
+
level: "error",
|
|
60
|
+
component: "MONGODB-MCP",
|
|
61
|
+
id: LogId.serverInitialized,
|
|
62
|
+
context: "test",
|
|
63
|
+
message: "Test message",
|
|
64
|
+
attributes: { foo: "bar" },
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
it("redacts sensitive information by default", () => {
|
|
68
|
+
keychain.register("SuperSecretPass123", "password");
|
|
69
|
+
diskLogger.info({
|
|
70
|
+
id: LogId.serverInitialized,
|
|
71
|
+
context: "test",
|
|
72
|
+
message: 'Failed to connect: "mongodb://admin:SuperSecretPass123@/db"',
|
|
73
|
+
});
|
|
74
|
+
expect(mock.calls[0]?.message).not.toContain("SuperSecretPass123");
|
|
75
|
+
});
|
|
76
|
+
it("delegates flush to the underlying log writer", async () => {
|
|
77
|
+
const results = await diskLogger.flush();
|
|
78
|
+
expect(mock.flushMock).toHaveBeenCalledOnce();
|
|
79
|
+
expect(results[0]?.status).toBe("fulfilled");
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=diskLogger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diskLogger.test.js","sourceRoot":"","sources":["../src/diskLogger.test.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loggerBase.test.d.ts","sourceRoot":"","sources":["../src/loggerBase.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { describe, beforeEach, afterEach, vi, it, expect } from "vitest";
|
|
2
|
+
import { CompositeLogger, LogId } from "@mongodb-js/mcp-core";
|
|
3
|
+
import { ConsoleLogger } from "./consoleLogger.js";
|
|
4
|
+
import { McpLogger } from "./mcpLogger.js";
|
|
5
|
+
import { Keychain } from "@mongodb-js/mcp-core";
|
|
6
|
+
describe("LoggerBase redaction", () => {
|
|
7
|
+
let consoleErrorSpy;
|
|
8
|
+
let consoleLogger;
|
|
9
|
+
let keychain;
|
|
10
|
+
let mcpLoggerSpy;
|
|
11
|
+
let mcpLogger;
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
|
|
14
|
+
keychain = Keychain.root;
|
|
15
|
+
consoleLogger = new ConsoleLogger({ keychain });
|
|
16
|
+
mcpLoggerSpy = vi.fn();
|
|
17
|
+
mcpLogger = new McpLogger({
|
|
18
|
+
server: {
|
|
19
|
+
sendLoggingMessage: mcpLoggerSpy,
|
|
20
|
+
isConnected: () => true,
|
|
21
|
+
},
|
|
22
|
+
options: { logLevel: "debug" },
|
|
23
|
+
keychain,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
keychain.clearAllSecrets();
|
|
28
|
+
vi.restoreAllMocks();
|
|
29
|
+
});
|
|
30
|
+
const getLastMcpLogMessage = () => {
|
|
31
|
+
return (mcpLoggerSpy.mock.lastCall?.[0]).data;
|
|
32
|
+
};
|
|
33
|
+
const getLastConsoleMessage = () => {
|
|
34
|
+
return consoleErrorSpy.mock.lastCall?.[0];
|
|
35
|
+
};
|
|
36
|
+
const mockSensitivePayload = {
|
|
37
|
+
id: LogId.serverInitialized,
|
|
38
|
+
context: "test",
|
|
39
|
+
message: "My email is foo@bar.com",
|
|
40
|
+
};
|
|
41
|
+
const expectLogMessageRedaction = (logMessage, expectRedacted) => {
|
|
42
|
+
const expectedContain = expectRedacted ? "<email>" : "foo@bar.com";
|
|
43
|
+
const expectedNotContain = expectRedacted ? "foo@bar.com" : "<email>";
|
|
44
|
+
expect(logMessage).to.contain(expectedContain);
|
|
45
|
+
expect(logMessage).to.not.contain(expectedNotContain);
|
|
46
|
+
};
|
|
47
|
+
it("redacts sensitive information by default", () => {
|
|
48
|
+
consoleLogger.info(mockSensitivePayload);
|
|
49
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
50
|
+
expectLogMessageRedaction(getLastConsoleMessage(), true);
|
|
51
|
+
});
|
|
52
|
+
it("redacts sensitive information for mcp logger by default", () => {
|
|
53
|
+
mcpLogger.info(mockSensitivePayload);
|
|
54
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
55
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), true);
|
|
56
|
+
});
|
|
57
|
+
it("redacts keychain secrets from mcp logger by default", () => {
|
|
58
|
+
keychain.register("SuperSecretPass123", "password");
|
|
59
|
+
mcpLogger.error({
|
|
60
|
+
id: LogId.serverInitialized,
|
|
61
|
+
context: "test",
|
|
62
|
+
message: 'Failed to connect: "mongodb://admin:SuperSecretPass123@/db"',
|
|
63
|
+
});
|
|
64
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
65
|
+
expect(getLastMcpLogMessage()).not.toContain("SuperSecretPass123");
|
|
66
|
+
});
|
|
67
|
+
it("redacts sensitive information from the keychain", () => {
|
|
68
|
+
keychain.register("123456", "password");
|
|
69
|
+
consoleLogger.info({ id: LogId.serverInitialized, context: "test", message: "Your password is 123456." });
|
|
70
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
71
|
+
expect(getLastConsoleMessage()).to.contain("Your password is <password>");
|
|
72
|
+
expect(getLastConsoleMessage()).to.not.contain("123456");
|
|
73
|
+
});
|
|
74
|
+
it("redacts sensitive information in attributes", () => {
|
|
75
|
+
keychain.register("123456", "password");
|
|
76
|
+
consoleLogger.info({
|
|
77
|
+
id: LogId.serverInitialized,
|
|
78
|
+
context: "test",
|
|
79
|
+
message: "Safe message",
|
|
80
|
+
attributes: { sessionKey: "contains 123456 value" },
|
|
81
|
+
});
|
|
82
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
83
|
+
expect(getLastConsoleMessage()).to.contain("sessionKey=contains <password> value");
|
|
84
|
+
expect(getLastConsoleMessage()).to.not.contain("123456");
|
|
85
|
+
});
|
|
86
|
+
it("redacts sensitive information from built-in patterns in attributes", () => {
|
|
87
|
+
consoleLogger.info({
|
|
88
|
+
id: LogId.serverInitialized,
|
|
89
|
+
context: "test",
|
|
90
|
+
message: "Safe message",
|
|
91
|
+
attributes: { detail: "contact foo@bar.com for info" },
|
|
92
|
+
});
|
|
93
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
94
|
+
expect(getLastConsoleMessage()).to.contain("detail=contact <email> for info");
|
|
95
|
+
expect(getLastConsoleMessage()).to.not.contain("foo@bar.com");
|
|
96
|
+
});
|
|
97
|
+
it("allows disabling redaction for all loggers", () => {
|
|
98
|
+
const payload = {
|
|
99
|
+
...mockSensitivePayload,
|
|
100
|
+
noRedaction: true,
|
|
101
|
+
};
|
|
102
|
+
consoleLogger.debug(payload);
|
|
103
|
+
mcpLogger.error(payload);
|
|
104
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
105
|
+
expectLogMessageRedaction(getLastConsoleMessage(), false);
|
|
106
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
107
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), false);
|
|
108
|
+
});
|
|
109
|
+
it("allows forcing redaction for all loggers", () => {
|
|
110
|
+
const payload = {
|
|
111
|
+
...mockSensitivePayload,
|
|
112
|
+
noRedaction: false,
|
|
113
|
+
};
|
|
114
|
+
consoleLogger.warning(payload);
|
|
115
|
+
mcpLogger.warning(payload);
|
|
116
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
117
|
+
expectLogMessageRedaction(getLastConsoleMessage(), true);
|
|
118
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
119
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), true);
|
|
120
|
+
});
|
|
121
|
+
it("allows disabling redaction for specific loggers", () => {
|
|
122
|
+
const payload = {
|
|
123
|
+
...mockSensitivePayload,
|
|
124
|
+
noRedaction: "console",
|
|
125
|
+
};
|
|
126
|
+
consoleLogger.debug(payload);
|
|
127
|
+
mcpLogger.debug(payload);
|
|
128
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
129
|
+
expectLogMessageRedaction(getLastConsoleMessage(), false);
|
|
130
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
131
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), true);
|
|
132
|
+
});
|
|
133
|
+
it("allows disabling redaction for multiple loggers", () => {
|
|
134
|
+
const payload = {
|
|
135
|
+
...mockSensitivePayload,
|
|
136
|
+
noRedaction: ["console", "mcp"],
|
|
137
|
+
};
|
|
138
|
+
consoleLogger.notice(payload);
|
|
139
|
+
mcpLogger.notice(payload);
|
|
140
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
141
|
+
expectLogMessageRedaction(getLastConsoleMessage(), false);
|
|
142
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
143
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), false);
|
|
144
|
+
});
|
|
145
|
+
describe("CompositeLogger redaction", () => {
|
|
146
|
+
it("propagates noRedaction config to child loggers", () => {
|
|
147
|
+
const compositeLogger = new CompositeLogger({ loggers: [consoleLogger, mcpLogger] });
|
|
148
|
+
compositeLogger.info({
|
|
149
|
+
...mockSensitivePayload,
|
|
150
|
+
noRedaction: true,
|
|
151
|
+
});
|
|
152
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
153
|
+
expectLogMessageRedaction(getLastConsoleMessage(), false);
|
|
154
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
155
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), false);
|
|
156
|
+
});
|
|
157
|
+
it("supports redaction for a subset of its child loggers", () => {
|
|
158
|
+
const compositeLogger = new CompositeLogger({ loggers: [consoleLogger, mcpLogger] });
|
|
159
|
+
compositeLogger.info({
|
|
160
|
+
...mockSensitivePayload,
|
|
161
|
+
noRedaction: ["console", "disk"],
|
|
162
|
+
});
|
|
163
|
+
expect(consoleErrorSpy).toHaveBeenCalledOnce();
|
|
164
|
+
expectLogMessageRedaction(getLastConsoleMessage(), false);
|
|
165
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
166
|
+
expectLogMessageRedaction(getLastMcpLogMessage(), true);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
//# sourceMappingURL=loggerBase.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loggerBase.test.js","sourceRoot":"","sources":["../src/loggerBase.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { McpServer, LoggerConfig, LoggerType, LogLevel, LogPayload } from "@mongodb-js/mcp-types";
|
|
2
|
+
import { LoggerBase } from "@mongodb-js/mcp-core";
|
|
3
|
+
export declare class McpLogger extends LoggerBase {
|
|
4
|
+
private readonly server;
|
|
5
|
+
private readonly logLevel;
|
|
6
|
+
private readonly pendingSends;
|
|
7
|
+
constructor({ server, options, ...loggerConfig }: {
|
|
8
|
+
server: McpServer;
|
|
9
|
+
options: {
|
|
10
|
+
logLevel: LogLevel;
|
|
11
|
+
};
|
|
12
|
+
} & LoggerConfig);
|
|
13
|
+
protected getMcpLogLevel(): LogLevel;
|
|
14
|
+
protected readonly type: LoggerType;
|
|
15
|
+
protected logCore(level: LogLevel, payload: LogPayload): void;
|
|
16
|
+
/** Dispatches the logging message to the MCP client and keeps track of pending sends */
|
|
17
|
+
private dispatchLoggingMessage;
|
|
18
|
+
flush(): Promise<PromiseSettledResult<void>[]>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=mcpLogger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpLogger.d.ts","sourceRoot":"","sources":["../src/mcpLogger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACvG,OAAO,EAAkB,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElE,qBAAa,SAAU,SAAQ,UAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;gBAEtC,EACf,MAAM,EACN,OAAO,EACP,GAAG,YAAY,EAClB,EAAE;QACC,MAAM,EAAE,SAAS,CAAC;QAClB,OAAO,EAAE;YACL,QAAQ,EAAE,QAAQ,CAAC;SACtB,CAAC;KACL,GAAG,YAAY;IAMhB,SAAS,CAAC,cAAc,IAAI,QAAQ;IAIpC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAS;IAE5C,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI;IAc7D,wFAAwF;YAC1E,sBAAsB;IAed,KAAK,IAAI,OAAO,CAAC,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;CAGvE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { MCP_LOG_LEVELS, LoggerBase } from "@mongodb-js/mcp-core";
|
|
2
|
+
export class McpLogger extends LoggerBase {
|
|
3
|
+
constructor({ server, options, ...loggerConfig }) {
|
|
4
|
+
super(loggerConfig);
|
|
5
|
+
this.pendingSends = new Set();
|
|
6
|
+
this.type = "mcp";
|
|
7
|
+
this.server = server;
|
|
8
|
+
this.logLevel = options.logLevel;
|
|
9
|
+
}
|
|
10
|
+
getMcpLogLevel() {
|
|
11
|
+
return this.logLevel;
|
|
12
|
+
}
|
|
13
|
+
logCore(level, payload) {
|
|
14
|
+
if (!this.server.isConnected()) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const minimumLevel = MCP_LOG_LEVELS.indexOf(this.getMcpLogLevel());
|
|
18
|
+
const currentLevel = MCP_LOG_LEVELS.indexOf(level);
|
|
19
|
+
if (minimumLevel > currentLevel) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
void this.dispatchLoggingMessage(level, payload);
|
|
23
|
+
}
|
|
24
|
+
/** Dispatches the logging message to the MCP client and keeps track of pending sends */
|
|
25
|
+
async dispatchLoggingMessage(level, payload) {
|
|
26
|
+
const promise = this.server.sendLoggingMessage({
|
|
27
|
+
level,
|
|
28
|
+
data: `[${payload.context}]: ${payload.message}`,
|
|
29
|
+
});
|
|
30
|
+
this.pendingSends.add(promise);
|
|
31
|
+
try {
|
|
32
|
+
await promise;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Swallow send failures — same as the original fire-and-forget behavior
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
this.pendingSends.delete(promise);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async flush() {
|
|
42
|
+
return Promise.allSettled([...this.pendingSends]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=mcpLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpLogger.js","sourceRoot":"","sources":["../src/mcpLogger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElE,MAAM,OAAO,SAAU,SAAQ,UAAU;IAKrC,YAAmB,EACf,MAAM,EACN,OAAO,EACP,GAAG,YAAY,EAMH;QACZ,KAAK,CAAC,YAAY,CAAC,CAAC;QAZP,iBAAY,GAAG,IAAI,GAAG,EAAiB,CAAC;QAqBtC,SAAI,GAAe,KAAK,CAAC;QARxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IACrC,CAAC;IAES,cAAc;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;IAIS,OAAO,CAAC,KAAe,EAAE,OAAmB;QAClD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7B,OAAO;QACX,CAAC;QAED,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QACnE,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACnD,IAAI,YAAY,GAAG,YAAY,EAAE,CAAC;YAC9B,OAAO;QACX,CAAC;QAED,KAAK,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED,wFAAwF;IAChF,KAAK,CAAC,sBAAsB,CAAC,KAAe,EAAE,OAAmB;QACrE,MAAM,OAAO,GAAkB,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAC1D,KAAK;YACL,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,MAAM,OAAO,CAAC,OAAO,EAAE;SACnD,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC;YACD,MAAM,OAAO,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACL,wEAAwE;QAC5E,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACL,CAAC;IAEe,KAAK,CAAC,KAAK;QACvB,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IACtD,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpLogger.test.d.ts","sourceRoot":"","sources":["../src/mcpLogger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, beforeEach, afterEach, vi, it, expect } from "vitest";
|
|
2
|
+
import { LogId, MCP_LOG_LEVELS } from "@mongodb-js/mcp-core";
|
|
3
|
+
import { McpLogger } from "./mcpLogger.js";
|
|
4
|
+
import { LoggingMessageNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { Keychain } from "@mongodb-js/mcp-core";
|
|
6
|
+
class DynamicMcpLogger extends McpLogger {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.minimumLevel = "debug";
|
|
10
|
+
}
|
|
11
|
+
getMcpLogLevel() {
|
|
12
|
+
return this.minimumLevel;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
describe("McpLogger", () => {
|
|
16
|
+
let keychain;
|
|
17
|
+
let mcpLoggerSpy;
|
|
18
|
+
let mcpLogger;
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.spyOn(console, "error").mockImplementation(() => { });
|
|
21
|
+
keychain = Keychain.root;
|
|
22
|
+
mcpLoggerSpy = vi.fn();
|
|
23
|
+
mcpLogger = new DynamicMcpLogger({
|
|
24
|
+
server: {
|
|
25
|
+
sendLoggingMessage: mcpLoggerSpy,
|
|
26
|
+
isConnected: () => true,
|
|
27
|
+
},
|
|
28
|
+
options: { logLevel: "debug" },
|
|
29
|
+
keychain,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
keychain.clearAllSecrets();
|
|
34
|
+
vi.restoreAllMocks();
|
|
35
|
+
});
|
|
36
|
+
const getLastMcpLogMessage = () => {
|
|
37
|
+
return (mcpLoggerSpy.mock.lastCall?.[0]).data;
|
|
38
|
+
};
|
|
39
|
+
it("filters out messages below the minimum log level", () => {
|
|
40
|
+
mcpLogger.minimumLevel = "debug";
|
|
41
|
+
mcpLogger.log("debug", { id: LogId.serverInitialized, context: "test", message: "Debug message" });
|
|
42
|
+
expect(mcpLoggerSpy).toHaveBeenCalledOnce();
|
|
43
|
+
expect(getLastMcpLogMessage()).toContain("Debug message");
|
|
44
|
+
mcpLogger.minimumLevel = "info";
|
|
45
|
+
mcpLogger.log("debug", { id: LogId.serverInitialized, context: "test", message: "Debug message 2" });
|
|
46
|
+
expect(mcpLoggerSpy).toHaveBeenCalledTimes(1);
|
|
47
|
+
mcpLogger.log("alert", { id: LogId.serverInitialized, context: "test", message: "Alert message" });
|
|
48
|
+
expect(mcpLoggerSpy).toHaveBeenCalledTimes(2);
|
|
49
|
+
expect(getLastMcpLogMessage()).toContain("Alert message");
|
|
50
|
+
});
|
|
51
|
+
it("MCPLogger.LOG_LEVELS contains all possible levels", () => {
|
|
52
|
+
expect(MCP_LOG_LEVELS).toEqual(LoggingMessageNotificationSchema.shape.params.shape.level.options);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=mcpLogger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpLogger.test.js","sourceRoot":"","sources":["../src/mcpLogger.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mongodb-js/mcp-logging",
|
|
3
|
+
"description": "MongoDB-specific logging utilities for the MongoDB MCP server",
|
|
4
|
+
"version": "3.0.0-prerelease.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"author": "MongoDB <info@mongodb.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"url": "https://github.com/mongodb-js/mongodb-mcp-server.git",
|
|
10
|
+
"directory": "packages/logging"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc --build tsconfig.build.json",
|
|
25
|
+
"test": "vitest --run",
|
|
26
|
+
"check": "tsc --build tsconfig.build.json --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@mongodb-js/mcp-core": "workspace:*"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@mongodb-js/mcp-types": "workspace:*",
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
34
|
+
"@types/node": "^25.6.0",
|
|
35
|
+
"typescript": "^5.9.2",
|
|
36
|
+
"vitest": "^4.1.4"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|