it-tools-mcp 3.0.5 → 3.0.7

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
@@ -4,17 +4,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import { getResourceUsage } from "./security.js";
5
5
  import fs from 'fs';
6
6
  import path from 'path';
7
- // Import tool modules
8
- import { registerEncodingTools } from "./tools/encoding.js";
9
- import { registerCryptoTools } from "./tools/crypto.js";
10
- import { registerDataFormatTools } from "./tools/dataFormat.js";
11
- import { registerTextTools } from "./tools/text.js";
12
- import { registerIdGeneratorTools } from "./tools/idGenerators.js";
13
- import { registerNetworkTools } from "./tools/network.js";
14
- import { registerMathTools } from "./tools/math.js";
15
- import { registerUtilityTools } from "./tools/utility.js";
16
- import { registerDevelopmentTools } from "./tools/development.js";
17
- import { registerColorTools } from "./tools/color.js";
18
7
  // Helper to read version from package.json at runtime (ESM compatible)
19
8
  function getPackageVersion() {
20
9
  // Use import.meta.url to get the directory in ESM
@@ -32,17 +21,26 @@ const server = new McpServer({
32
21
  tools: {},
33
22
  },
34
23
  });
35
- // Register all tool modules
36
- registerEncodingTools(server);
37
- registerCryptoTools(server);
38
- registerDataFormatTools(server);
39
- registerTextTools(server);
40
- registerIdGeneratorTools(server);
41
- registerNetworkTools(server);
42
- registerMathTools(server);
43
- registerUtilityTools(server);
44
- registerDevelopmentTools(server);
45
- registerColorTools(server);
24
+ // Register all tool modules (dynamically for faster startup, with per-module timing)
25
+ async function registerAllTools(server) {
26
+ const modules = [
27
+ { name: 'encoding', fn: () => import('./tools/encoding.js').then(m => m.registerEncodingTools(server)) },
28
+ { name: 'crypto', fn: () => import('./tools/crypto.js').then(m => m.registerCryptoTools(server)) },
29
+ { name: 'dataFormat', fn: () => import('./tools/dataFormat.js').then(m => m.registerDataFormatTools(server)) },
30
+ { name: 'text', fn: () => import('./tools/text.js').then(m => m.registerTextTools(server)) },
31
+ { name: 'idGenerators', fn: () => import('./tools/idGenerators.js').then(m => m.registerIdGeneratorTools(server)) },
32
+ { name: 'network', fn: () => import('./tools/network.js').then(m => m.registerNetworkTools(server)) },
33
+ { name: 'math', fn: () => import('./tools/math.js').then(m => m.registerMathTools(server)) },
34
+ { name: 'utility', fn: () => import('./tools/utility.js').then(m => m.registerUtilityTools(server)) },
35
+ { name: 'development', fn: () => import('./tools/development.js').then(m => m.registerDevelopmentTools(server)) },
36
+ { name: 'color', fn: () => import('./tools/color.js').then(m => m.registerColorTools(server)) },
37
+ ];
38
+ for (const mod of modules) {
39
+ console.time(`register:${mod.name}`);
40
+ await mod.fn();
41
+ console.timeEnd(`register:${mod.name}`);
42
+ }
43
+ }
46
44
  // Add resource monitoring tool
47
45
  server.tool("system-info", "Get system resource usage and server information", {}, async () => {
48
46
  const usage = getResourceUsage();
@@ -63,8 +61,13 @@ server.tool("system-info", "Get system resource usage and server information", {
63
61
  });
64
62
  // Run the server
65
63
  async function main() {
64
+ console.time("Tool registration");
65
+ await registerAllTools(server);
66
+ console.timeEnd("Tool registration");
66
67
  const transport = new StdioServerTransport();
68
+ console.time("Server connect");
67
69
  await server.connect(transport);
70
+ console.timeEnd("Server connect");
68
71
  // Log startup with resource info
69
72
  console.error("IT Tools MCP Server running on stdio");
70
73
  console.error("Resource usage:", JSON.stringify(getResourceUsage(), null, 2));
@@ -78,7 +81,9 @@ async function main() {
78
81
  }
79
82
  }, 5 * 60 * 1000);
80
83
  }
