it-tools-mcp 3.0.8 → 3.0.9
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/README.dockerhub.md +4 -3
- package/README.md +20 -8
- package/build/tools/dataFormat.js +33 -0
- package/build/tools/network.js +200 -54
- package/package.json +11 -3
package/README.dockerhub.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://hub.docker.com/r/wrenchpilot/it-tools-mcp)
|
|
5
5
|
[](https://github.com/wrenchpilot/it-tools-mcp/actions)
|
|
6
6
|
|
|
7
|
-
A comprehensive Model Context Protocol (MCP) server that provides access to **
|
|
7
|
+
A comprehensive Model Context Protocol (MCP) server that provides access to **86 IT tools and utilities** commonly used by developers, system administrators, and IT professionals. This server exposes a complete set of tools for encoding/decoding, text manipulation, hashing, network utilities, and many other common development and IT tasks.
|
|
8
8
|
|
|
9
9
|
## Using with VS Code
|
|
10
10
|
|
|
@@ -56,7 +56,7 @@ Add to your VS Code `settings.json`:
|
|
|
56
56
|
}
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
See the complete list of all
|
|
59
|
+
See the complete list of all 86 tools with detailed parameters on [GitHub](https://github.com/wrenchpilot/it-tools-mcp#available-tools)
|
|
60
60
|
|
|
61
61
|
## 📸 Examples in Action
|
|
62
62
|
|
|
@@ -76,7 +76,7 @@ Built with **TypeScript**, **Zod** validation, and **MCP SDK** for robust, type-
|
|
|
76
76
|
|
|
77
77
|
This project was developed using **VS Code**, **Copilot Chat Agent**, **Playwright MCP**, and the **Claude Sonnet 4 Model**, showcasing modern AI-assisted software development:
|
|
78
78
|
|
|
79
|
-
- 🔧 **All
|
|
79
|
+
- 🔧 **All 86 tools** designed and implemented with AI assistance
|
|
80
80
|
- 📦 **Complete Docker setup** with GitHub Actions CI/CD pipeline
|
|
81
81
|
- 🔍 **Schema optimization** with systematic validation cleanup
|
|
82
82
|
- 📚 **Comprehensive documentation** and tool catalogs
|
|
@@ -86,6 +86,7 @@ This project was developed using **VS Code**, **Copilot Chat Agent**, **Playwrig
|
|
|
86
86
|
```text
|
|
87
87
|
src/
|
|
88
88
|
├── index.ts # Main MCP server
|
|
89
|
+
├── security.ts # Security settings
|
|
89
90
|
└── tools/ # Tool modules by category
|
|
90
91
|
├── encoding.ts # Base64, URL, HTML encoding
|
|
91
92
|
├── crypto.ts # Hashing, JWT, passwords
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
> **📝 Note**: A condensed version of this README is automatically synced to [Docker Hub](https://hub.docker.com/r/wrenchpilot/it-tools-mcp) due to character limits.
|
|
8
8
|
|
|
9
|
-
A comprehensive Model Context Protocol (MCP) server that provides access to
|
|
9
|
+
A comprehensive Model Context Protocol (MCP) server that provides access to 86 IT tools and utilities commonly used by developers, system administrators, and IT professionals. This server exposes a complete set of tools for encoding/decoding, text manipulation, hashing, network utilities, and many other common development and IT tasks.
|
|
10
10
|
|
|
11
11
|
## 📦 Installation & Setup
|
|
12
12
|
|
|
@@ -80,16 +80,16 @@ echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"base64-enc
|
|
|
80
80
|
|
|
81
81
|
## 🛠️ Tool Categories
|
|
82
82
|
|
|
83
|
-
This MCP server provides **
|
|
83
|
+
This MCP server provides **86 tools** across **8 categories**:
|
|
84
84
|
|
|
85
85
|
- **🔧 Encoding & Decoding** (9 tools): Base64, URL, HTML entities, text-to-binary, Unicode
|
|
86
86
|
- **📝 Data Format** (11 tools): JSON, XML, YAML, SQL, TOML, Markdown ↔ HTML conversion
|
|
87
87
|
- **🔐 Security & Crypto** (12 tools): Hashing (MD5, SHA1-512), HMAC, JWT, bcrypt, passwords, tokens
|
|
88
88
|
- **✨ Text Processing** (16 tools): Case conversion, stats, diff, ASCII art, NATO alphabet, slugify
|
|
89
|
-
- **🌐 Network &
|
|
89
|
+
- **🌐 Network & System** (19 tools): IPv4/IPv6 subnets, URL parsing, MAC addresses, phone formatting, ps, top, cat, head, tail, grep, ping, nslookup, telnet, dig, ssh, random-port, mac-address-generate, ip/ipv6 calculators
|
|
90
90
|
- **🔢 Math & Calculations** (6 tools): Expression evaluation, base conversion, temperature, percentages
|
|
91
|
-
- **🆔 ID & Code Generators** (4 tools
|
|
92
|
-
-
|
|
91
|
+
- **🆔 ID & Code Generators** (4 tools: UUID, ULID, QR codes, SVG placeholders
|
|
92
|
+
- **🛠️ Utility Tools** (9 tools): Color, MIME, HTTP, device info, email normalization, etc.
|
|
93
93
|
|
|
94
94
|
## 📸 Screenshot Examples
|
|
95
95
|
|
|
@@ -159,14 +159,25 @@ This MCP server provides **75 tools** across **8 categories**:
|
|
|
159
159
|
| `lorem-ipsum-generator` | Generate Lorem Ipsum | `type?: 'words' \| 'sentences' \| 'paragraphs'`, `count?: number` |
|
|
160
160
|
| `numeronym-generator` | Generate numeronyms | `text: string` |
|
|
161
161
|
| `emoji-search` | Search emojis | `query: string` |
|
|
162
|
-
| **Network &
|
|
162
|
+
| **Network & System** | | |
|
|
163
|
+
| `ps` | List running processes | None |
|
|
164
|
+
| `top` | Show top processes (by CPU) | None |
|
|
165
|
+
| `cat` | Display file content | `file: string` |
|
|
166
|
+
| `head` | Show first N lines of file | `file: string`, `lines?: number` |
|
|
167
|
+
| `tail` | Show last N lines of file | `file: string`, `lines?: number` |
|
|
168
|
+
| `grep` | Search for pattern in file | `file: string`, `pattern: string` |
|
|
169
|
+
| `ping` | Ping a host | `target: string`, `count?: number` |
|
|
170
|
+
| `nslookup` | DNS lookup (A/AAAA/CNAME) | `target: string` |
|
|
171
|
+
| `telnet` | Test TCP connectivity | `target: string`, `port: number` |
|
|
172
|
+
| `dig` | DNS query (custom type) | `target: string`, `type?: string` |
|
|
173
|
+
| `ssh` | SSH command execution | `target: string`, `user: string`, `command: string` |
|
|
163
174
|
| `ip-subnet-calculator` | Calculate IPv4 subnet | `ip: string`, `cidr: number` |
|
|
164
175
|
| `ipv4-subnet-calc` | Enhanced IPv4 subnet calc | `cidr: string` |
|
|
165
176
|
| `ipv6-ula-generator` | Generate IPv6 ULA | `globalId?: string` |
|
|
166
177
|
| `url-parse` | Parse URL components | `url: string` |
|
|
167
178
|
| `random-port` | Generate random ports | `count?: number`, `min?: number`, `max?: number`, `exclude?: number[]` |
|
|
168
|
-
| `mac-address-generate` | Generate MAC address | `prefix?: string`, `separator?: ':'
|
|
169
|
-
| `phone-format` |
|
|
179
|
+
| `mac-address-generate` | Generate MAC address | `prefix?: string`, `separator?: ':' | '-'` |
|
|
180
|
+
| `phone-format` | Parse and format phone numbers | `phoneNumber: string`, `countryCode?: string` |
|
|
170
181
|
| `iban-validate` | Validate IBAN | `iban: string` |
|
|
171
182
|
| **Math & Calculations** | | |
|
|
172
183
|
| `math-evaluate` | Evaluate expressions | `expression: string` |
|
|
@@ -260,6 +271,7 @@ This showcases how AI can accelerate development while maintaining code quality,
|
|
|
260
271
|
```text
|
|
261
272
|
src/
|
|
262
273
|
├── index.ts # Main MCP server
|
|
274
|
+
├── security.ts # Security settings
|
|
263
275
|
└── tools/ # Tool modules by category
|
|
264
276
|
├── encoding.ts # Base64, URL, HTML encoding
|
|
265
277
|
├── crypto.ts # Hashing, JWT, passwords
|
|
@@ -504,4 +504,37 @@ ${differences.map((diff, i) => `${i + 1}. ${diff}`).join('\n')}`,
|
|
|
504
504
|
};
|
|
505
505
|
}
|
|
506
506
|
});
|
|
507
|
+
// Phone number formatter
|
|
508
|
+
server.tool("phone-format", "Parse and format phone numbers", {
|
|
509
|
+
phoneNumber: z.string().describe("Phone number to parse and format"),
|
|
510
|
+
countryCode: z.string().optional().describe("Country code (e.g., 'US', 'GB', 'FR')"),
|
|
511
|
+
}, async ({ phoneNumber, countryCode }) => {
|
|
512
|
+
try {
|
|
513
|
+
const { isValidPhoneNumber, parsePhoneNumber } = await import("libphonenumber-js");
|
|
514
|
+
// First check if it's a valid phone number
|
|
515
|
+
if (!isValidPhoneNumber(phoneNumber, countryCode)) {
|
|
516
|
+
throw new Error("Invalid phone number format");
|
|
517
|
+
}
|
|
518
|
+
// Parse the phone number
|
|
519
|
+
const parsedNumber = parsePhoneNumber(phoneNumber, countryCode);
|
|
520
|
+
return {
|
|
521
|
+
content: [
|
|
522
|
+
{
|
|
523
|
+
type: "text",
|
|
524
|
+
text: `Phone Number Formatting:\n\nOriginal: ${phoneNumber}\nCountry: ${parsedNumber.country || 'Unknown'}\nNational: ${parsedNumber.formatNational()}\nInternational: ${parsedNumber.formatInternational()}\nE.164: ${parsedNumber.format('E.164')}\nURI: ${parsedNumber.getURI()}\n\nDetails:\nType: ${parsedNumber.getType() || 'Unknown'}\nCountry Code: +${parsedNumber.countryCallingCode}\nNational Number: ${parsedNumber.nationalNumber}\nValid: ${parsedNumber.isValid()}\n\n✅ Formatted using libphonenumber-js library for accuracy.`,
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
return {
|
|
531
|
+
content: [
|
|
532
|
+
{
|
|
533
|
+
type: "text",
|
|
534
|
+
text: `Error formatting phone number: ${error instanceof Error ? error.message : 'Unknown error'}\n\n💡 Tips:\n• Include country code (e.g., +1 555-123-4567)\n• Use standard formats (e.g., (555) 123-4567)\n• Specify country code parameter if needed\n• Examples: "+1-555-123-4567", "555-123-4567" with countryCode="US"`,
|
|
535
|
+
},
|
|
536
|
+
],
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
});
|
|
507
540
|
}
|
package/build/tools/network.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { Client as SSHClient } from "ssh2";
|
|
3
|
+
import ping from "ping";
|
|
4
|
+
import dns from "dns";
|
|
5
|
+
import Telnet from "telnet-client";
|
|
6
|
+
import psList from "ps-list";
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import readLastLines from "read-last-lines";
|
|
9
|
+
// For Telnet import (telnet-client exports as an object, not a class)
|
|
10
|
+
const TelnetClient = Telnet.Telnet || Telnet;
|
|
2
11
|
export function registerNetworkTools(server) {
|
|
3
12
|
// IP address tools
|
|
4
13
|
server.tool("ip-subnet-calculator", "Calculate subnet information for IPv4", {
|
|
@@ -440,60 +449,7 @@ ${prefix ? `Used prefix: ${prefix}` : 'Randomly generated'}`,
|
|
|
440
449
|
};
|
|
441
450
|
}
|
|
442
451
|
});
|
|
443
|
-
// Phone number formatter
|
|
444
|
-
server.tool("phone-format", "Parse and format phone numbers", {
|
|
445
|
-
phoneNumber: z.string().describe("Phone number to parse and format"),
|
|
446
|
-
countryCode: z.string().optional().describe("Country code (e.g., 'US', 'GB', 'FR')"),
|
|
447
|
-
}, async ({ phoneNumber, countryCode }) => {
|
|
448
|
-
try {
|
|
449
|
-
const { isValidPhoneNumber, parsePhoneNumber } = await import("libphonenumber-js");
|
|
450
|
-
// First check if it's a valid phone number
|
|
451
|
-
if (!isValidPhoneNumber(phoneNumber, countryCode)) {
|
|
452
|
-
throw new Error("Invalid phone number format");
|
|
453
|
-
}
|
|
454
|
-
// Parse the phone number
|
|
455
|
-
const parsedNumber = parsePhoneNumber(phoneNumber, countryCode);
|
|
456
|
-
return {
|
|
457
|
-
content: [
|
|
458
|
-
{
|
|
459
|
-
type: "text",
|
|
460
|
-
text: `Phone Number Formatting:
|
|
461
|
-
|
|
462
|
-
Original: ${phoneNumber}
|
|
463
|
-
Country: ${parsedNumber.country || 'Unknown'}
|
|
464
|
-
National: ${parsedNumber.formatNational()}
|
|
465
|
-
International: ${parsedNumber.formatInternational()}
|
|
466
|
-
E.164: ${parsedNumber.format('E.164')}
|
|
467
|
-
URI: ${parsedNumber.getURI()}
|
|
468
|
-
|
|
469
|
-
Details:
|
|
470
|
-
Type: ${parsedNumber.getType() || 'Unknown'}
|
|
471
|
-
Country Code: +${parsedNumber.countryCallingCode}
|
|
472
|
-
National Number: ${parsedNumber.nationalNumber}
|
|
473
|
-
Valid: ${parsedNumber.isValid()}
|
|
474
|
-
|
|
475
|
-
✅ Formatted using libphonenumber-js library for accuracy.`,
|
|
476
|
-
},
|
|
477
|
-
],
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
catch (error) {
|
|
481
|
-
return {
|
|
482
|
-
content: [
|
|
483
|
-
{
|
|
484
|
-
type: "text",
|
|
485
|
-
text: `Error formatting phone number: ${error instanceof Error ? error.message : 'Unknown error'}
|
|
486
|
-
|
|
487
|
-
💡 Tips:
|
|
488
|
-
• Include country code (e.g., +1 555-123-4567)
|
|
489
|
-
• Use standard formats (e.g., (555) 123-4567)
|
|
490
|
-
• Specify country code parameter if needed
|
|
491
|
-
• Examples: "+1-555-123-4567", "555-123-4567" with countryCode="US"`,
|
|
492
|
-
},
|
|
493
|
-
],
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
});
|
|
452
|
+
// Phone number formatter tool moved to dataFormat.ts
|
|
497
453
|
// IBAN validator (using iban library)
|
|
498
454
|
server.tool("iban-validate", "Validate and parse IBAN (International Bank Account Number)", {
|
|
499
455
|
iban: z.string().describe("IBAN to validate and parse"),
|
|
@@ -575,4 +531,194 @@ Common issues:
|
|
|
575
531
|
};
|
|
576
532
|
}
|
|
577
533
|
});
|
|
534
|
+
// SSH Tool (using ssh2)
|
|
535
|
+
server.tool("ssh", "Connect to a target via SSH", {
|
|
536
|
+
target: z.string().describe("Target host"),
|
|
537
|
+
user: z.string().describe("Username"),
|
|
538
|
+
command: z.string().describe("Command to run on remote host"),
|
|
539
|
+
privateKey: z.string().optional().describe("Private key for authentication (PEM format, optional)")
|
|
540
|
+
}, async ({ target, user, command, privateKey }) => {
|
|
541
|
+
return new Promise((resolve) => {
|
|
542
|
+
const conn = new SSHClient();
|
|
543
|
+
let output = "";
|
|
544
|
+
conn.on("ready", () => {
|
|
545
|
+
conn.exec(command, (err, stream) => {
|
|
546
|
+
if (err) {
|
|
547
|
+
resolve({ content: [{ type: "text", text: `SSH error: ${err.message}` }] });
|
|
548
|
+
conn.end();
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
stream.on("close", () => {
|
|
552
|
+
conn.end();
|
|
553
|
+
resolve({ content: [{ type: "text", text: output }] });
|
|
554
|
+
}).on("data", (data) => {
|
|
555
|
+
output += data.toString();
|
|
556
|
+
}).stderr.on("data", (data) => {
|
|
557
|
+
output += data.toString();
|
|
558
|
+
});
|
|
559
|
+
});
|
|
560
|
+
}).on("error", (err) => {
|
|
561
|
+
resolve({ content: [{ type: "text", text: `SSH connection error: ${err.message}` }] });
|
|
562
|
+
}).connect({
|
|
563
|
+
host: target,
|
|
564
|
+
username: user,
|
|
565
|
+
...(privateKey ? { privateKey } : {})
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
});
|
|
569
|
+
// Ping Tool (using ping)
|
|
570
|
+
server.tool("ping", "Ping a host to check connectivity", {
|
|
571
|
+
target: z.string().describe("Host to ping"),
|
|
572
|
+
count: z.number().default(4).describe("Number of ping attempts")
|
|
573
|
+
}, async ({ target, count }) => {
|
|
574
|
+
try {
|
|
575
|
+
const res = await ping.promise.probe(target, { min_reply: count });
|
|
576
|
+
return {
|
|
577
|
+
content: [
|
|
578
|
+
{ type: "text", text: `Ping to ${target}:\nAlive: ${res.alive}\nTime: ${res.time} ms\nOutput: ${res.output}` }
|
|
579
|
+
]
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
catch (error) {
|
|
583
|
+
return { content: [{ type: "text", text: `Ping failed: ${error instanceof Error ? error.message : error}` }] };
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
// nslookup Tool (using dns)
|
|
587
|
+
server.tool("nslookup", "Perform DNS lookup on a hostname or IP address", {
|
|
588
|
+
target: z.string().describe("Hostname or IP address")
|
|
589
|
+
}, async ({ target }) => {
|
|
590
|
+
return new Promise((resolve) => {
|
|
591
|
+
dns.lookup(target, (err, address, family) => {
|
|
592
|
+
if (err) {
|
|
593
|
+
resolve({ content: [{ type: "text", text: `nslookup failed: ${err.message}` }] });
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
resolve({ content: [{ type: "text", text: `Address: ${address}\nFamily: IPv${family}` }] });
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
// telnet Tool (using telnet-client)
|
|
602
|
+
server.tool("telnet", "Test TCP connectivity to a host and port", {
|
|
603
|
+
target: z.string().describe("Host to connect to"),
|
|
604
|
+
port: z.number().describe("Port number")
|
|
605
|
+
}, async ({ target, port }) => {
|
|
606
|
+
const connection = new TelnetClient();
|
|
607
|
+
const params = {
|
|
608
|
+
host: target,
|
|
609
|
+
port: port,
|
|
610
|
+
shellPrompt: /[$%#>]$/,
|
|
611
|
+
timeout: 1500,
|
|
612
|
+
};
|
|
613
|
+
try {
|
|
614
|
+
await connection.connect(params);
|
|
615
|
+
await connection.end();
|
|
616
|
+
return { content: [{ type: "text", text: `Telnet to ${target}:${port} succeeded.` }] };
|
|
617
|
+
}
|
|
618
|
+
catch (error) {
|
|
619
|
+
return { content: [{ type: "text", text: `Telnet failed: ${error instanceof Error ? error.message : error}` }] };
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
// dig Tool (using dns.resolve)
|
|
623
|
+
server.tool("dig", "Perform DNS lookup with dig command", {
|
|
624
|
+
target: z.string().describe("Hostname or IP address"),
|
|
625
|
+
type: z.string().default("A").describe("DNS record type")
|
|
626
|
+
}, async ({ target, type }) => {
|
|
627
|
+
return new Promise((resolve) => {
|
|
628
|
+
dns.resolve(target, type, (err, addresses) => {
|
|
629
|
+
if (err) {
|
|
630
|
+
resolve({ content: [{ type: "text", text: `dig failed: ${err.message}` }] });
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
resolve({ content: [{ type: "text", text: `${type} records for ${target}:\n${JSON.stringify(addresses, null, 2)}` }] });
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
// ps Tool (using ps-list)
|
|
639
|
+
server.tool("ps", "List running processes", {}, async () => {
|
|
640
|
+
try {
|
|
641
|
+
const processes = await psList();
|
|
642
|
+
// Defensive: handle missing properties and filter out bad entries
|
|
643
|
+
const output = processes
|
|
644
|
+
.map(p => {
|
|
645
|
+
const pid = p.pid ?? 'N/A';
|
|
646
|
+
const name = p.name ?? 'N/A';
|
|
647
|
+
return `${pid}\t${name}`;
|
|
648
|
+
})
|
|
649
|
+
.join("\n");
|
|
650
|
+
return { content: [{ type: "text", text: output || 'No processes found.' }] };
|
|
651
|
+
}
|
|
652
|
+
catch (error) {
|
|
653
|
+
// Log error for debugging
|
|
654
|
+
console.error('ps error:', error);
|
|
655
|
+
return { content: [{ type: "text", text: `ps failed: ${error instanceof Error ? error.message : error}` }] };
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
// cat Tool (using fs)
|
|
659
|
+
server.tool("cat", "Display content of a file", {
|
|
660
|
+
file: z.string().describe("File path")
|
|
661
|
+
}, async ({ file }) => {
|
|
662
|
+
try {
|
|
663
|
+
const data = fs.readFileSync(file, "utf8");
|
|
664
|
+
return { content: [{ type: "text", text: data }] };
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
return { content: [{ type: "text", text: `cat failed: ${error instanceof Error ? error.message : error}` }] };
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
// top Tool (using ps-list, show top 10 by CPU)
|
|
671
|
+
server.tool("top", "Display system processes (snapshot)", {}, async () => {
|
|
672
|
+
try {
|
|
673
|
+
const processes = await psList();
|
|
674
|
+
const sorted = processes.sort((a, b) => (b.cpu || 0) - (a.cpu || 0)).slice(0, 10);
|
|
675
|
+
const output = sorted.map(p => `${p.pid}\t${p.name}\tCPU: ${p.cpu || 0}%\tMEM: ${p.memory || 0}`).join("\n");
|
|
676
|
+
return { content: [{ type: "text", text: output }] };
|
|
677
|
+
}
|
|
678
|
+
catch (error) {
|
|
679
|
+
return { content: [{ type: "text", text: `top failed: ${error instanceof Error ? error.message : error}` }] };
|
|
680
|
+
}
|
|
681
|
+
});
|
|
682
|
+
// grep Tool (using grep-js)
|
|
683
|
+
server.tool("grep", "Search for patterns in files", {
|
|
684
|
+
pattern: z.string().describe("Pattern to search for"),
|
|
685
|
+
file: z.string().describe("File path")
|
|
686
|
+
}, async ({ pattern, file }) => {
|
|
687
|
+
try {
|
|
688
|
+
const data = fs.readFileSync(file, "utf8");
|
|
689
|
+
const lines = data.split("\n");
|
|
690
|
+
const matches = lines.filter(line => line.includes(pattern));
|
|
691
|
+
return { content: [{ type: "text", text: matches.join("\n") }] };
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
return { content: [{ type: "text", text: `grep failed: ${error instanceof Error ? error.message : error}` }] };
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
// head Tool (using fs)
|
|
698
|
+
server.tool("head", "Display the beginning of a file", {
|
|
699
|
+
file: z.string().describe("File path"),
|
|
700
|
+
lines: z.number().default(10).describe("Number of lines")
|
|
701
|
+
}, async ({ file, lines }) => {
|
|
702
|
+
try {
|
|
703
|
+
const data = fs.readFileSync(file, "utf8");
|
|
704
|
+
const out = data.split("\n").slice(0, lines).join("\n");
|
|
705
|
+
return { content: [{ type: "text", text: out }] };
|
|
706
|
+
}
|
|
707
|
+
catch (error) {
|
|
708
|
+
return { content: [{ type: "text", text: `head failed: ${error instanceof Error ? error.message : error}` }] };
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
// tail Tool (using read-last-lines)
|
|
712
|
+
server.tool("tail", "Display the end of a file", {
|
|
713
|
+
file: z.string().describe("File path"),
|
|
714
|
+
lines: z.number().default(10).describe("Number of lines")
|
|
715
|
+
}, async ({ file, lines }) => {
|
|
716
|
+
try {
|
|
717
|
+
const out = await readLastLines.read(file, lines);
|
|
718
|
+
return { content: [{ type: "text", text: out }] };
|
|
719
|
+
}
|
|
720
|
+
catch (error) {
|
|
721
|
+
return { content: [{ type: "text", text: `tail failed: ${error instanceof Error ? error.message : error}` }] };
|
|
722
|
+
}
|
|
723
|
+
});
|
|
578
724
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "it-tools-mcp",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.9",
|
|
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,9 +13,8 @@
|
|
|
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:
|
|
16
|
+
"test:all": "node tests/all-tools-test.mjs",
|
|
17
17
|
"test:security": "node tests/security-test.mjs",
|
|
18
|
-
"test:all": "npm run test && npm run test:security && npm run test:math",
|
|
19
18
|
"docker:build": "docker buildx build --platform linux/amd64,linux/arm64 --provenance=true --sbom=true -t it-tools-mcp .",
|
|
20
19
|
"docker:build:local": "docker build -t it-tools-mcp .",
|
|
21
20
|
"docker:run": "docker-compose up --build",
|
|
@@ -56,7 +55,10 @@
|
|
|
56
55
|
"@types/marked": "^5.0.2",
|
|
57
56
|
"@types/mime-types": "^3.0.1",
|
|
58
57
|
"@types/node": "^22.15.32",
|
|
58
|
+
"@types/ping": "^0.4.4",
|
|
59
|
+
"@types/shell-escape": "^0.2.3",
|
|
59
60
|
"@types/speakeasy": "^2.0.10",
|
|
61
|
+
"@types/ssh2": "^1.15.5",
|
|
60
62
|
"@types/turndown": "^5.0.5",
|
|
61
63
|
"@types/validator": "^13.15.2",
|
|
62
64
|
"@types/xml-formatter": "^1.2.0",
|
|
@@ -84,9 +86,15 @@
|
|
|
84
86
|
"mime-types": "^3.0.1",
|
|
85
87
|
"node-fetch": "^3.3.2",
|
|
86
88
|
"papaparse": "^5.5.3",
|
|
89
|
+
"ping": "^0.4.4",
|
|
90
|
+
"ps-list": "^8.1.1",
|
|
87
91
|
"qrcode": "^1.5.4",
|
|
92
|
+
"read-last-lines": "^1.8.0",
|
|
93
|
+
"shell-escape": "^0.2.0",
|
|
88
94
|
"speakeasy": "^2.0.0",
|
|
89
95
|
"sql-formatter": "^15.6.5",
|
|
96
|
+
"ssh2": "^1.16.0",
|
|
97
|
+
"telnet-client": "^2.2.5",
|
|
90
98
|
"turndown": "^7.2.0",
|
|
91
99
|
"ulid": "^3.0.1",
|
|
92
100
|
"validator": "^13.15.15",
|