it-tools-mcp 3.0.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.
- package/LICENSE +21 -0
- package/README.dockerhub.md +98 -0
- package/README.md +263 -0
- package/build/index.js +75 -0
- package/build/security.js +201 -0
- package/build/tools/color.js +67 -0
- package/build/tools/crypto.js +445 -0
- package/build/tools/dataFormat.js +517 -0
- package/build/tools/development.js +267 -0
- package/build/tools/encoding.js +240 -0
- package/build/tools/idGenerators.js +176 -0
- package/build/tools/math.js +306 -0
- package/build/tools/network.js +578 -0
- package/build/tools/text.js +678 -0
- package/build/tools/utility.js +407 -0
- package/package.json +94 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CronExpressionParser } from 'cron-parser';
|
|
3
|
+
export function registerDevelopmentTools(server) {
|
|
4
|
+
// Regex tester
|
|
5
|
+
server.tool("regex-tester", "Test regular expressions against text", {
|
|
6
|
+
pattern: z.string().describe("Regular expression pattern"),
|
|
7
|
+
text: z.string().describe("Text to test against the regex"),
|
|
8
|
+
flags: z.string().optional().describe("Regex flags (g, i, m, s, u, y)"),
|
|
9
|
+
}, async ({ pattern, text, flags }) => {
|
|
10
|
+
try {
|
|
11
|
+
const regex = new RegExp(pattern, flags);
|
|
12
|
+
const matches = text.match(regex);
|
|
13
|
+
const globalMatches = flags?.includes('g') ? [...text.matchAll(new RegExp(pattern, flags))] : null;
|
|
14
|
+
const isMatch = regex.test(text);
|
|
15
|
+
let result = `Regex Test Results:
|
|
16
|
+
|
|
17
|
+
Pattern: ${pattern}
|
|
18
|
+
Flags: ${flags || 'none'}
|
|
19
|
+
Text: ${text}
|
|
20
|
+
|
|
21
|
+
Match: ${isMatch ? '✅ Yes' : '❌ No'}`;
|
|
22
|
+
if (matches) {
|
|
23
|
+
result += `\n\nFirst Match: ${matches[0]}`;
|
|
24
|
+
if (matches.length > 1) {
|
|
25
|
+
result += `\nCapture Groups: ${matches.slice(1).join(', ')}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (globalMatches && globalMatches.length > 0) {
|
|
29
|
+
result += `\n\nAll Matches (${globalMatches.length}):`;
|
|
30
|
+
globalMatches.forEach((match, index) => {
|
|
31
|
+
result += `\n${index + 1}. "${match[0]}" at position ${match.index}`;
|
|
32
|
+
if (match.length > 1) {
|
|
33
|
+
result += ` (groups: ${match.slice(1).join(', ')})`;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
result += `\n\nCommon Regex Patterns:
|
|
38
|
+
• Email: ^[\\w\\.-]+@[\\w\\.-]+\\.[a-zA-Z]{2,}$
|
|
39
|
+
• Phone: ^\\+?[1-9]\\d{1,14}$
|
|
40
|
+
• URL: ^https?:\\/\\/.+
|
|
41
|
+
• IPv4: ^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$
|
|
42
|
+
• Date (YYYY-MM-DD): ^\\d{4}-\\d{2}-\\d{2}$`;
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
text: result,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: `Error testing regex: ${error instanceof Error ? error.message : 'Unknown error'}
|
|
58
|
+
|
|
59
|
+
Common regex flags:
|
|
60
|
+
• g - Global (find all matches)
|
|
61
|
+
• i - Case insensitive
|
|
62
|
+
• m - Multiline
|
|
63
|
+
• s - Dot matches newline
|
|
64
|
+
• u - Unicode
|
|
65
|
+
• y - Sticky`,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// Crontab generator
|
|
72
|
+
server.tool("crontab-generate", "Generate crontab expressions", {
|
|
73
|
+
minute: z.string().describe("Minute (0-59, *, */n, n-m)").optional(),
|
|
74
|
+
hour: z.string().describe("Hour (0-23, *, */n, n-m)").optional(),
|
|
75
|
+
dayOfMonth: z.string().describe("Day of month (1-31, *, */n, n-m)").optional(),
|
|
76
|
+
month: z.string().describe("Month (1-12, *, */n, n-m)").optional(),
|
|
77
|
+
dayOfWeek: z.string().describe("Day of week (0-7, *, */n, n-m)").optional(),
|
|
78
|
+
}, async ({ minute = "*", hour = "*", dayOfMonth = "*", month = "*", dayOfWeek = "*" }) => {
|
|
79
|
+
try {
|
|
80
|
+
const cronExpression = `${minute} ${hour} ${dayOfMonth} ${month} ${dayOfWeek}`;
|
|
81
|
+
// Generate human readable description
|
|
82
|
+
let description = "Runs ";
|
|
83
|
+
// Minute description
|
|
84
|
+
if (minute === "*") {
|
|
85
|
+
description += "every minute";
|
|
86
|
+
}
|
|
87
|
+
else if (minute.startsWith("*/")) {
|
|
88
|
+
description += `every ${minute.slice(2)} minutes`;
|
|
89
|
+
}
|
|
90
|
+
else if (minute.includes("-")) {
|
|
91
|
+
description += `at minutes ${minute}`;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
description += `at minute ${minute}`;
|
|
95
|
+
}
|
|
96
|
+
// Hour description
|
|
97
|
+
if (hour !== "*") {
|
|
98
|
+
if (hour.startsWith("*/")) {
|
|
99
|
+
description += ` of every ${hour.slice(2)} hours`;
|
|
100
|
+
}
|
|
101
|
+
else if (hour.includes("-")) {
|
|
102
|
+
description += ` during hours ${hour}`;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
description += ` at ${hour}:00`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Day of month description
|
|
109
|
+
if (dayOfMonth !== "*") {
|
|
110
|
+
if (dayOfMonth.startsWith("*/")) {
|
|
111
|
+
description += ` every ${dayOfMonth.slice(2)} days`;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
description += ` on day ${dayOfMonth} of the month`;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Month description
|
|
118
|
+
if (month !== "*") {
|
|
119
|
+
const monthNames = ["", "January", "February", "March", "April", "May", "June",
|
|
120
|
+
"July", "August", "September", "October", "November", "December"];
|
|
121
|
+
if (month.includes(",")) {
|
|
122
|
+
const months = month.split(",").map(m => monthNames[parseInt(m)] || m).join(", ");
|
|
123
|
+
description += ` in ${months}`;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
description += ` in ${monthNames[parseInt(month)] || month}`;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Day of week description
|
|
130
|
+
if (dayOfWeek !== "*") {
|
|
131
|
+
const dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
132
|
+
if (dayOfWeek.includes(",")) {
|
|
133
|
+
const days = dayOfWeek.split(",").map(d => dayNames[parseInt(d)] || d).join(", ");
|
|
134
|
+
description += ` on ${days}`;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
description += ` on ${dayNames[parseInt(dayOfWeek)] || dayOfWeek}`;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Generate next few run times using proper cron parser
|
|
141
|
+
const nextRuns = [];
|
|
142
|
+
try {
|
|
143
|
+
const interval = CronExpressionParser.parse(cronExpression);
|
|
144
|
+
for (let i = 0; i < 5; i++) {
|
|
145
|
+
const nextRun = interval.next();
|
|
146
|
+
nextRuns.push(nextRun.toDate().toISOString().replace('T', ' ').slice(0, 19));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (cronError) {
|
|
150
|
+
// Fall back to basic time intervals if cron parsing fails
|
|
151
|
+
const now = new Date();
|
|
152
|
+
for (let i = 0; i < 5; i++) {
|
|
153
|
+
const nextRun = new Date(now.getTime() + (i + 1) * 60 * 1000);
|
|
154
|
+
nextRuns.push(nextRun.toISOString().replace('T', ' ').slice(0, 19));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: "text",
|
|
161
|
+
text: `Crontab Expression Generated:
|
|
162
|
+
|
|
163
|
+
Expression: ${cronExpression}
|
|
164
|
+
Description: ${description}
|
|
165
|
+
|
|
166
|
+
Fields:
|
|
167
|
+
┌─────────── minute (0-59)
|
|
168
|
+
│ ┌───────── hour (0-23)
|
|
169
|
+
│ │ ┌─────── day of month (1-31)
|
|
170
|
+
│ │ │ ┌───── month (1-12)
|
|
171
|
+
│ │ │ │ ┌─── day of week (0-6, Sunday = 0)
|
|
172
|
+
│ │ │ │ │
|
|
173
|
+
${minute.padEnd(2)} ${hour.padEnd(2)} ${dayOfMonth.padEnd(2)} ${month.padEnd(2)} ${dayOfWeek}
|
|
174
|
+
|
|
175
|
+
Common Examples:
|
|
176
|
+
• 0 9 * * * - Every day at 9:00 AM
|
|
177
|
+
• 0 9 * * 1-5 - Weekdays at 9:00 AM
|
|
178
|
+
• 0 */6 * * * - Every 6 hours
|
|
179
|
+
• 0 9 1 * * - First day of every month at 9:00 AM
|
|
180
|
+
• 30 23 * * 0 - Every Sunday at 11:30 PM
|
|
181
|
+
|
|
182
|
+
Special Characters:
|
|
183
|
+
• * - Any value
|
|
184
|
+
• , - List separator (1,3,5)
|
|
185
|
+
• - - Range (1-5)
|
|
186
|
+
• / - Step values (*/5)
|
|
187
|
+
|
|
188
|
+
Next estimated runs (simplified):
|
|
189
|
+
${nextRuns.map((run, i) => `${i + 1}. ${run}`).join('\n')}
|
|
190
|
+
|
|
191
|
+
Note: Use 'crontab -e' to edit your crontab file.`,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return {
|
|
198
|
+
content: [
|
|
199
|
+
{
|
|
200
|
+
type: "text",
|
|
201
|
+
text: `Error generating crontab: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
// List converter
|
|
208
|
+
server.tool("list-converter", "Convert between different list formats (comma-separated, line-separated, etc.)", {
|
|
209
|
+
list: z.string().describe("Input list to convert"),
|
|
210
|
+
inputFormat: z.enum(["comma", "semicolon", "newline", "space", "pipe"]).describe("Input format"),
|
|
211
|
+
outputFormat: z.enum(["comma", "semicolon", "newline", "space", "pipe", "json", "quoted"]).describe("Output format"),
|
|
212
|
+
trim: z.boolean().describe("Trim whitespace from items").optional(),
|
|
213
|
+
}, async ({ list, inputFormat, outputFormat, trim = true }) => {
|
|
214
|
+
try {
|
|
215
|
+
const separators = {
|
|
216
|
+
comma: ',',
|
|
217
|
+
semicolon: ';',
|
|
218
|
+
newline: '\n',
|
|
219
|
+
space: ' ',
|
|
220
|
+
pipe: '|'
|
|
221
|
+
};
|
|
222
|
+
// Parse input list
|
|
223
|
+
const inputSeparator = separators[inputFormat];
|
|
224
|
+
let items = list.split(inputSeparator);
|
|
225
|
+
if (trim) {
|
|
226
|
+
items = items.map(item => item.trim()).filter(item => item.length > 0);
|
|
227
|
+
}
|
|
228
|
+
// Convert to output format
|
|
229
|
+
let result = '';
|
|
230
|
+
switch (outputFormat) {
|
|
231
|
+
case 'json':
|
|
232
|
+
result = JSON.stringify(items, null, 2);
|
|
233
|
+
break;
|
|
234
|
+
case 'quoted':
|
|
235
|
+
result = items.map(item => `"${item.replace(/"/g, '\\"')}"`).join(', ');
|
|
236
|
+
break;
|
|
237
|
+
default:
|
|
238
|
+
const outputSeparator = separators[outputFormat];
|
|
239
|
+
result = items.join(outputSeparator);
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: "text",
|
|
246
|
+
text: `Converted list:
|
|
247
|
+
${result}
|
|
248
|
+
|
|
249
|
+
Items count: ${items.length}
|
|
250
|
+
Input format: ${inputFormat}
|
|
251
|
+
Output format: ${outputFormat}`,
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
return {
|
|
258
|
+
content: [
|
|
259
|
+
{
|
|
260
|
+
type: "text",
|
|
261
|
+
text: `Error converting list: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerEncodingTools(server) {
|
|
3
|
+
// Base64 encoding tool
|
|
4
|
+
server.tool("base64-encode", "Encode text to Base64", {
|
|
5
|
+
text: z.string().describe("Text to encode to Base64"),
|
|
6
|
+
}, async ({ text }) => {
|
|
7
|
+
const encoded = Buffer.from(text, 'utf-8').toString('base64');
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
text: `Base64 encoded: ${encoded}`,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
// Base64 decoding tool
|
|
18
|
+
server.tool("base64-decode", "Decode Base64 text", {
|
|
19
|
+
text: z.string().describe("Base64 text to decode"),
|
|
20
|
+
}, async ({ text }) => {
|
|
21
|
+
try {
|
|
22
|
+
const decoded = Buffer.from(text, 'base64').toString('utf-8');
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `Base64 decoded: ${decoded}`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return {
|
|
34
|
+
content: [
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: `Error decoding Base64: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
// URL encoding tool
|
|
44
|
+
server.tool("url-encode", "URL encode text", {
|
|
45
|
+
text: z.string().describe("Text to URL encode"),
|
|
46
|
+
}, async ({ text }) => {
|
|
47
|
+
const encoded = encodeURIComponent(text);
|
|
48
|
+
return {
|
|
49
|
+
content: [
|
|
50
|
+
{
|
|
51
|
+
type: "text",
|
|
52
|
+
text: `URL encoded: ${encoded}`,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
// URL decoding tool
|
|
58
|
+
server.tool("url-decode", "URL decode text", {
|
|
59
|
+
text: z.string().describe("URL encoded text to decode"),
|
|
60
|
+
}, async ({ text }) => {
|
|
61
|
+
try {
|
|
62
|
+
const decoded = decodeURIComponent(text);
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: "text",
|
|
67
|
+
text: `URL decoded: ${decoded}`,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: "text",
|
|
77
|
+
text: `Error decoding URL: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
// HTML encode tool
|
|
84
|
+
server.tool("html-encode", "Encode HTML entities", {
|
|
85
|
+
text: z.string().describe("Text to HTML encode"),
|
|
86
|
+
}, async ({ text }) => {
|
|
87
|
+
const encoded = text
|
|
88
|
+
.replace(/&/g, '&')
|
|
89
|
+
.replace(/</g, '<')
|
|
90
|
+
.replace(/>/g, '>')
|
|
91
|
+
.replace(/"/g, '"')
|
|
92
|
+
.replace(/'/g, ''');
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: "text",
|
|
97
|
+
text: `HTML encoded: ${encoded}`,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
// HTML decode tool
|
|
103
|
+
server.tool("html-decode", "Decode HTML entities", {
|
|
104
|
+
text: z.string().describe("HTML encoded text to decode"),
|
|
105
|
+
}, async ({ text }) => {
|
|
106
|
+
const decoded = text
|
|
107
|
+
.replace(/&/g, '&')
|
|
108
|
+
.replace(/</g, '<')
|
|
109
|
+
.replace(/>/g, '>')
|
|
110
|
+
.replace(/"/g, '"')
|
|
111
|
+
.replace(/'/g, "'");
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: "text",
|
|
116
|
+
text: `HTML decoded: ${decoded}`,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
// Extended HTML entities tool
|
|
122
|
+
server.tool("html-entities-extended", "Extended HTML entity encoding/decoding", {
|
|
123
|
+
text: z.string().describe("Text to encode or decode"),
|
|
124
|
+
operation: z.enum(["encode", "decode"]).describe("Operation to perform"),
|
|
125
|
+
}, async ({ text, operation }) => {
|
|
126
|
+
try {
|
|
127
|
+
if (operation === "encode") {
|
|
128
|
+
const encoded = text
|
|
129
|
+
.replace(/&/g, '&')
|
|
130
|
+
.replace(/</g, '<')
|
|
131
|
+
.replace(/>/g, '>')
|
|
132
|
+
.replace(/"/g, '"')
|
|
133
|
+
.replace(/'/g, ''')
|
|
134
|
+
.replace(/©/g, '©')
|
|
135
|
+
.replace(/®/g, '®')
|
|
136
|
+
.replace(/™/g, '™')
|
|
137
|
+
.replace(/€/g, '€')
|
|
138
|
+
.replace(/£/g, '£')
|
|
139
|
+
.replace(/¥/g, '¥')
|
|
140
|
+
.replace(/§/g, '§')
|
|
141
|
+
.replace(/¶/g, '¶')
|
|
142
|
+
.replace(/†/g, '†')
|
|
143
|
+
.replace(/‡/g, '‡');
|
|
144
|
+
return {
|
|
145
|
+
content: [
|
|
146
|
+
{
|
|
147
|
+
type: "text",
|
|
148
|
+
text: `HTML entities encoded: ${encoded}`,
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const decoded = text
|
|
155
|
+
.replace(/&/g, '&')
|
|
156
|
+
.replace(/</g, '<')
|
|
157
|
+
.replace(/>/g, '>')
|
|
158
|
+
.replace(/"/g, '"')
|
|
159
|
+
.replace(/'/g, "'")
|
|
160
|
+
.replace(/©/g, '©')
|
|
161
|
+
.replace(/®/g, '®')
|
|
162
|
+
.replace(/™/g, '™')
|
|
163
|
+
.replace(/€/g, '€')
|
|
164
|
+
.replace(/£/g, '£')
|
|
165
|
+
.replace(/¥/g, '¥')
|
|
166
|
+
.replace(/§/g, '§')
|
|
167
|
+
.replace(/¶/g, '¶')
|
|
168
|
+
.replace(/†/g, '†')
|
|
169
|
+
.replace(/‡/g, '‡');
|
|
170
|
+
return {
|
|
171
|
+
content: [
|
|
172
|
+
{
|
|
173
|
+
type: "text",
|
|
174
|
+
text: `HTML entities decoded: ${decoded}`,
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
return {
|
|
182
|
+
content: [
|
|
183
|
+
{
|
|
184
|
+
type: "text",
|
|
185
|
+
text: `Error processing HTML entities: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
// Text to binary converter
|
|
192
|
+
server.tool("text-to-binary", "Convert text to binary and vice versa", {
|
|
193
|
+
input: z.string().describe("Text to convert to binary, or binary to convert to text"),
|
|
194
|
+
operation: z.enum(["encode", "decode"]).describe("Operation: encode text to binary or decode binary to text"),
|
|
195
|
+
}, async ({ input, operation }) => {
|
|
196
|
+
try {
|
|
197
|
+
if (operation === "encode") {
|
|
198
|
+
const binary = input
|
|
199
|
+
.split('')
|
|
200
|
+
.map(char => char.charCodeAt(0).toString(2).padStart(8, '0'))
|
|
201
|
+
.join(' ');
|
|
202
|
+
return {
|
|
203
|
+
content: [
|
|
204
|
+
{
|
|
205
|
+
type: "text",
|
|
206
|
+
text: `Text: ${input}
|
|
207
|
+
Binary: ${binary}`,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
// Decode binary to text
|
|
214
|
+
const binaryGroups = input.replace(/\s+/g, ' ').trim().split(' ');
|
|
215
|
+
const text = binaryGroups
|
|
216
|
+
.map(binary => String.fromCharCode(parseInt(binary, 2)))
|
|
217
|
+
.join('');
|
|
218
|
+
return {
|
|
219
|
+
content: [
|
|
220
|
+
{
|
|
221
|
+
type: "text",
|
|
222
|
+
text: `Binary: ${input}
|
|
223
|
+
Text: ${text}`,
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
return {
|
|
231
|
+
content: [
|
|
232
|
+
{
|
|
233
|
+
type: "text",
|
|
234
|
+
text: `Error converting text/binary: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import QRCode from "qrcode";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
export function registerIdGeneratorTools(server) {
|
|
5
|
+
// UUID generation tool
|
|
6
|
+
server.tool("uuid-generate", "Generate a random UUID v4", {}, async () => {
|
|
7
|
+
const uuid = randomUUID();
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
text: `Generated UUID: ${uuid}`,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
// ULID generator
|
|
18
|
+
server.tool("ulid-generate", "Generate Universally Unique Lexicographically Sortable Identifier", {}, async () => {
|
|
19
|
+
try {
|
|
20
|
+
// Simplified ULID implementation
|
|
21
|
+
const timestamp = Date.now();
|
|
22
|
+
const randomPart = Math.random().toString(36).substring(2, 18);
|
|
23
|
+
const ulid = timestamp.toString(36).toUpperCase() + randomPart.toUpperCase();
|
|
24
|
+
return {
|
|
25
|
+
content: [
|
|
26
|
+
{
|
|
27
|
+
type: "text",
|
|
28
|
+
text: `Generated ULID: ${ulid}
|
|
29
|
+
|
|
30
|
+
Timestamp: ${timestamp}
|
|
31
|
+
Generated at: ${new Date(timestamp).toISOString()}
|
|
32
|
+
|
|
33
|
+
Note: This is a simplified ULID implementation.
|
|
34
|
+
For production use, please use a proper ULID library.`,
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `Error generating ULID: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// QR code generator (Real implementation using qrcode library)
|
|
51
|
+
server.tool("qr-generate", "Generate QR code for any text including URLs, WiFi networks, contact info, etc.", {
|
|
52
|
+
text: z.string().describe("Text to encode in QR code (URLs, WiFi: WIFI:T:WPA;S:network;P:password;;, contact info, etc.)"),
|
|
53
|
+
size: z.number().describe("Size multiplier (1-3)").optional(),
|
|
54
|
+
}, async ({ text, size = 1 }) => {
|
|
55
|
+
try {
|
|
56
|
+
if (size < 1 || size > 3) {
|
|
57
|
+
return {
|
|
58
|
+
content: [
|
|
59
|
+
{
|
|
60
|
+
type: "text",
|
|
61
|
+
text: "Size must be between 1 and 3.",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Generate QR code as base64 data URL
|
|
67
|
+
console.log(`[DEBUG] Generating QR code for: "${text}" with size: ${size}`);
|
|
68
|
+
const dataUrl = await QRCode.toDataURL(text, {
|
|
69
|
+
type: 'image/png',
|
|
70
|
+
errorCorrectionLevel: 'M',
|
|
71
|
+
width: Math.max(256, size * 128), // Minimum 256px, scales with size parameter
|
|
72
|
+
margin: 2,
|
|
73
|
+
color: {
|
|
74
|
+
dark: '#000000', // Black
|
|
75
|
+
light: '#FFFFFF' // White
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
console.log(`[DEBUG] QR code generated successfully`);
|
|
79
|
+
// Extract just the base64 data (remove the data:image/png;base64, prefix)
|
|
80
|
+
const base64Data = dataUrl.split(',')[1];
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: `📱 QR Code for: "${text}"
|
|
86
|
+
|
|
87
|
+
📊 Data encoded: "${text}" (${text.length} characters)
|
|
88
|
+
🎯 Error correction: Medium (M)
|
|
89
|
+
📐 Image size: ${Math.max(256, size * 128)}x${Math.max(256, size * 128)} pixels
|
|
90
|
+
|
|
91
|
+
✅ This QR code can be scanned with any QR code reader app
|
|
92
|
+
💡 Generated using the 'qrcode' npm library!`,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: "image",
|
|
96
|
+
data: base64Data,
|
|
97
|
+
mimeType: "image/png"
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error(`[DEBUG] QR code generation failed:`, error);
|
|
104
|
+
return {
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
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'}`,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
// SVG placeholder generator
|
|
120
|
+
server.tool("svg-placeholder-generator", "Generate SVG placeholder images", {
|
|
121
|
+
width: z.number().describe("Width in pixels").optional(),
|
|
122
|
+
height: z.number().describe("Height in pixels").optional(),
|
|
123
|
+
backgroundColor: z.string().describe("Background color (hex)").optional(),
|
|
124
|
+
textColor: z.string().describe("Text color (hex)").optional(),
|
|
125
|
+
text: z.string().optional().describe("Custom text (default: dimensions)"),
|
|
126
|
+
}, async ({ width = 300, height = 200, backgroundColor = "#cccccc", textColor = "#666666", text }) => {
|
|
127
|
+
try {
|
|
128
|
+
if (width < 1 || width > 2000 || height < 1 || height > 2000) {
|
|
129
|
+
return {
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: "Width and height must be between 1 and 2000 pixels.",
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const displayText = text || `${width}×${height}`;
|
|
139
|
+
const fontSize = Math.min(width, height) / 8;
|
|
140
|
+
const svg = `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
|
|
141
|
+
<rect width="100%" height="100%" fill="${backgroundColor}"/>
|
|
142
|
+
<text x="50%" y="50%" font-family="Arial, sans-serif" font-size="${fontSize}" fill="${textColor}" text-anchor="middle" dy=".3em">${displayText}</text>
|
|
143
|
+
</svg>`;
|
|
144
|
+
const dataUrl = `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`;
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: "text",
|
|
149
|
+
text: `SVG Placeholder Generated:
|
|
150
|
+
|
|
151
|
+
Dimensions: ${width}×${height}
|
|
152
|
+
Background: ${backgroundColor}
|
|
153
|
+
Text Color: ${textColor}
|
|
154
|
+
Text: ${displayText}
|
|
155
|
+
|
|
156
|
+
SVG Code:
|
|
157
|
+
${svg}
|
|
158
|
+
|
|
159
|
+
Data URL:
|
|
160
|
+
${dataUrl}`,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
return {
|
|
167
|
+
content: [
|
|
168
|
+
{
|
|
169
|
+
type: "text",
|
|
170
|
+
text: `Error generating SVG placeholder: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|