it-tools-mcp 3.0.23 → 3.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.
Files changed (127) hide show
  1. package/README.dockerhub.md +30 -17
  2. package/README.md +81 -33
  3. package/build/index.js +47 -15
  4. package/build/tools/ansible/ansible-inventory-generator/index.js +212 -0
  5. package/build/tools/ansible/ansible-playbook-validator/index.js +128 -0
  6. package/build/tools/ansible/ansible-reference/index.js +393 -0
  7. package/build/tools/ansible/ansible-vault-decrypt/index.js +137 -0
  8. package/build/tools/ansible/ansible-vault-encrypt/index.js +79 -0
  9. package/build/tools/color/color-hex-to-rgb/index.js +29 -0
  10. package/build/tools/{color.js → color/color-rgb-to-hex/index.js} +1 -27
  11. package/build/tools/crypto/basic-auth-generator/index.js +45 -0
  12. package/build/tools/crypto/bcrypt-hash/index.js +67 -0
  13. package/build/tools/crypto/bip39-generate/index.js +53 -0
  14. package/build/tools/crypto/hash-md5/index.js +19 -0
  15. package/build/tools/crypto/hash-sha1/index.js +19 -0
  16. package/build/tools/crypto/hash-sha256/index.js +19 -0
  17. package/build/tools/crypto/hash-sha512/index.js +19 -0
  18. package/build/tools/crypto/hmac-generator/index.js +37 -0
  19. package/build/tools/crypto/jwt-decode/index.js +41 -0
  20. package/build/tools/crypto/otp-code-generator/index.js +67 -0
  21. package/build/tools/crypto/password-generate/index.js +54 -0
  22. package/build/tools/crypto/token-generator/index.js +75 -0
  23. package/build/tools/dataFormat/html-to-markdown/index.js +34 -0
  24. package/build/tools/dataFormat/json-diff/index.js +94 -0
  25. package/build/tools/dataFormat/json-format/index.js +100 -0
  26. package/build/tools/dataFormat/json-minify/index.js +29 -0
  27. package/build/tools/dataFormat/json-to-csv/index.js +34 -0
  28. package/build/tools/dataFormat/json-to-toml/index.js +30 -0
  29. package/build/tools/dataFormat/markdown-to-html/index.js +32 -0
  30. package/build/tools/dataFormat/phone-format/index.js +35 -0
  31. package/build/tools/dataFormat/sql-format/index.js +37 -0
  32. package/build/tools/dataFormat/toml-to-json/index.js +29 -0
  33. package/build/tools/dataFormat/xml-format/index.js +44 -0
  34. package/build/tools/dataFormat/yaml-format/index.js +58 -0
  35. package/build/tools/{development.js → development/crontab-generate/index.js} +1 -129
  36. package/build/tools/development/html-prettifier/index.js +47 -0
  37. package/build/tools/development/javascript-prettifier/index.js +74 -0
  38. package/build/tools/development/list-converter/index.js +62 -0
  39. package/build/tools/development/markdown-toc-generator/index.js +53 -0
  40. package/build/tools/development/regex-tester/index.js +69 -0
  41. package/build/tools/docker/docker-compose-to-docker-run/index.js +138 -0
  42. package/build/tools/docker/docker-compose-validator/index.js +125 -0
  43. package/build/tools/docker/docker-reference/index.js +188 -0
  44. package/build/tools/docker/docker-run-to-docker-compose/index.js +117 -0
  45. package/build/tools/docker/traefik-compose-generator/index.js +98 -0
  46. package/build/tools/encoding/base64-decode/index.js +28 -0
  47. package/build/tools/encoding/base64-encode/index.js +16 -0
  48. package/build/tools/encoding/html-decode/index.js +21 -0
  49. package/build/tools/encoding/html-encode/index.js +21 -0
  50. package/build/tools/encoding/html-entities-extended/index.js +72 -0
  51. package/build/tools/encoding/text-to-binary/index.js +51 -0
  52. package/build/tools/encoding/url-decode/index.js +28 -0
  53. package/build/tools/encoding/url-encode/index.js +16 -0
  54. package/build/tools/forensic/file-type-identifier/index.js +90 -0
  55. package/build/tools/forensic/safelink-decoder/index.js +54 -0
  56. package/build/tools/forensic/url-fanger/index.js +52 -0
  57. package/build/tools/idGenerators/qr-generate/index.js +76 -0
  58. package/build/tools/idGenerators/svg-placeholder-generator/index.js +59 -0
  59. package/build/tools/idGenerators/ulid-generate/index.js +34 -0
  60. package/build/tools/idGenerators/uuid-generate/index.js +14 -0
  61. package/build/tools/math/math-evaluate/index.js +33 -0
  62. package/build/tools/math/number-base-converter/index.js +46 -0
  63. package/build/tools/math/percentage-calculator/index.js +50 -0
  64. package/build/tools/math/roman-numeral-converter/index.js +76 -0
  65. package/build/tools/math/temperature-converter/index.js +59 -0
  66. package/build/tools/math/unix-timestamp-converter/index.js +55 -0
  67. package/build/tools/network/cat/index.js +15 -0
  68. package/build/tools/network/cidr-to-ip-range/index.js +108 -0
  69. package/build/tools/network/curl/index.js +35 -0
  70. package/build/tools/network/dig/index.js +19 -0
  71. package/build/tools/network/grep/index.js +18 -0
  72. package/build/tools/network/head/index.js +17 -0
  73. package/build/tools/network/iban-validate/index.js +83 -0
  74. package/build/tools/network/ip-range-to-cidr/index.js +88 -0
  75. package/build/tools/network/ip-subnet-calculator/index.js +102 -0
  76. package/build/tools/network/ipv4-subnet-calc/index.js +112 -0
  77. package/build/tools/network/ipv6-subnet-calculator/index.js +104 -0
  78. package/build/tools/network/ipv6-ula-generator/index.js +65 -0
  79. package/build/tools/network/mac-address-generate/index.js +68 -0
  80. package/build/tools/network/nslookup/index.js +18 -0
  81. package/build/tools/network/ping/index.js +20 -0
  82. package/build/tools/network/ps/index.js +22 -0
  83. package/build/tools/network/random-port/index.js +53 -0
  84. package/build/tools/network/scp/index.js +134 -0
  85. package/build/tools/network/ssh/index.js +83 -0
  86. package/build/tools/network/tail/index.js +16 -0
  87. package/build/tools/network/telnet/index.js +45 -0
  88. package/build/tools/network/top/index.js +14 -0
  89. package/build/tools/network/url-parse/index.js +52 -0
  90. package/build/tools/physics/angle-converter/index.js +73 -0
  91. package/build/tools/physics/energy-converter/index.js +72 -0
  92. package/build/tools/physics/power-converter/index.js +71 -0
  93. package/build/tools/text/ascii-art-text/index.js +112 -0
  94. package/build/tools/text/distinct-words/index.js +30 -0
  95. package/build/tools/text/emoji-search/index.js +76 -0
  96. package/build/tools/text/lorem-ipsum-generator/index.js +87 -0
  97. package/build/tools/text/numeronym-generator/index.js +37 -0
  98. package/build/tools/text/slugify-string/index.js +44 -0
  99. package/build/tools/text/string-obfuscator/index.js +49 -0
  100. package/build/tools/text/text-camelcase/index.js +20 -0
  101. package/build/tools/text/text-capitalize/index.js +16 -0
  102. package/build/tools/text/text-diff/index.js +72 -0
  103. package/build/tools/text/text-kebabcase/index.js +20 -0
  104. package/build/tools/text/text-lowercase/index.js +15 -0
  105. package/build/tools/text/text-pascalcase/index.js +18 -0
  106. package/build/tools/text/text-snakecase/index.js +20 -0
  107. package/build/tools/text/text-stats/index.js +29 -0
  108. package/build/tools/text/text-to-nato-alphabet/index.js +57 -0
  109. package/build/tools/text/text-to-unicode/index.js +50 -0
  110. package/build/tools/text/text-to-unicode-names/index.js +34 -0
  111. package/build/tools/text/text-uppercase/index.js +15 -0
  112. package/build/tools/utility/css-prettifier/index.js +70 -0
  113. package/build/tools/utility/device-info/index.js +44 -0
  114. package/build/tools/utility/email-normalizer/index.js +73 -0
  115. package/build/tools/utility/http-status-codes/index.js +173 -0
  116. package/build/tools/utility/mime-types/index.js +121 -0
  117. package/build/tools/utility/port-numbers/index.js +106 -0
  118. package/build/tools/utility/rem-px-converter/index.js +63 -0
  119. package/package.json +3 -3
  120. package/build/tools/crypto.js +0 -445
  121. package/build/tools/dataFormat.js +0 -535
  122. package/build/tools/encoding.js +0 -240
  123. package/build/tools/idGenerators.js +0 -180
  124. package/build/tools/math.js +0 -310
  125. package/build/tools/network.js +0 -931
  126. package/build/tools/text.js +0 -678
  127. package/build/tools/utility.js +0 -407