84
+ console.timeEnd("Total startup");
81
85
  }
86
+ console.time("Total startup");
82
87
  main().catch((error) => {
83
88
  console.error("Fatal error in main():", error);
84
89
  process.exit(1);
@@ -1,10 +1,3 @@
1
- import * as toml from "@iarna/toml";
2
- import * as YAML from "js-yaml";
3
- import Papa from "papaparse";
4
- import { format as formatSQL } from "sql-formatter";
5
- import formatXML from "xml-formatter";
6
- import { marked } from "marked";
7
- import TurndownService from "turndown";
8
1
  import { z } from "zod";
9
2
  export function registerDataFormatTools(server) {
10
3
  // JSON formatting tool
@@ -132,12 +125,13 @@ Examples of supported formats:
132
125
  };
133
126
  }
134
127
  });
135
- // JSON to CSV converter
128
+ // CSV converter (using papaparse)
136
129
  server.tool("json-to-csv", "Convert JSON to CSV format", {
137
130
  json: z.string().describe("JSON string to convert to CSV"),
138
131
  delimiter: z.string().describe("CSV delimiter").optional(),
139
132
  }, async ({ json, delimiter = "," }) => {
140
133
  try {
134
+ const Papa = (await import("papaparse")).default;
141
135
  const data = JSON.parse(json);
142
136
  if (!Array.isArray(data)) {
143
137
  throw new Error("JSON must be an array of objects");
@@ -163,54 +157,12 @@ Examples of supported formats:
163
157
  };
164
158
  }
165
159
  });
166
- // XML formatter tool
167
- server.tool("xml-format", "Format and prettify XML", {
168
- xml: z.string().describe("XML string to format"),
169
- indent: z.number().describe("Number of spaces for indentation").optional(),
170
- }, async ({ xml, indent = 2 }) => {
171
- try {
172
- const formatted = formatXML(xml, {
173
- indentation: ' '.repeat(indent),
174
- filter: (node) => node.type !== 'Comment',
175
- collapseContent: true,
176
- lineSeparator: '\n'
177
- });
178
- return {
179
- content: [
180
- {
181
- type: "text",
182
- text: `Formatted XML:
183
-
184
- ${formatted}
185
-
186
- ✅ XML formatted successfully
187
- 🎯 Features: ${indent}-space indentation, collapsed content, clean structure`,
188
- },
189
- ],
190
- };
191
- }
192
- catch (error) {
193
- return {
194
- content: [
195
- {
196
- type: "text",
197
- text: `Error formatting XML: ${error instanceof Error ? error.message : 'Unknown error'}
198
-
199
- 💡 Common XML issues:
200
- • Check that all tags are properly closed
201
- • Ensure proper nesting of elements
202
- • Validate attribute syntax (key="value")
203
- • Check for special character encoding`,
204
- },
205
- ],
206
- };
207
- }
208
- });
209
160
  // YAML formatter tool
210
161
  server.tool("yaml-format", "Format and prettify YAML", {
211
162
  yaml: z.string().describe("YAML string to format"),
212
163
  }, async ({ yaml }) => {
213
164
  try {
165
+ const YAML = await import("js-yaml");
214
166
  // Parse YAML to validate and then dump with proper formatting
215
167
  const parsed = YAML.load(yaml);
216
168
  // Format with proper indentation and options
@@ -261,18 +213,56 @@ ${formatted.trim()}
261
213
  };
262
214
  }
263
215
  });
