mcp-devutils 1.4.0 → 1.5.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.
Files changed (3) hide show
  1. package/README.md +7 -2
  2. package/index.js +144 -1
  3. package/package.json +8 -3
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # mcp-devutils
2
2
 
3
- MCP server with **30 developer utilities** for Claude Desktop, Cursor, and any MCP-compatible AI assistant.
3
+ MCP server with **35 developer utilities** for Claude Desktop, Cursor, and any MCP-compatible AI assistant.
4
4
 
5
5
  ## Install
6
6
 
@@ -15,7 +15,7 @@ MCP server with **30 developer utilities** for Claude Desktop, Cursor, and any M
15
15
  }
16
16
  ```
17
17
 
18
- ## Tools (30)
18
+ ## Tools (35)
19
19
 
20
20
  | Tool | Description |
21
21
  |------|-------------|
@@ -48,6 +48,11 @@ MCP server with **30 developer utilities** for Claude Desktop, Cursor, and any M
48
48
  | `password_strength` | Analyze password entropy and strength |
49
49
  | `data_size` | Convert between bytes/KB/MB/GB/TB (SI + IEC) |
50
50
  | `string_escape` | Escape strings for JSON/CSV/regex/SQL/shell |
51
+ | `nanoid` | Generate compact, URL-safe unique IDs |
52
+ | `csv_json` | Convert between CSV and JSON |
53
+ | `hex_encode` | Hex encode/decode text |
54
+ | `char_info` | Unicode character info (codepoint, UTF-8 bytes, HTML entity) |
55
+ | `byte_count` | Count string bytes in UTF-8/UTF-16/ASCII |
51
56
 
52
57
  ## Zero dependencies
53
58
 
package/index.js CHANGED
@@ -5,7 +5,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
5
5
  import crypto from "crypto";
6
6
 
7
7
  const server = new Server(
8
- { name: "mcp-devutils", version: "1.4.0" },
8
+ { name: "mcp-devutils", version: "1.5.0" },
9
9
  { capabilities: { tools: {} } }
10
10
  );
11
11
 
@@ -405,6 +405,65 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
405
405
  },
406
406
  required: ["text", "format"]
407
407
  }
408
+ },
409
+ {
410
+ name: "nanoid",
411
+ description: "Generate compact, URL-safe unique IDs (like UUID but shorter). Customizable length and alphabet.",
412
+ inputSchema: {
413
+ type: "object",
414
+ properties: {
415
+ length: { type: "number", description: "ID length (default: 21)" },
416
+ alphabet: { type: "string", description: "Custom alphabet (default: A-Za-z0-9_-)" },
417
+ count: { type: "number", description: "Number of IDs to generate (default: 1, max: 10)" }
418
+ }
419
+ }
420
+ },
421
+ {
422
+ name: "csv_json",
423
+ description: "Convert between CSV and JSON. CSV→JSON parses CSV text into an array of objects. JSON→CSV converts an array of objects to CSV.",
424
+ inputSchema: {
425
+ type: "object",
426
+ properties: {
427
+ input: { type: "string", description: "CSV text or JSON string to convert" },
428
+ direction: { type: "string", enum: ["csv_to_json", "json_to_csv"], description: "Conversion direction" },
429
+ delimiter: { type: "string", description: "CSV delimiter (default: comma)" }
430
+ },
431
+ required: ["input", "direction"]
432
+ }
433
+ },
434
+ {
435
+ name: "hex_encode",
436
+ description: "Encode text to hexadecimal or decode hex back to text",
437
+ inputSchema: {
438
+ type: "object",
439
+ properties: {
440
+ text: { type: "string", description: "Text to encode or hex string to decode" },
441
+ action: { type: "string", enum: ["encode", "decode"], description: "Action (default: encode)" }
442
+ },
443
+ required: ["text"]
444
+ }
445
+ },
446
+ {
447
+ name: "char_info",
448
+ description: "Get Unicode character info — codepoint, name category, UTF-8 bytes, HTML entity for each character in the input",
449
+ inputSchema: {
450
+ type: "object",
451
+ properties: {
452
+ text: { type: "string", description: "Characters to analyze (1-20 chars)" }
453
+ },
454
+ required: ["text"]
455
+ }
456
+ },
457
+ {
458
+ name: "byte_count",
459
+ description: "Count the byte length of a string in UTF-8, UTF-16, and ASCII. Useful for checking API payload sizes and database field limits.",
460
+ inputSchema: {
461
+ type: "object",
462
+ properties: {
463
+ text: { type: "string", description: "Text to measure" }
464
+ },
465
+ required: ["text"]
466
+ }
408
467
  }
409
468
  ]
410
469
  };
@@ -1306,6 +1365,90 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1306
1365
  return { content: [{ type: "text", text: result }] };
1307
1366
  }
1308
1367
 
1368
+ case "nanoid": {
1369
+ const len = Math.min(Math.max(args.length || 21, 1), 128);
1370
+ const alphabet = args.alphabet || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
1371
+ const count = Math.min(Math.max(args.count || 1, 1), 10);
1372
+ const ids = [];
1373
+ for (let i = 0; i < count; i++) {
1374
+ const bytes = crypto.randomBytes(len);
1375
+ let id = "";
1376
+ for (let j = 0; j < len; j++) {
1377
+ id += alphabet[bytes[j] % alphabet.length];
1378
+ }
1379
+ ids.push(id);
1380
+ }
1381
+ return { content: [{ type: "text", text: ids.join("\n") }] };
1382
+ }
1383
+
1384
+ case "csv_json": {
1385
+ const { input, direction, delimiter = "," } = args;
1386
+ if (direction === "csv_to_json") {
1387
+ const lines = input.split("\n").filter(l => l.trim());
1388
+ if (lines.length < 1) throw new Error("CSV must have at least a header row");
1389
+ const headers = lines[0].split(delimiter).map(h => h.trim().replace(/^"|"$/g, ""));
1390
+ const rows = lines.slice(1).map(line => {
1391
+ const vals = line.split(delimiter).map(v => v.trim().replace(/^"|"$/g, ""));
1392
+ const obj = {};
1393
+ headers.forEach((h, i) => { obj[h] = vals[i] || ""; });
1394
+ return obj;
1395
+ });
1396
+ return { content: [{ type: "text", text: JSON.stringify(rows, null, 2) }] };
1397
+ } else {
1398
+ const arr = JSON.parse(input);
1399
+ if (!Array.isArray(arr) || arr.length === 0) throw new Error("Input must be a non-empty JSON array");
1400
+ const headers = Object.keys(arr[0]);
1401
+ const csvLines = [headers.join(delimiter)];
1402
+ for (const row of arr) {
1403
+ csvLines.push(headers.map(h => {
1404
+ const val = String(row[h] ?? "");
1405
+ return val.includes(delimiter) || val.includes('"') || val.includes("\n")
1406
+ ? `"${val.replace(/"/g, '""')}"` : val;
1407
+ }).join(delimiter));
1408
+ }
1409
+ return { content: [{ type: "text", text: csvLines.join("\n") }] };
1410
+ }
1411
+ }
1412
+
1413
+ case "hex_encode": {
1414
+ const action = args.action || "encode";
1415
+ if (action === "encode") {
1416
+ return { content: [{ type: "text", text: Buffer.from(args.text, "utf-8").toString("hex") }] };
1417
+ } else {
1418
+ const hex = args.text.replace(/\s/g, "");
1419
+ return { content: [{ type: "text", text: Buffer.from(hex, "hex").toString("utf-8") }] };
1420
+ }
1421
+ }
1422
+
1423
+ case "char_info": {
1424
+ const chars = [...args.text].slice(0, 20);
1425
+ const info = chars.map(ch => {
1426
+ const cp = ch.codePointAt(0);
1427
+ const hex = cp.toString(16).toUpperCase().padStart(4, "0");
1428
+ const utf8Bytes = Buffer.from(ch, "utf-8");
1429
+ const htmlEntity = cp < 128 ? `&#${cp};` : `&#x${hex};`;
1430
+ return `'${ch}' U+${hex} decimal: ${cp} UTF-8: ${[...utf8Bytes].map(b => b.toString(16).padStart(2, "0")).join(" ")} HTML: ${htmlEntity}`;
1431
+ });
1432
+ return { content: [{ type: "text", text: info.join("\n") }] };
1433
+ }
1434
+
1435
+ case "byte_count": {
1436
+ const text = args.text;
1437
+ const utf8 = Buffer.byteLength(text, "utf-8");
1438
+ const utf16 = Buffer.byteLength(text, "utf-16le");
1439
+ const ascii = text.length; // JS string length
1440
+ const chars = [...text].length; // actual character count (handles surrogate pairs)
1441
+ return {
1442
+ content: [{ type: "text", text: JSON.stringify({
1443
+ characters: chars,
1444
+ js_length: text.length,
1445
+ utf8_bytes: utf8,
1446
+ utf16_bytes: utf16,
1447
+ ascii_bytes: ascii
1448
+ }, null, 2) }]
1449
+ };
1450
+ }
1451
+
1309
1452
  default:
