drawio-mcp-server 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -9,7 +9,8 @@ import { bus_reply_stream, bus_request_stream, } from "./types.js";
9
9
  import { create_bus } from "./emitter_bus.js";
10
10
  import { default_tool } from "./tool.js";
11
11
  import { nanoid_id_generator } from "./nanoid_id_generator.js";
12
- import { create_logger, validLogLevels } from "./mcp_console_logger.js";
12
+ import { create_logger as create_console_logger } from "./mcp_console_logger.js";
13
+ import { create_logger as create_server_logger, validLogLevels, } from "./mcp_server_logger.js";
13
14
  const PORT = 3333;
14
15
  async function checkPortAvailable(port) {
15
16
  return new Promise((resolve) => {
@@ -74,21 +75,30 @@ async function start_websocket_server() {
74
75
  });
75
76
  return app;
76
77
  }
77
- // Create server instance
78
- const server = new McpServer({
79
- name: "drawio-mcp-server",
80
- version: "1.2.0",
81
- }, {
82
- capabilities: {
83
- resources: {},
84
- tools: {},
78
+ const logger_type = process.env.LOGGER_TYPE;
79
+ let capabilities = {
80
+ resources: {},
81
+ tools: {},
82
+ };
83
+ if (logger_type === "mcp_server") {
84
+ capabilities = {
85
+ ...capabilities,
85
86
  logging: {
86
87
  setLevels: true,
87
88
  levels: validLogLevels,
88
89
  },
89
- },
90
+ };
91
+ }
92
+ // Create server instance
93
+ const server = new McpServer({
94
+ name: "drawio-mcp-server",
95
+ version: "1.2.1",
96
+ }, {
97
+ capabilities,
90
98
  });
91
- const log = create_logger(server);
99
+ const log = logger_type === "mcp_server"
100
+ ? create_server_logger(server)
101
+ : create_console_logger();
92
102
  const bus = create_bus(log)(emitter);
93
103
  const id_generator = nanoid_id_generator();
94
104
  const context = {
@@ -1,133 +1,14 @@
1
- import { z } from "zod";
2
- // Log levels (lower is more severe)
3
- const LogLevelMap = {
4
- emergency: 0,
5
- alert: 1,
6
- critical: 2,
7
- error: 3,
8
- warning: 4,
9
- notice: 5,
10
- info: 6,
11
- debug: 7,
12
- };
13
- export const validLogLevels = Object.keys(LogLevelMap);
14
- // Define the request schema for setLevels
15
- const SetLevelsRequestSchema = z.object({
16
- method: z.literal("logging/setLevels"),
17
- params: z.object({
18
- levels: z.record(z.string(), z.enum(validLogLevels).nullable()),
19
- }),
20
- });
21
- // Define the request schema for setLevel
22
- const SetLevelRequestSchema = z.object({
23
- method: z.literal("logging/setLevel"),
24
- params: z.object({
25
- level: z.enum(validLogLevels),
26
- }),
27
- });
28
- // Per-logger log levels (default is root `"."`)
29
- let logLevels = {
30
- ".": LogLevelMap.info, // Start with info level
31
- };
32
- // Helper: Effective log level for a logger
33
- const getEffectiveLogLevel = (loggerName) => {
34
- return loggerName in logLevels
35
- ? logLevels[loggerName]
36
- : (logLevels["."] ?? LogLevelMap.info);
37
- };
38
- // Helper: Should we log at this level?
39
- const shouldLog = (level, loggerName) => {
40
- const numericLevel = LogLevelMap[level];
41
- const effectiveLevel = getEffectiveLogLevel(loggerName);
42
- return numericLevel <= effectiveLevel;
43
- };
44
- // Helper: Actually send a log if allowed
45
- const log = (server) => (level, loggerName, data) => {
46
- if (!(level in LogLevelMap)) {
47
- console.error(`Internal Error: Invalid log level used: ${level}`);
48
- return;
49
- }
50
- if (shouldLog(level, loggerName)) {
51
- server.server.sendLoggingMessage({
52
- level,
53
- logger: loggerName,
54
- data,
55
- });
56
- }
57
- };
58
- export function create_logger(server) {
59
- const log3 = log(server);
60
- // 2. Register handler for logging/setLevels (only override requested loggers)
61
- server.server.setRequestHandler(SetLevelsRequestSchema, async (request) => {
62
- const newLevels = request.params.levels;
63
- // Only update logLevels for specified keys; unset any set to null
64
- for (const loggerName in newLevels) {
65
- if (Object.prototype.hasOwnProperty.call(newLevels, loggerName)) {
66
- const levelName = newLevels[loggerName];
67
- if (levelName === null) {
68
- if (loggerName !== ".") {
69
- delete logLevels[loggerName]; // Remove override
70
- log3("debug", "logging", {
71
- message: `Reset log level for logger: ${loggerName}`,
72
- });
73
- }
74
- }
75
- else if (levelName &&
76
- validLogLevels.includes(levelName)) {
77
- logLevels[loggerName] = LogLevelMap[levelName];
78
- log3("debug", "logging", {
79
- message: `Set log level for logger '${loggerName}' to '${levelName}'`,
80
- });
81
- }
82
- else {
83
- log3("warning", "logging", {
84
- message: `Invalid log level '${levelName}' received for logger '${loggerName}'`,
85
- });
86
- }
87
- }
88
- }
89
- return {};
90
- });
91
- // Register handler for logging/setLevel (sets root logger level)
92
- server.server.setRequestHandler(SetLevelRequestSchema, async (request) => {
93
- const log3 = log(server);
94
- const levelName = request.params.level;
95
- if (validLogLevels.includes(levelName)) {
96
- logLevels["."] = LogLevelMap[levelName];
97
- log3("debug", "logging", {
98
- message: `Set root log level to '${levelName}'`,
99
- });
100
- }
101
- else {
102
- log3("warning", "logging", {
103
- message: `Invalid log level '${levelName}' received`,
104
- });
105
- }
106
- return {};
107
- });
1
+ export function create_logger() {
108
2
  return {
109
3
  log: (level, message, ...data) => {
110
- log3(level, ".", { message, data });
111
- // return server.server.sendLoggingMessage({
112
- // // level: LogLevelMap[level?.toLowerCase()],
113
- // level: level?.toLowerCase() as McpLogLevel,
114
- // logger: "root",
115
- // data,
116
- // });
117
- // return data.length > 0
118
- // ? console.error(`${level?.toUpperCase()}: ${message}`, ...data)
119
- // : console.error(`${level?.toUpperCase()}: ${message}`);
4
+ return data.length > 0
5
+ ? console.error(`${level?.toUpperCase()}: ${message}`, ...data)
6
+ : console.error(`${level?.toUpperCase()}: ${message}`);
120
7
  },
121
8
  debug: (message, ...data) => {
122
- log3("debug", ".", { message, data });
123
- // return server.server.sendLoggingMessage({
124
- // level: "debug" as McpLogLevel,
125
- // logger: "root",
126
- // data,
127
- // });
128
- // return data.length > 0
129
- // ? console.error(`DEBUG: ${message}`, ...data)
130
- // : console.error(`DEBUG: ${message}`);
9
+ return data.length > 0
10
+ ? console.error(`DEBUG: ${message}`, ...data)
11
+ : console.error(`DEBUG: ${message}`);
131
12
  },
132
13
  };
133
14
  }
@@ -1,196 +1,63 @@
1
1
  import { jest } from "@jest/globals";
2
2
  import { create_logger } from "./mcp_console_logger.js";
3
3
  describe("create_logger", () => {
4
- let mock_send_logging_message;
5
- let mock_set_request_handler;
6
- let mock_server;
4
+ let originalConsoleError;
5
+ let mockConsoleError;
7
6
  beforeEach(() => {
8
- mock_send_logging_message = jest.fn();
9
- mock_set_request_handler = jest.fn();
10
- mock_server = {
11
- server: {
12
- sendLoggingMessage: mock_send_logging_message,
13
- setRequestHandler: mock_set_request_handler,
14
- },
15
- };
7
+ // Save original console.error
8
+ originalConsoleError = console.error;
9
+ // Create mock for console.error
10
+ mockConsoleError = jest.fn();
11
+ console.error = mockConsoleError;
16
12
  });
17
13
  afterEach(() => {
14
+ // Restore original console.error
15
+ console.error = originalConsoleError;
16
+ // Clear all mocks
18
17
  jest.clearAllMocks();
19
18
  });
20
19
  it("should return a Logger object with log and debug methods", () => {
21
- const logger = create_logger(mock_server);
20
+ const logger = create_logger();
22
21
  expect(logger).toBeDefined();
23
22
  expect(typeof logger.log).toBe("function");
24
23
  expect(typeof logger.debug).toBe("function");
25
24
  });
26
- it("log should call sendLoggingMessage with level and data (message is ignored by implementation)", () => {
27
- const logger = create_logger(mock_server);
28
- const test_message = "test message";
29
- const test_data = { key: "value" };
30
- const test_level = "info";
31
- logger.log(test_level, test_message, test_data);
32
- expect(mock_send_logging_message).toHaveBeenCalledTimes(1);
33
- expect(mock_send_logging_message).toHaveBeenCalledWith({
34
- level: "info",
35
- logger: ".",
36
- data: { message: test_message, data: [test_data] },
37
- });
38
- });
39
- it("debug should call sendLoggingMessage with debug level and data", async () => {
40
- const logger = create_logger(mock_server);
41
- const test_message = "debug message";
42
- const test_data = { debug: true };
43
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
44
- await set_level_handler({
45
- method: "logging/setLevel",
46
- params: { level: "debug" },
47
- });
48
- mock_send_logging_message.mockClear();
49
- logger.debug(test_message, test_data);
50
- expect(mock_send_logging_message).toHaveBeenCalledTimes(1);
51
- expect(mock_send_logging_message).toHaveBeenCalledWith({
52
- level: "debug",
53
- logger: ".",
54
- data: { message: test_message, data: [test_data] },
55
- });
56
- });
57
- it("should handle no additional data parameters", async () => {
58
- const logger = create_logger(mock_server);
59
- const test_message = "message without data";
60
- logger.log("warning", test_message);
61
- expect(mock_send_logging_message).toHaveBeenCalledWith({
62
- level: "warning",
63
- logger: ".",
64
- data: { message: test_message, data: [] },
65
- });
66
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
67
- await set_level_handler({
68
- method: "logging/setLevel",
69
- params: { level: "debug" },
70
- });
71
- mock_send_logging_message.mockClear();
72
- logger.debug(test_message);
73
- expect(mock_send_logging_message).toHaveBeenCalledWith({
74
- level: "debug",
75
- logger: ".",
76
- data: { message: test_message, data: [] },
77
- });
78
- });
79
- it("should handle multiple data parameters", async () => {
80
- const logger = create_logger(mock_server);
81
- const test_message = "message with multiple data";
25
+ it("log method should call console.error with message and data", () => {
26
+ const logger = create_logger();
27
+ const testMessage = "test message";
28
+ const testData = { key: "value" };
29
+ const testLevel = "info";
30
+ logger.log(testLevel, testMessage, testData);
31
+ expect(mockConsoleError).toHaveBeenCalledTimes(1);
32
+ expect(mockConsoleError).toHaveBeenCalledWith(`${testLevel.toUpperCase()}: ${testMessage}`, testData);
33
+ });
34
+ it("debug method should call console.error with message and data", () => {
35
+ const logger = create_logger();
36
+ const testMessage = "debug message";
37
+ const testData = { debug: true };
38
+ logger.debug(testMessage, testData);
39
+ expect(mockConsoleError).toHaveBeenCalledTimes(1);
40
+ expect(mockConsoleError).toHaveBeenCalledWith(`DEBUG: ${testMessage}`, testData);
41
+ });
42
+ it("should handle no additional data parameters", () => {
43
+ const logger = create_logger();
44
+ const testMessage = "message without data";
45
+ logger.log("warn", testMessage);
46
+ expect(mockConsoleError).toHaveBeenCalledWith(`WARN: ${testMessage}`);
47
+ mockConsoleError.mockClear();
48
+ logger.debug(testMessage);
49
+ expect(mockConsoleError).toHaveBeenCalledWith(`DEBUG: ${testMessage}`);
50
+ });
51
+ it("should handle multiple data parameters", () => {
52
+ const logger = create_logger();
53
+ const testMessage = "message with multiple data";
82
54
  const data1 = { key1: "value1" };
83
55
  const data2 = { key2: "value2" };
84
56
  const data3 = "string data";
85
- logger.log("error", test_message, data1, data2, data3);
86
- expect(mock_send_logging_message).toHaveBeenCalledWith({
87
- level: "error",
88
- logger: ".",
89
- data: { message: test_message, data: [data1, data2, data3] },
90
- });
91
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
92
- await set_level_handler({
93
- method: "logging/setLevel",
94
- params: { level: "debug" },
95
- });
96
- mock_send_logging_message.mockClear();
97
- logger.debug(test_message, data1, data2, data3);
98
- expect(mock_send_logging_message).toHaveBeenCalledWith({
99
- level: "debug",
100
- logger: ".",
101
- data: { message: test_message, data: [data1, data2, data3] },
102
- });
103
- });
104
- it("should not log and print error if an invalid log level is used directly", () => {
105
- const logger = create_logger(mock_server);
106
- const console_error_spy = jest
107
- .spyOn(console, "error")
108
- .mockImplementation(() => { });
109
- logger.log("invalid_level", "this should not be logged");
110
- expect(console_error_spy).toHaveBeenCalledWith("Internal Error: Invalid log level used: invalid_level");
111
- expect(mock_send_logging_message).not.toHaveBeenCalled();
112
- console_error_spy.mockRestore();
113
- });
114
- it("should log a warning if logging/setLevel receives an invalid log level", async () => {
115
- create_logger(mock_server);
116
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
117
- await set_level_handler({
118
- method: "logging/setLevel",
119
- params: { level: "not_a_level" },
120
- });
121
- expect(mock_send_logging_message).toHaveBeenCalledWith({
122
- level: "warning",
123
- logger: "logging",
124
- data: {
125
- message: "Invalid log level 'not_a_level' received",
126
- },
127
- });
128
- });
129
- it("should support valid per-logger setLevels, and emit debug message", async () => {
130
- create_logger(mock_server);
131
- const set_levels_handler = mock_set_request_handler.mock.calls[0][1];
132
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
133
- await set_level_handler({
134
- method: "logging/setLevel",
135
- params: { level: "debug" },
136
- });
137
- mock_send_logging_message.mockClear();
138
- await set_levels_handler({
139
- method: "logging/setLevels",
140
- params: { levels: { app: "error" } },
141
- });
142
- expect(mock_send_logging_message).toHaveBeenCalledWith({
143
- level: "debug",
144
- logger: "logging",
145
- data: {
146
- message: "Set log level for logger 'app' to 'error'",
147
- },
148
- });
149
- });
150
- it("should reset per-logger level to default when null is provided", async () => {
151
- create_logger(mock_server);
152
- const set_levels_handler = mock_set_request_handler.mock.calls[0][1];
153
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
154
- await set_level_handler({
155
- method: "logging/setLevel",
156
- params: { level: "debug" },
157
- });
158
- mock_send_logging_message.mockClear();
159
- await set_levels_handler({
160
- method: "logging/setLevels",
161
- params: { levels: { app: "warning" } },
162
- });
163
- await set_levels_handler({
164
- method: "logging/setLevels",
165
- params: { levels: { app: null } },
166
- });
167
- expect(mock_send_logging_message.mock.calls.some((call) => {
168
- const arg = call[0];
169
- return (arg.level === "debug" &&
170
- arg.logger === "logging" &&
171
- arg.data &&
172
- arg.data.message === "Reset log level for logger: app");
173
- })).toBe(true);
174
- });
175
- it("should log a warning for invalid per-logger level in setLevels", async () => {
176
- create_logger(mock_server);
177
- const set_levels_handler = mock_set_request_handler.mock.calls[0][1];
178
- const set_level_handler = mock_set_request_handler.mock.calls[1][1];
179
- await set_level_handler({
180
- method: "logging/setLevel",
181
- params: { level: "debug" },
182
- });
183
- mock_send_logging_message.mockClear();
184
- await set_levels_handler({
185
- method: "logging/setLevels",
186
- params: { levels: { "my.logger": "invalid" } },
187
- });
188
- expect(mock_send_logging_message).toHaveBeenCalledWith({
189
- level: "warning",
190
- logger: "logging",
191
- data: {
192
- message: "Invalid log level 'invalid' received for logger 'my.logger'",
193
- },
194
- });
57
+ logger.log("error", testMessage, data1, data2, data3);
58
+ expect(mockConsoleError).toHaveBeenCalledWith(`ERROR: ${testMessage}`, data1, data2, data3);
59
+ mockConsoleError.mockClear();
60
+ logger.debug(testMessage, data1, data2, data3);
61
+ expect(mockConsoleError).toHaveBeenCalledWith(`DEBUG: ${testMessage}`, data1, data2, data3);
195
62
  });
196
63
  });
@@ -0,0 +1,116 @@
1
+ import { z } from "zod";
2
+ // Log levels (lower is more severe)
3
+ const LogLevelMap = {
4
+ emergency: 0,
5
+ alert: 1,
6
+ critical: 2,
7
+ error: 3,
8
+ warning: 4,
9
+ notice: 5,
10
+ info: 6,
11
+ debug: 7,
12
+ };
13
+ export const validLogLevels = Object.keys(LogLevelMap);
14
+ // Define the request schema for setLevels
15
+ const SetLevelsRequestSchema = z.object({
16
+ method: z.literal("logging/setLevels"),
17
+ params: z.object({
18
+ levels: z.record(z.string(), z.enum(validLogLevels).nullable()),
19
+ }),
20
+ });
21
+ // Define the request schema for setLevel
22
+ const SetLevelRequestSchema = z.object({
23
+ method: z.literal("logging/setLevel"),
24
+ params: z.object({
25
+ level: z.enum(validLogLevels),
26
+ }),
27
+ });
28
+ // Per-logger log levels (default is root `"."`)
29
+ let logLevels = {
30
+ ".": LogLevelMap.info, // Start with info level
31
+ };
32
+ // Helper: Effective log level for a logger
33
+ const getEffectiveLogLevel = (loggerName) => {
34
+ return loggerName in logLevels
35
+ ? logLevels[loggerName]
36
+ : (logLevels["."] ?? LogLevelMap.info);
37
+ };
38
+ // Helper: Should we log at this level?
39
+ const shouldLog = (level, loggerName) => {
40
+ const numericLevel = LogLevelMap[level];
41
+ const effectiveLevel = getEffectiveLogLevel(loggerName);
42
+ return numericLevel <= effectiveLevel;
43
+ };
44
+ // Helper: Actually send a log if allowed
45
+ const log = (server) => (level, loggerName, data) => {
46
+ if (!(level in LogLevelMap)) {
47
+ console.error(`Internal Error: Invalid log level used: ${level}`);
48
+ return;
49
+ }
50
+ if (shouldLog(level, loggerName)) {
51
+ server.server.sendLoggingMessage({
52
+ level,
53
+ logger: loggerName,
54
+ data,
55
+ });
56
+ }
57
+ };
58
+ export function create_logger(server) {
59
+ const log3 = log(server);
60
+ // 2. Register handler for logging/setLevels (only override requested loggers)
61
+ server.server.setRequestHandler(SetLevelsRequestSchema, async (request) => {
62
+ const newLevels = request.params.levels;
63
+ // Only update logLevels for specified keys; unset any set to null
64
+ for (const loggerName in newLevels) {
65
+ if (Object.prototype.hasOwnProperty.call(newLevels, loggerName)) {
66
+ const levelName = newLevels[loggerName];
67
+ if (levelName === null) {
68
+ if (loggerName !== ".") {
69
+ delete logLevels[loggerName]; // Remove override
70
+ log3("debug", "logging", {
71
+ message: `Reset log level for logger: ${loggerName}`,
72
+ });
73
+ }
74
+ }
75
+ else if (levelName &&
76
+ validLogLevels.includes(levelName)) {
77
+ logLevels[loggerName] = LogLevelMap[levelName];
78
+ log3("debug", "logging", {
79
+ message: `Set log level for logger '${loggerName}' to '${levelName}'`,
80
+ });
81
+ }
82
+ else {
83
+ log3("warning", "logging", {
84
+ message: `Invalid log level '${levelName}' received for logger '${loggerName}'`,
85
+ });
86
+ }
87
+ }
88
+ }
89
+ return {};
90
+ });
91
+ // Register handler for logging/setLevel (sets root logger level)
92
+ server.server.setRequestHandler(SetLevelRequestSchema, async (request) => {
93
+ const log3 = log(server);
94
+ const levelName = request.params.level;
95
+ if (validLogLevels.includes(levelName)) {
96
+ logLevels["."] = LogLevelMap[levelName];
97
+ log3("debug", "logging", {
98
+ message: `Set root log level to '${levelName}'`,
99
+ });
100
+ }
101
+ else {
102
+ log3("warning", "logging", {
103
+ message: `Invalid log level '${levelName}' received`,
104
+ });
105
+ }
106
+ return {};
107
+ });
108
+ return {
109
+ log: (level, message, ...data) => {
110
+ log3(level, ".", { message, data });
111
+ },
112
+ debug: (message, ...data) => {
113
+ log3("debug", ".", { message, data });
114
+ },
115
+ };
116
+ }
@@ -0,0 +1,196 @@
1
+ import { jest } from "@jest/globals";
2
+ import { create_logger } from "./mcp_server_logger.js";
3
+ describe("create_logger", () => {
4
+ let mock_send_logging_message;
5
+ let mock_set_request_handler;
6
+ let mock_server;
7
+ beforeEach(() => {
8
+ mock_send_logging_message = jest.fn();
9
+ mock_set_request_handler = jest.fn();
10
+ mock_server = {
11
+ server: {
12
+ sendLoggingMessage: mock_send_logging_message,
13
+ setRequestHandler: mock_set_request_handler,
14
+ },
15
+ };
16
+ });
17
+ afterEach(() => {
18
+ jest.clearAllMocks();
19
+ });
20
+ it("should return a Logger object with log and debug methods", () => {
21
+ const logger = create_logger(mock_server);
22
+ expect(logger).toBeDefined();
23
+ expect(typeof logger.log).toBe("function");
24
+ expect(typeof logger.debug).toBe("function");
25
+ });
26
+ it("log should call sendLoggingMessage with level and data (message is ignored by implementation)", () => {
27
+ const logger = create_logger(mock_server);
28
+ const test_message = "test message";
29
+ const test_data = { key: "value" };
30
+ const test_level = "info";
31
+ logger.log(test_level, test_message, test_data);
32
+ expect(mock_send_logging_message).toHaveBeenCalledTimes(1);
33
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
34
+ level: "info",
35
+ logger: ".",
36
+ data: { message: test_message, data: [test_data] },
37
+ });
38
+ });
39
+ it("debug should call sendLoggingMessage with debug level and data", async () => {
40
+ const logger = create_logger(mock_server);
41
+ const test_message = "debug message";
42
+ const test_data = { debug: true };
43
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
44
+ await set_level_handler({
45
+ method: "logging/setLevel",
46
+ params: { level: "debug" },
47
+ });
48
+ mock_send_logging_message.mockClear();
49
+ logger.debug(test_message, test_data);
50
+ expect(mock_send_logging_message).toHaveBeenCalledTimes(1);
51
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
52
+ level: "debug",
53
+ logger: ".",
54
+ data: { message: test_message, data: [test_data] },
55
+ });
56
+ });
57
+ it("should handle no additional data parameters", async () => {
58
+ const logger = create_logger(mock_server);
59
+ const test_message = "message without data";
60
+ logger.log("warning", test_message);
61
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
62
+ level: "warning",
63
+ logger: ".",
64
+ data: { message: test_message, data: [] },
65
+ });
66
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
67
+ await set_level_handler({
68
+ method: "logging/setLevel",
69
+ params: { level: "debug" },
70
+ });
71
+ mock_send_logging_message.mockClear();
72
+ logger.debug(test_message);
73
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
74
+ level: "debug",
75
+ logger: ".",
76
+ data: { message: test_message, data: [] },
77
+ });
78
+ });
79
+ it("should handle multiple data parameters", async () => {
80
+ const logger = create_logger(mock_server);
81
+ const test_message = "message with multiple data";
82
+ const data1 = { key1: "value1" };
83
+ const data2 = { key2: "value2" };
84
+ const data3 = "string data";
85
+ logger.log("error", test_message, data1, data2, data3);
86
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
87
+ level: "error",
88
+ logger: ".",
89
+ data: { message: test_message, data: [data1, data2, data3] },
90
+ });
91
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
92
+ await set_level_handler({
93
+ method: "logging/setLevel",
94
+ params: { level: "debug" },
95
+ });
96
+ mock_send_logging_message.mockClear();
97
+ logger.debug(test_message, data1, data2, data3);
98
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
99
+ level: "debug",
100
+ logger: ".",
101
+ data: { message: test_message, data: [data1, data2, data3] },
102
+ });
103
+ });
104
+ it("should not log and print error if an invalid log level is used directly", () => {
105
+ const logger = create_logger(mock_server);
106
+ const console_error_spy = jest
107
+ .spyOn(console, "error")
108
+ .mockImplementation(() => { });
109
+ logger.log("invalid_level", "this should not be logged");
110
+ expect(console_error_spy).toHaveBeenCalledWith("Internal Error: Invalid log level used: invalid_level");
111
+ expect(mock_send_logging_message).not.toHaveBeenCalled();
112
+ console_error_spy.mockRestore();
113
+ });
114
+ it("should log a warning if logging/setLevel receives an invalid log level", async () => {
115
+ create_logger(mock_server);
116
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
117
+ await set_level_handler({
118
+ method: "logging/setLevel",
119
+ params: { level: "not_a_level" },
120
+ });
121
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
122
+ level: "warning",
123
+ logger: "logging",
124
+ data: {
125
+ message: "Invalid log level 'not_a_level' received",
126
+ },
127
+ });
128
+ });
129
+ it("should support valid per-logger setLevels, and emit debug message", async () => {
130
+ create_logger(mock_server);
131
+ const set_levels_handler = mock_set_request_handler.mock.calls[0][1];
132
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
133
+ await set_level_handler({
134
+ method: "logging/setLevel",
135
+ params: { level: "debug" },
136
+ });
137
+ mock_send_logging_message.mockClear();
138
+ await set_levels_handler({
139
+ method: "logging/setLevels",
140
+ params: { levels: { app: "error" } },
141
+ });
142
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
143
+ level: "debug",
144
+ logger: "logging",
145
+ data: {
146
+ message: "Set log level for logger 'app' to 'error'",
147
+ },
148
+ });
149
+ });
150
+ it("should reset per-logger level to default when null is provided", async () => {
151
+ create_logger(mock_server);
152
+ const set_levels_handler = mock_set_request_handler.mock.calls[0][1];
153
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
154
+ await set_level_handler({
155
+ method: "logging/setLevel",
156
+ params: { level: "debug" },
157
+ });
158
+ mock_send_logging_message.mockClear();
159
+ await set_levels_handler({
160
+ method: "logging/setLevels",
161
+ params: { levels: { app: "warning" } },
162
+ });
163
+ await set_levels_handler({
164
+ method: "logging/setLevels",
165
+ params: { levels: { app: null } },
166
+ });
167
+ expect(mock_send_logging_message.mock.calls.some((call) => {
168
+ const arg = call[0];
169
+ return (arg.level === "debug" &&
170
+ arg.logger === "logging" &&
171
+ arg.data &&
172
+ arg.data.message === "Reset log level for logger: app");
173
+ })).toBe(true);
174
+ });
175
+ it("should log a warning for invalid per-logger level in setLevels", async () => {
176
+ create_logger(mock_server);
177
+ const set_levels_handler = mock_set_request_handler.mock.calls[0][1];
178
+ const set_level_handler = mock_set_request_handler.mock.calls[1][1];
179
+ await set_level_handler({
180
+ method: "logging/setLevel",
181
+ params: { level: "debug" },
182
+ });
183
+ mock_send_logging_message.mockClear();
184
+ await set_levels_handler({
185
+ method: "logging/setLevels",
186
+ params: { levels: { "my.logger": "invalid" } },
187
+ });
188
+ expect(mock_send_logging_message).toHaveBeenCalledWith({
189
+ level: "warning",
190
+ logger: "logging",
191
+ data: {
192
+ message: "Invalid log level 'invalid' received for logger 'my.logger'",
193
+ },
194
+ });
195
+ });
196
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drawio-mcp-server",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Provides Draw.io services to MCP Clients",
5
5
  "type": "module",
6
6
  "main": "index.js",