216
+ // XML formatter tool
217
+ server.tool("xml-format", "Format and prettify XML", {
218
+ xml: z.string().describe("XML string to format"),
219
+ indent: z.number().describe("Number of spaces for indentation").optional(),
220
+ }, async ({ xml, indent = 2 }) => {
221
+ try {
222
+ const formatXML = (await import("xml-formatter")).default;
223
+ const formatted = formatXML(xml, {
224
+ indentation: ' '.repeat(indent),
225
+ collapseContent: true,
226
+ });
227
+ return {
228
+ content: [
229
+ {
230
+ type: "text",
231
+ text: `Formatted XML:
232
+
233
+ ${formatted}
234
+
235
+ ✅ XML formatted successfully
236
+ 🎯 Features: ${indent}-space indentation, collapsed content, clean structure`,
237
+ },
238
+ ],
239
+ };
240
+ }
241
+ catch (error) {
242
+ return {
243
+ content: [
244
+ {
245
+ type: "text",
246
+ text: `Error formatting XML: ${error instanceof Error ? error.message : 'Unknown error'}
247
+
248
+ 💡 Common XML issues:
249
+ • Check that all tags are properly closed
250
+ • Ensure proper nesting of elements
251
+ • Validate attribute syntax (key="value")
252
+ • Check for special character encoding`,
253
+ },
254
+ ],
255
+ };
256
+ }
257
+ });
264
258
  // SQL formatter tool