1310
1453
  throw new Error(`Unknown tool: ${name}`);
1311
1454
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mcp-devutils",
3
- "version": "1.4.0",
4
- "description": "MCP server with 30 developer utilities - UUID, hash, HMAC, base64, timestamps, JWT decode, random strings, URL encode/decode, JSON format, regex test, cron explain, color convert, semver compare, HTTP status codes, slugify, HTML escape, chmod calculator, text diff, number base converter, lorem ipsum, word count, CIDR calculator, case converter, markdown TOC, env parser, IP info, password strength, data size converter, string escape",
3
+ "version": "1.5.0",
4
+ "description": "MCP server with 35 developer utilities - UUID, nanoid, hash, HMAC, base64, hex encode, timestamps, JWT decode, random strings, URL encode/decode, JSON format, CSV/JSON convert, regex test, cron explain, color convert, semver compare, HTTP status codes, slugify, HTML escape, chmod calculator, text diff, number base converter, lorem ipsum, word count, byte count, CIDR calculator, case converter, markdown TOC, env parser, IP info, password strength, data size converter, string escape, char info",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "bin": {
@@ -41,7 +41,12 @@
41
41
  "ip-address",
42
42
  "password-strength",
43
43
  "data-size",
44
- "string-escape"
44
+ "string-escape",
45
+ "nanoid",
46
+ "csv-json",
47
+ "hex-encode",
48
+ "unicode",
49
+ "byte-count"
45
50
  ],
46
51
  "author": "Hong Teoh",
47
52
  "license": "MIT",