@@ -0,0 +1,134 @@
1
+ import { z } from "zod";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import os from "os";
5
+ function resolvePrivateKey(privateKeyArg) {
6
+ // If not provided, try default keys
7
+ if (!privateKeyArg) {
8
+ const home = os.homedir();
9
+ const defaultKeys = [
10
+ path.join(home, '.ssh', 'id_rsa'),
11
+ path.join(home, '.ssh', 'id_ed25519'),
12
+ ];
13
+ for (const keyPath of defaultKeys) {
14
+ if (fs.existsSync(keyPath)) {
15
+ return fs.readFileSync(keyPath, 'utf8');
16
+ }
17
+ }
18
+ return undefined;
19
+ }
20
+ // If it looks like a path, try to read it
21
+ if (privateKeyArg.startsWith('/') ||
22
+ privateKeyArg.startsWith('~') ||
23
+ privateKeyArg.endsWith('.pem') ||
24
+ privateKeyArg.endsWith('.key')) {
25
+ let keyPath = privateKeyArg;
26
+ if (keyPath.startsWith('~')) {
27
+ keyPath = path.join(os.homedir(), keyPath.slice(1));
28
+ }
29
+ if (fs.existsSync(keyPath)) {
30
+ return fs.readFileSync(keyPath, 'utf8');
31
+ }
32
+ else {
33
+ throw new Error('Private key file not found: ' + keyPath);
34
+ }
35
+ }
36
+ // Otherwise, assume it's the key content
37
+ return privateKeyArg;
38
+ }
39
+ export function registerScp(server) {
40
+ server.tool("scp", "Copy files to or from a remote host using SFTP (SCP-like)", {
41
+ target: z.string().describe("Target host"),
42
+ user: z.string().describe("Username"),
43
+ direction: z.enum(["upload", "download"]).describe("Direction: upload (local to remote) or download (remote to local)"),
44
+ localPath: z.string().describe("Local file path (source for upload, destination for download)"),
45
+ remotePath: z.string().describe("Remote file path (destination for upload, source for download)"),
46
+ privateKey: z.string().optional().describe("Private key for authentication (PEM format, optional, or path to key file)")
47
+ }, async ({ target, user, direction, localPath, remotePath, privateKey }) => {
48
+ try {
49
+ const { Client } = await import("ssh2");
50
+ const fs = await import("fs");
51
+ let resolvedKey;
52
+ try {
53
+ resolvedKey = resolvePrivateKey(privateKey);
54
+ }
55
+ catch (err) {
56
+ return { content: [{ type: "text", text: `SCP key error: ${err.message}` }] };
57
+ }
58
+ return await new Promise((resolve) => {
59
+ const conn = new Client();
60
+ let finished = false;
61
+ const finish = (msg) => {
62
+ if (!finished) {
63
+ finished = true;
64
+ try {
65
+ conn.end();
66
+ }
67
+ catch { }
68
+ resolve({ content: [{ type: "text", text: msg }] });
69
+ }
70
+ };
71
+ // Connection timeout (20s)
72
+ const timeout = setTimeout(() => {
73
+ finish(`SCP connection timed out after 20 seconds`);
74
+ }, 20000);
75
+ conn.on("ready", () => {
76
+ clearTimeout(timeout);
77
+ conn.sftp((err, sftp) => {
78
+ if (err) {
79
+ finish(`SFTP error: ${err.message}`);
80
+ return;
81
+ }
82
+ if (direction === "upload") {
83
+ let readStream, writeStream;
84
+ try {
85
+ readStream = fs.createReadStream(localPath);
86
+ writeStream = sftp.createWriteStream(remotePath);
87
+ }
88
+ catch (streamErr) {
89
+ finish(`Upload failed: ${streamErr.message}`);
90
+ return;
91
+ }
92
+ writeStream.on("close", () => finish(`Upload complete: ${localPath} → ${user}@${target}:${remotePath}`));
93
+ writeStream.on("error", (err) => finish(`Upload failed: ${err.message}`));
94
+ readStream.on("error", (err) => finish(`Upload failed: ${err.message}`));
95
+ readStream.pipe(writeStream);
96
+ }
97
+ else {
98
+ let readStream, writeStream;
99
+ try {
100
+ readStream = sftp.createReadStream(remotePath);
101
+ writeStream = fs.createWriteStream(localPath);
102
+ }
103
+ catch (streamErr) {
104
+ finish(`Download failed: ${streamErr.message}`);
105
+ return;
106
+ }
107
+ writeStream.on("close", () => finish(`Download complete: ${user}@${target}:${remotePath} → ${localPath}`));
108
+ writeStream.on("error", (err) => finish(`Download failed: ${err.message}`));
109
+ readStream.on("error", (err) => finish(`Download failed: ${err.message}`));
110
+ readStream.pipe(writeStream);
111
+ }
112
+ });
113
+ }).on("error", (err) => {
114
+ clearTimeout(timeout);
115
+ finish(`SCP connection error: ${err.message}`);
116
+ });
117
+ try {
118
+ conn.connect({
119
+ host: target,
120
+ username: user,
121
+ ...(resolvedKey ? { privateKey: resolvedKey } : {})
122
+ });
123
+ }
124
+ catch (err) {
125
+ clearTimeout(timeout);
126
+ finish(`SCP connect threw: ${err.message}`);
127
+ }
128
+ });
129
+ }
130
+ catch (fatalErr) {
131
+ return { content: [{ type: "text", text: `SCP fatal error: ${fatalErr.message || fatalErr}` }] };
132
+ }
133
+ });
134
+ }
@@ -0,0 +1,83 @@
1
+ import { z } from "zod";
2
+ import { Client as SSHClient } from "ssh2";
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import os from "os";
6
+ function resolvePrivateKey(privateKeyArg) {
7
+ // If not provided, try default keys
8
+ if (!privateKeyArg) {
9
+ const home = os.homedir();
10
+ const defaultKeys = [
11
+ path.join(home, '.ssh', 'id_rsa'),
12
+ path.join(home, '.ssh', 'id_ed25519'),
13
+ ];
14
+ for (const keyPath of defaultKeys) {
15
+ if (fs.existsSync(keyPath)) {
16
+ return fs.readFileSync(keyPath, 'utf8');
17
+ }
18
+ }
19
+ return undefined;
20
+ }
21
+ // If it looks like a path, try to read it
22
+ if (privateKeyArg.startsWith('/') ||
23
+ privateKeyArg.startsWith('~') ||
24
+ privateKeyArg.endsWith('.pem') ||
25
+ privateKeyArg.endsWith('.key')) {
26
+ let keyPath = privateKeyArg;
27
+ if (keyPath.startsWith('~')) {
28
+ keyPath = path.join(os.homedir(), keyPath.slice(1));
29
+ }
30
+ if (fs.existsSync(keyPath)) {
31
+ return fs.readFileSync(keyPath, 'utf8');
32
+ }
33
+ else {
34
+ throw new Error('Private key file not found: ' + keyPath);
35
+ }
36
+ }
37
+ // Otherwise, assume it's the key content
38
+ return privateKeyArg;
39
+ }
40
+ export function registerSsh(server) {
41
+ server.tool("ssh", "Connect to a target via SSH", {
42
+ target: z.string().describe("Target host"),
43
+ user: z.string().describe("Username"),
44
+ command: z.string().describe("Command to run on remote host"),
45
+ privateKey: z.string().optional().describe("Private key for authentication (PEM format, optional, or path to key file)")
46
+ }, async ({ target, user, command, privateKey }) => {
47
+ return new Promise((resolve) => {
48
+ let resolvedKey;
49
+ try {
50
+ resolvedKey = resolvePrivateKey(privateKey);
51
+ }
52
+ catch (err) {
53
+ resolve({ content: [{ type: "text", text: `SSH key error: ${err.message}` }] });
54
+ return;
55
+ }
56
+ const conn = new SSHClient();
57
+ let output = "";
58
+ conn.on("ready", () => {
59
+ conn.exec(command, (err, stream) => {
60
+ if (err) {
61
+ resolve({ content: [{ type: "text", text: `SSH error: ${err.message}` }] });
62
+ conn.end();
63
+ return;
64
+ }
65
+ stream.on("close", () => {
66
+ conn.end();
67
+ resolve({ content: [{ type: "text", text: output }] });
68
+ }).on("data", (data) => {
69
+ output += data.toString();
70
+ }).stderr.on("data", (data) => {
71
+ output += data.toString();
72
+ });
73
+ });
74
+ }).on("error", (err) => {
75
+ resolve({ content: [{ type: "text", text: `SSH connection error: ${err.message}` }] });
76
+ }).connect({
77
+ host: target,
78
+ username: user,
79
+ ...(resolvedKey ? { privateKey: resolvedKey } : {})
80
+ });
81
+ });
82
+ });
83
+ }
@@ -0,0 +1,16 @@
1
+ import { z } from "zod";
2
+ import readLastLines from "read-last-lines";
3
+ export function registerTail(server) {
4
+ server.tool("tail", "Display the end of a file", {
5
+ file: z.string().describe("File path"),
6
+ lines: z.number().default(10).describe("Number of lines")
7
+ }, async ({ file, lines }) => {
8
+ try {
9
+ const out = await readLastLines.read(file, lines);
10
+ return { content: [{ type: "text", text: out }] };
11
+ }
12
+ catch (error) {
13
+ return { content: [{ type: "text", text: `tail failed: ${error instanceof Error ? error.message : error}` }] };
14
+ }
15
+ });
16
+ }
@@ -0,0 +1,45 @@
1
+ import { z } from "zod";
2
+ export function registerTelnet(server) {
3
+ server.tool("telnet", "Test TCP connectivity to a host and port", {
4
+ target: z.string().describe("Host to connect to"),
5
+ port: z.number().describe("Port number")
6
+ }, async ({ target, port }) => {
7
+ return new Promise(async (resolve) => {
8
+ try {
9
+ const net = (await import('net')).default;
10
+ const socket = new net.Socket();
11
+ let connected = false;
12
+ let banner = '';
13
+ socket.setTimeout(2000);
14
+ socket.connect(port, target, () => {
15
+ connected = true;
16
+ });
17
+ socket.on('data', (data) => {
18
+ banner += data.toString();
19
+ // If we get a banner, close immediately
20
+ socket.end();
21
+ });
22
+ socket.on('timeout', () => {
23
+ socket.destroy();
24
+ if (!connected) {
25
+ resolve({ content: [{ type: "text", text: `Telnet failed: Connection timed out` }] });
26
+ }
27
+ else {
28
+ resolve({ content: [{ type: "text", text: `Telnet to ${target}:${port} succeeded.${banner ? '\nBanner: ' + banner.trim() : ''}` }] });
29
+ }
30
+ });
31
+ socket.on('error', (err) => {
32
+ resolve({ content: [{ type: "text", text: `Telnet failed: ${err.message}` }] });
33
+ });
34
+ socket.on('close', (hadError) => {
35
+ if (connected) {
36
+ resolve({ content: [{ type: "text", text: `Telnet to ${target}:${port} succeeded.${banner ? '\nBanner: ' + banner.trim() : ''}` }] });
37
+ }
38
+ });
39
+ }
40
+ catch (error) {
41
+ resolve({ content: [{ type: "text", text: `Telnet failed: ${error instanceof Error ? error.message : error}` }] });
42
+ }
43
+ });
44
+ });
45
+ }
@@ -0,0 +1,14 @@
1
+ import psList from "ps-list";
2
+ export function registerTop(server) {
3
+ server.tool("top", "Display system processes (snapshot)", {}, async () => {
4
+ try {
5
+ const processes = await psList();
6
+ const sorted = processes.sort((a, b) => (b.cpu || 0) - (a.cpu || 0)).slice(0, 10);
7
+ const output = sorted.map(p => `${p.pid}\t${p.name}\tCPU: ${p.cpu || 0}%\tMEM: ${p.memory || 0}`).join("\n");
8
+ return { content: [{ type: "text", text: output }] };
9
+ }
10
+ catch (error) {
11
+ return { content: [{ type: "text", text: `top failed: ${error instanceof Error ? error.message : error}` }] };
12
+ }
13
+ });
14
+ }
@@ -0,0 +1,52 @@
1
+ import { z } from "zod";
2
+ export function registerUrlParse(server) {
3
+ server.tool("url-parse", "Parse URL into components", {
4
+ url: z.string().describe("URL to parse"),
5
+ }, async ({ url }) => {
6
+ try {
7
+ const urlObj = new URL(url);
8
+ // Parse query parameters
9
+ const params = {};
10
+ urlObj.searchParams.forEach((value, key) => {
11
+ params[key] = value;
12
+ });
13
+ return {
14
+ content: [
15
+ {
16
+ type: "text",
17
+ text: `URL Components:
18
+
19
+ Original URL: ${url}
20
+
21
+ Protocol: ${urlObj.protocol}
22
+ Host: ${urlObj.host}
23
+ Hostname: ${urlObj.hostname}
24
+ Port: ${urlObj.port || 'default'}
25
+ Pathname: ${urlObj.pathname}
26
+ Search: ${urlObj.search}
27
+ Hash: ${urlObj.hash}
28
+ Origin: ${urlObj.origin}
29
+
30
+ Query Parameters:
31
+ ${Object.keys(params).length > 0
32
+ ? Object.entries(params).map(([key, value]) => ` ${key}: ${value}`).join('\n')
33
+ : ' (none)'}
34
+
35
+ Path Segments:
36
+ ${urlObj.pathname.split('/').filter(segment => segment).map((segment, i) => ` ${i + 1}. ${segment}`).join('\n') || ' (none)'}`,
37
+ },
38
+ ],
39
+ };
40
+ }
41
+ catch (error) {
42
+ return {
43
+ content: [
44
+ {
45
+ type: "text",
46
+ text: `Error parsing URL: ${error instanceof Error ? error.message : 'Invalid URL format'}`,
47
+ },
48
+ ],
49
+ };
50
+ }
51
+ });
52
+ }
@@ -0,0 +1,73 @@
1
+ import { z } from "zod";
2
+ export function registerAngleConverter(server) {
3
+ server.tool("angle-converter", "Convert between different angle units", {
4
+ value: z.number().describe("Angle value to convert"),
5
+ fromUnit: z.enum([
6
+ "degree", "radian", "gradian", "turn", "arcminute", "arcsecond"
7
+ ]).describe("Source angle unit"),
8
+ toUnit: z.enum([
9
+ "degree", "radian", "gradian", "turn", "arcminute", "arcsecond"
10
+ ]).describe("Target angle unit")
11
+ }, async ({ value, fromUnit, toUnit }) => {
12
+ try {
13
+ // Conversion factors to degrees
14
+ const toDegrees = {
15
+ "degree": 1,
16
+ "radian": 180 / Math.PI,
17
+ "gradian": 0.9, // 1 gradian = 0.9 degrees
18
+ "turn": 360, // 1 turn = 360 degrees
19
+ "arcminute": 1 / 60, // 1 arcminute = 1/60 degree
20
+ "arcsecond": 1 / 3600 // 1 arcsecond = 1/3600 degree
21
+ };
22
+ // Convert to degrees first
23
+ const degrees = value * toDegrees[fromUnit];
24
+ // Convert from degrees to target unit
25
+ const result = degrees / toDegrees[toUnit];
26
+ const units = {
27
+ "degree": "°",
28
+ "radian": "rad",
29
+ "gradian": "gon",
30
+ "turn": "tr",
31
+ "arcminute": "'",
32
+ "arcsecond": "\""
33
+ };
34
+ // Additional conversions for context
35
+ const inDegrees = degrees;
36
+ const inRadians = degrees * Math.PI / 180;
37
+ const inGradians = degrees / 0.9;
38
+ return {
39
+ content: [{
40
+ type: "text",
41
+ text: `Angle Conversion Results:
42
+
43
+ ${value} ${units[fromUnit]} = ${result} ${units[toUnit]}
44
+
45
+ All Conversions:
46
+ • Degrees: ${inDegrees.toFixed(6)}°
47
+ • Radians: ${inRadians.toFixed(6)} rad
48
+ • Gradians: ${inGradians.toFixed(6)} gon
49
+ • Turns: ${(inDegrees / 360).toFixed(6)} tr
50
+ • Arcminutes: ${(inDegrees * 60).toFixed(2)}'
51
+ • Arcseconds: ${(inDegrees * 3600).toFixed(2)}"
52
+
53
+ Trigonometric Values:
54
+ • sin: ${Math.sin(inRadians).toFixed(6)}
55
+ • cos: ${Math.cos(inRadians).toFixed(6)}
56
+ • tan: ${Math.tan(inRadians).toFixed(6)}
57
+
58
+ Reference:
59
+ • π rad = 180° = 200 gon = 0.5 tr
60
+ • 1° = 60' = 3600"`
61
+ }]
62
+ };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ content: [{
67
+ type: "text",
68
+ text: `Error converting angle: ${error instanceof Error ? error.message : 'Unknown error'}`
69
+ }]
70
+ };
71
+ }
72
+ });
73
+ }
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ export function registerEnergyConverter(server) {
3
+ server.tool("energy-converter", "Convert between different energy units", {
4
+ value: z.number().describe("Energy value to convert"),
5
+ fromUnit: z.enum([
6
+ "joule", "kilojoule", "calorie", "kilocalorie", "btu",
7
+ "watt-hour", "kilowatt-hour", "electronvolt", "foot-pound"
8
+ ]).describe("Source energy unit"),
9
+ toUnit: z.enum([
10
+ "joule", "kilojoule", "calorie", "kilocalorie", "btu",
11
+ "watt-hour", "kilowatt-hour", "electronvolt", "foot-pound"
12
+ ]).describe("Target energy unit")
13
+ }, async ({ value, fromUnit, toUnit }) => {
14
+ try {
15
+ // Conversion factors to joules
16
+ const toJoules = {
17
+ "joule": 1,
18
+ "kilojoule": 1000,
19
+ "calorie": 4.184,
20
+ "kilocalorie": 4184,
21
+ "btu": 1055.06,
22
+ "watt-hour": 3600,
23
+ "kilowatt-hour": 3600000,
24
+ "electronvolt": 1.602176634e-19,
25
+ "foot-pound": 1.355818
26
+ };
27
+ // Convert to joules first
28
+ const joules = value * toJoules[fromUnit];
29
+ // Convert from joules to target unit
30
+ const result = joules / toJoules[toUnit];
31
+ const units = {
32
+ "joule": "J",
33
+ "kilojoule": "kJ",
34
+ "calorie": "cal",
35
+ "kilocalorie": "kcal",
36
+ "btu": "BTU",
37
+ "watt-hour": "Wh",
38
+ "kilowatt-hour": "kWh",
39
+ "electronvolt": "eV",
40
+ "foot-pound": "ft·lb"
41
+ };
42
+ return {
43
+ content: [{
44
+ type: "text",
45
+ text: `Energy Conversion Results:
46
+
47
+ ${value} ${units[fromUnit]} = ${result.toExponential(6)} ${units[toUnit]}
48
+
49
+ Formatted Results:
50
+ • Scientific: ${result.toExponential(6)} ${units[toUnit]}
51
+ • Fixed: ${result.toFixed(6)} ${units[toUnit]}
52
+ • Compact: ${result.toPrecision(6)} ${units[toUnit]}
53
+
54
+ Intermediate (Joules): ${joules.toExponential(6)} J
55
+
56
+ Common Energy Equivalents:
57
+ • 1 kWh = 3.6 MJ = 860 kcal
58
+ • 1 BTU = 1055 J = 252 cal
59
+ • 1 eV = 1.602 × 10⁻¹⁹ J`
60
+ }]
61
+ };
62
+ }
63
+ catch (error) {
64
+ return {
65
+ content: [{
66
+ type: "text",
67
+ text: `Error converting energy: ${error instanceof Error ? error.message : 'Unknown error'}`
68
+ }]
69
+ };
70
+ }
71
+ });
72
+ }
@@ -0,0 +1,71 @@
1
+ import { z } from "zod";
2
+ export function registerPowerConverter(server) {
3
+ server.tool("power-converter", "Convert between different power units", {
4
+ value: z.number().describe("Power value to convert"),
5
+ fromUnit: z.enum([
6
+ "watt", "kilowatt", "megawatt", "horsepower", "metric-horsepower",
7
+ "btu-per-hour", "calorie-per-second", "foot-pound-per-second"
8
+ ]).describe("Source power unit"),
9
+ toUnit: z.enum([
10
+ "watt", "kilowatt", "megawatt", "horsepower", "metric-horsepower",
11
+ "btu-per-hour", "calorie-per-second", "foot-pound-per-second"
12
+ ]).describe("Target power unit")
13
+ }, async ({ value, fromUnit, toUnit }) => {
14
+ try {
15
+ // Conversion factors to watts
16
+ const toWatts = {
17
+ "watt": 1,
18
+ "kilowatt": 1000,
19
+ "megawatt": 1000000,
20
+ "horsepower": 745.7, // Mechanical horsepower
21
+ "metric-horsepower": 735.5,
22
+ "btu-per-hour": 0.293071,
23
+ "calorie-per-second": 4.184,
24
+ "foot-pound-per-second": 1.355818
25
+ };
26
+ // Convert to watts first
27
+ const watts = value * toWatts[fromUnit];
28
+ // Convert from watts to target unit
29
+ const result = watts / toWatts[toUnit];
30
+ const units = {
31
+ "watt": "W",
32
+ "kilowatt": "kW",
33
+ "megawatt": "MW",
34
+ "horsepower": "hp",
35
+ "metric-horsepower": "PS",
36
+ "btu-per-hour": "BTU/h",
37
+ "calorie-per-second": "cal/s",
38
+ "foot-pound-per-second": "ft·lb/s"
39
+ };
40
+ return {
41
+ content: [{
42
+ type: "text",
43
+ text: `Power Conversion Results:
44
+
45
+ ${value} ${units[fromUnit]} = ${result.toFixed(6)} ${units[toUnit]}
46
+
47
+ Common Conversions:
48
+ • Watts: ${watts.toFixed(3)} W
49
+ • Kilowatts: ${(watts / 1000).toFixed(6)} kW
50
+ • Horsepower: ${(watts / 745.7).toFixed(6)} hp
51
+ • Metric HP: ${(watts / 735.5).toFixed(6)} PS
52
+ • BTU/hour: ${(watts / 0.293071).toFixed(3)} BTU/h
53
+
54
+ Energy Relationships:
55
+ • Power × Time = Energy
56
+ • 1 kW for 1 hour = 1 kWh = 3.6 MJ
57
+ • 1 hp ≈ 746 W (mechanical)
58
+ • 1 PS ≈ 736 W (metric)`
59
+ }]
60
+ };
61
+ }
62
+ catch (error) {
63
+ return {
64
+ content: [{
65
+ type: "text",
66
+ text: `Error converting power: ${error instanceof Error ? error.message : 'Unknown error'}`
67
+ }]
68
+ };
69
+ }
70
+ });
71
+ }
@@ -0,0 +1,112 @@
1
+ import { z } from "zod";
2
+ export function registerAsciiArtText(server) {
3
+ server.tool("ascii-art-text", "Generate ASCII art text", {
4
+ text: z.string().describe("Text to convert to ASCII art, or use 'LIST_FONTS' to get all available font names"),
5
+ font: z.string().describe("ASCII art font style. Supports all 295+ figlet fonts. Use 'standard' if unsure.").optional(),
6
+ }, async ({ text, font = "standard" }) => {
7
+ try {
8
+ // Generate ASCII art using figlet
9
+ const figlet = await import('figlet');
10
+ // Get list of available fonts
11
+ const availableFonts = figlet.default.fontsSync();
12
+ // Check if user wants to list all fonts
13
+ if (text.toUpperCase() === 'LIST_FONTS') {
14
+ const sortedFonts = availableFonts.sort();
15
+ const popularFonts = [
16
+ "Standard", "Big", "Small", "Slant", "3-D", "Banner", "Block", "Shadow",
17
+ "Larry 3D", "Doom", "Star Wars", "Gothic", "Graffiti", "Bubble", "Digital"
18
+ ];
19
+ // Filter popular fonts that are actually available
20
+ const availablePopularFonts = popularFonts.filter(f => sortedFonts.some(availableFont => availableFont === f));
21
+ return {
22
+ content: [
23
+ {
24
+ type: "text",
25
+ text: `Available ASCII Art Fonts (${sortedFonts.length} total):
26
+
27
+ 🌟 POPULAR FONTS:
28
+ ${availablePopularFonts.join(', ')}
29
+
30
+ 📝 ALL AVAILABLE FONTS:
31
+ ${sortedFonts.join(', ')}
32
+
33
+ 💡 Usage: Use any font name above as the 'font' parameter.
34
+ Examples: 'Standard', '3-D', 'Larry 3D', 'Banner', 'Block', etc.`,
35
+ },
36
+ ],
37
+ };
38
+ }
39
+ // Find the exact font match (case insensitive and flexible matching)
40
+ let targetFont = "Standard"; // Default fallback
41
+ const inputFont = font.toLowerCase();
42
+ // Direct match
43
+ const exactMatch = availableFonts.find(f => f.toLowerCase() === inputFont);
44
+ if (exactMatch) {
45
+ targetFont = exactMatch;
46
+ }
47
+ else {
48
+ // Fuzzy match - look for fonts that contain the input as substring
49
+ const partialMatch = availableFonts.find(f => f.toLowerCase().includes(inputFont) ||
50
+ inputFont.includes(f.toLowerCase()));
51
+ if (partialMatch) {
52
+ targetFont = partialMatch;
53
+ }
54
+ }
55
+ // Generate ASCII art
56
+ const asciiArt = figlet.default.textSync(text, {
57
+ font: targetFont,
58
+ horizontalLayout: 'default',
59
+ verticalLayout: 'default'
60
+ });
61
+ const fontUsed = targetFont === font ? font : `${font} → ${targetFont}`;
62
+ return {
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text: `ASCII Art (${fontUsed}):\n\n${asciiArt}`,
67
+ },
68
+ ],
69
+ };
70
+ }
71
+ catch (error) {
72
+ // Get available fonts for error message
73
+ try {
74
+ const figlet = await import('figlet');
75
+ const availableFonts = figlet.default.fontsSync();
76
+ const popularFonts = [
77
+ "Standard", "Big", "Small", "Slant", "3-D", "Banner", "Block", "Shadow",
78
+ "Larry 3D", "Doom", "Star Wars", "Gothic", "Graffiti", "Bubble", "Digital"
79
+ ];
80
+ return {
81
+ content: [
82
+ {
83
+ type: "text",
84
+ text: `Error generating ASCII art: ${error instanceof Error ? error.message : 'Unknown error'}
85
+
86
+ Font '${font}' not found or invalid.
87
+
88
+ Popular fonts to try: ${popularFonts.join(', ')}
89
+
90
+ Total available fonts: ${availableFonts.length}
91
+ Some examples: ${availableFonts.slice(0, 10).join(', ')}...
92
+
93
+ Note: ASCII art generation works best with short text (1-10 characters).`,
94
+ },
95
+ ],
96
+ };
97
+ }
98
+ catch {
99
+ return {
100
+ content: [
101
+ {
102
+ type: "text",
103
+ text: `Error generating ASCII art: ${error instanceof Error ? error.message : 'Unknown error'}
104
+
105
+ Note: ASCII art generation works best with short text (1-10 characters).`,
106
+ },
107
+ ],
108
+ };
109
+ }
110
+ }
111
+ });
112
+ }