265
259
  server.tool("sql-format", "Format and prettify SQL queries", {
266
260
  sql: z.string().describe("SQL query to format"),
267
261
  }, async ({ sql }) => {
268
262
  try {
263
+ const { format: formatSQL } = await import("sql-formatter");
269
264
  const formatted = formatSQL(sql, {
270
- language: 'sql',
271
- tabWidth: 2,
272
- useTabs: false,
273
- keywordCase: 'upper',
274
- identifierCase: 'lower',
275
- functionCase: 'upper'
265
+ language: "sql"
276
266
  });
277
267
  return {
278
268
  content: [
@@ -310,6 +300,7 @@ ${formatted}
310
300
  toml: z.string().describe("TOML string to convert"),
311
301
  }, async ({ toml: tomlString }) => {
312
302
  try {
303
+ const toml = await import("@iarna/toml");
313
304
  const result = toml.parse(tomlString);
314
305
  return {
315
306
  content: [
@@ -336,6 +327,7 @@ ${formatted}
336
327
  json: z.string().describe("JSON string to convert"),
337
328
  }, async ({ json }) => {
338
329
  try {
330
+ const toml = await import("@iarna/toml");
339
331
  const data = JSON.parse(json);
340
332
  const tomlResult = toml.stringify(data);
341
333
  return {
@@ -363,7 +355,7 @@ ${formatted}
363
355
  markdown: z.string().describe("Markdown content to convert to HTML"),
364
356
  }, async ({ markdown }) => {
365
357
  try {
366
- // Use marked with basic configuration (marked is synchronous)
358
+ const { marked } = await import("marked");
367
359
  const html = marked(markdown, {
368
360
  breaks: true,
369
361
  gfm: true
@@ -393,13 +385,11 @@ ${formatted}
393
385
  html: z.string().describe("HTML content to convert to Markdown"),
394
386
  }, async ({ html }) => {
395
387
  try {
396
- // Configure turndown for better output
388
+ const TurndownService = (await import("turndown")).default;
397
389
  const turndownService = new TurndownService({
398
390
  headingStyle: 'atx',
399
391
  codeBlockStyle: 'fenced',
400
- bulletListMarker: '-',
401
392
  emDelimiter: '*',
402
- strongDelimiter: '**'
403
393
  });
404
394
  const markdown = turndownService.turndown(html);
405
395
  return {
@@ -1,5 +1,4 @@
1
1
  import { randomUUID } from "crypto";
2
- import QRCode from "qrcode";
3
2
  import { z } from "zod";
4
3
  export function registerIdGeneratorTools(server) {
5
4
  // UUID generation tool
@@ -53,6 +52,7 @@ For production use, please use a proper ULID library.`,
53
52
  size: z.number().describe("Size multiplier (1-3)").optional(),
54
53
  }, async ({ text, size = 1 }) => {
55
54
  try {
55
+ const QRCode = (await import("qrcode")).default;
56
56
  if (size < 1 || size > 3) {
57
57
  return {
58
58
  content: [
@@ -105,12 +105,7 @@ For production use, please use a proper ULID library.`,
105
105
  content: [
106
106
  {
107
107
  type: "text",
108
- text: `Error generating QR code: ${error instanceof Error ? error.message : 'Unknown error'}
109
-
110
- Debug info:
111
- - Text: "${text}"
112
- - Size: ${size}
113
- - QRCode library available: ${typeof QRCode !== 'undefined' ? 'Yes' : 'No'}`,
108
+ text: `Error generating QR code: ${error instanceof Error ? error.message : 'Unknown error'}\n\nDebug info:\n- Text: \"${text}\"\n- Size: ${size}`,
114
109
  },
115
110
  ],
116
111
  };
@@ -1,4 +1,3 @@
1
- import { evaluate } from "mathjs";
2
1
  import { z } from "zod";
3
2
  export function registerMathTools(server) {
4
3
  // Math expression evaluator
@@ -6,12 +5,15 @@ export function registerMathTools(server) {
6
5
  expression: z.string().describe("Mathematical expression to evaluate (e.g., '2 + 3 * 4')")
7
6
  }, async ({ expression }) => {
8
7
  try {
8
+ const { evaluate } = await import("mathjs");
9
+ const start = Date.now();
9
10
  const result = evaluate(expression);
11
+ const elapsed = Date.now() - start;
10
12
  return {
11
13
  content: [
12
14
  {
13
15
  type: "text",
14
- text: `Expression: ${expression}\nResult: ${result}`
16
+ text: `Expression: ${expression}\nResult: ${result}\n(evaluated in ${elapsed} ms)`
15
17
  }
16
18
  ]
17
19
  };
@@ -1,5 +1,3 @@
1
- import { isValidPhoneNumber, parsePhoneNumber } from "libphonenumber-js";
2
- import IBAN from "iban";
3
1
  import { z } from "zod";
4
2
  export function registerNetworkTools(server) {
5
3
  // IP address tools
@@ -448,6 +446,7 @@ ${prefix ? `Used prefix: ${prefix}` : 'Randomly generated'}`,
448
446
  countryCode: z.string().optional().describe("Country code (e.g., 'US', 'GB', 'FR')"),
449
447
  }, async ({ phoneNumber, countryCode }) => {
450
448
  try {
449
+ const { isValidPhoneNumber, parsePhoneNumber } = await import("libphonenumber-js");
451
450
  // First check if it's a valid phone number
452
451
  if (!isValidPhoneNumber(phoneNumber, countryCode)) {
453
452
  throw new Error("Invalid phone number format");
@@ -500,6 +499,7 @@ Valid: ${parsedNumber.isValid()}
500
499
  iban: z.string().describe("IBAN to validate and parse"),
501
500
  }, async ({ iban }) => {
502
501
  try {
502
+ const IBAN = (await import("iban")).default;
503
503
  // Clean the input
504
504
  const cleanIban = iban.replace(/\s/g, '').toUpperCase();
505
505
  // Validate using the IBAN library
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "it-tools-mcp",
3
- "version": "3.0.5",
3
+ "version": "3.0.7",
4
4
  "description": "MCP server providing access to various IT tools and utilities for developers",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",
@@ -13,8 +13,9 @@
13
13
  "start:node": "node build/index.js",
14
14
  "dev": "tsc && node build/index.js",
15
15
  "test": "node tests/test-server.mjs",
16
+ "test:math": "node tests/math-tool-test.mjs",
16
17
  "test:security": "node tests/security-test.mjs",
17
- "test:all": "npm run test && npm run test:security",
18
+ "test:all": "npm run test && npm run test:security && npm run test:math",
18
19
  "docker:build": "docker buildx build --platform linux/amd64,linux/arm64 --provenance=true --sbom=true -t it-tools-mcp .",
19
20
  "docker:build:local": "docker build -t it-tools-mcp .",
20
21
  "docker:run": "docker-compose up --build",
@@ -81,6 +82,7 @@
81
82
  "marked": "^15.0.12",
82
83
  "mathjs": "^14.5.2",
83
84
  "mime-types": "^3.0.1",
85
+ "node-fetch": "^3.3.2",
84
86
  "papaparse": "^5.5.3",
85
87
  "qrcode": "^1.5.4",
86
88
  "speakeasy": "^2.0.0",