it-tools-mcp 3.0.16 → 3.0.18

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.
@@ -4,7 +4,7 @@
4
4
  [![Docker Image Size](https://img.shields.io/docker/image-size/wrenchpilot/it-tools-mcp/latest?refresh=1)](https://hub.docker.com/r/wrenchpilot/it-tools-mcp)
5
5
  [![Build Status](https://github.com/wrenchpilot/it-tools-mcp/workflows/Build%20and%20Push%20to%20Docker%20Hub/badge.svg)](https://github.com/wrenchpilot/it-tools-mcp/actions)
6
6
 
7
- A comprehensive Model Context Protocol (MCP) server that provides access to **87 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.
7
+ A comprehensive Model Context Protocol (MCP) server that provides access to **88 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 87 tools with detailed parameters on [GitHub](https://github.com/wrenchpilot/it-tools-mcp#available-tools)
59
+ See the complete list of all 88 tools with detailed parameters on [GitHub](https://github.com/wrenchpilot/it-tools-mcp#available-tools)
60
60
 
61
61
  ## 📸 Examples in Action
62
62
 
@@ -78,7 +78,7 @@ Built with **TypeScript**, **Zod** validation, and **MCP SDK** for robust, type-
78
78
 
79
79
  This project was developed using **VS Code**, **Copilot Chat Agent**, **Playwright MCP**, and the **Claude Sonnet 4 Model**, showcasing modern AI-assisted software development:
80
80
 
81
- - 🔧 **All 87 tools** designed and implemented with AI assistance
81
+ - 🔧 **All 88 tools** designed and implemented with AI assistance
82
82
  - 📦 **Complete Docker setup** with GitHub Actions CI/CD pipeline
83
83
  - 🔍 **Schema optimization** with systematic validation cleanup
84
84
  - 📚 **Comprehensive documentation** and tool catalogs
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 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.
9
+ A comprehensive Model Context Protocol (MCP) server that provides access to 87 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,13 +80,13 @@ 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 **86 tools** across **8 categories**:
83
+ This MCP server provides **87 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 & 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
89
+ - **🌐 Network & System** (20 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, curl
90
90
  - **🔢 Math & Calculations** (6 tools): Expression evaluation, base conversion, temperature, percentages
91
91
  - **🆔 ID & Code Generators** (4 tools: UUID, ULID, QR codes, SVG placeholders
92
92
  - **🛠️ Utility Tools** (9 tools): Color, MIME, HTTP, device info, email normalization, etc.
@@ -107,102 +107,103 @@ Examples of using the IT Tools MCP server with VS Code Copilot Chat for secure p
107
107
 
108
108
  | Tool | Description | Parameters |
109
109
  | --------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
110
- | **Encoding & Decoding** | | |
111
- | `base64-encode` | Encode text to Base64 | `text: string` |
112
- | `base64-decode` | Decode Base64 text | `text: string` |
113
- | `url-encode` | URL encode text | `text: string` |
114
- | `url-decode` | URL decode text | `text: string` |
115
- | `html-encode` | Encode HTML entities | `text: string` |
116
- | `html-decode` | Decode HTML entities | `text: string` |
117
- | `html-entities-extended` | Extended HTML entity encoding/decoding | `text: string`, `operation: 'encode' \| 'decode'` |
118
- | `text-to-binary` | Convert text to binary and vice versa | `input: string`, `operation: 'encode' \| 'decode'` |
119
- | `text-to-unicode` | Convert text to Unicode and vice versa | `input: string`, `operation: 'encode' \| 'decode'` |
120
110
  | **Data Format** | | |
111
+ | `html-to-markdown` | Convert HTML to Markdown | `html: string` |
112
+ | `json-diff` | Compare JSON objects | `json1: string`, `json2: string` |
121
113
  | `json-format` | Format and validate JSON | `json: string`, `indent?: number` |
122
114
  | `json-minify` | Minify JSON | `json: string` |
123
115
  | `json-to-csv` | Convert JSON to CSV | `json: string`, `delimiter?: string` |
124
116
  | `json-to-toml` | Convert JSON to TOML | `json: string` |
125
- | `json-diff` | Compare JSON objects | `json1: string`, `json2: string` |
126
- | `xml-format` | Format XML | `xml: string`, `indent?: number` |
127
- | `yaml-format` | Format YAML | `yaml: string` |
117
+ | `markdown-to-html` | Convert Markdown to HTML | `markdown: string` |
118
+ | `phone-format` | Parse and format phone numbers | `phoneNumber: string`, `countryCode?: string` |
128
119
  | `sql-format` | Format SQL | `sql: string` |
129
120
  | `toml-to-json` | Convert TOML to JSON | `toml: string` |
130
- | `markdown-to-html` | Convert Markdown to HTML | `markdown: string` |
131
- | `html-to-markdown` | Convert HTML to Markdown | `html: string` |
121
+ | `xml-format` | Format XML | `xml: string`, `indent?: number` |
122
+ | `yaml-format` | Format YAML | `yaml: string` |
123
+ | **Development Tools** | | |
124
+ | `crontab-generate` | Generate cron expressions | `minute?: string`, `hour?: string`, `dayOfMonth?: string`, `month?: string`, `dayOfWeek?: string` |
125
+ | `list-converter` | Convert list formats | `list: string`, `inputFormat: 'comma' \| 'semicolon' \| 'newline' \| 'space' \| 'pipe'`, `outputFormat: 'comma' \| 'semicolon' \| 'newline' \| 'space' \| 'pipe' \| 'json' \| 'quoted'`, `trim?: boolean` |
126
+ | `regex-tester` | Test regular expressions | `pattern: string`, `text: string`, `flags?: string` |
127
+ | **Encoding & Decoding** | | |
128
+ | `base64-decode` | Decode Base64 text | `text: string` |
129
+ | `base64-encode` | Encode text to Base64 | `text: string` |
130
+ | `html-decode` | Decode HTML entities | `text: string` |
131
+ | `html-encode` | Encode HTML entities | `text: string` |
132
+ | `html-entities-extended` | Extended HTML entity encoding/decoding | `text: string`, `operation: 'encode' \| 'decode'` |
133
+ | `text-to-binary` | Convert text to binary and vice versa | `input: string`, `operation: 'encode' \| 'decode'` |
134
+ | `text-to-unicode` | Convert text to Unicode and vice versa | `input: string`, `operation: 'encode' \| 'decode'` |
135
+ | `url-decode` | URL decode text | `text: string` |
136
+ | `url-encode` | URL encode text | `text: string` |
137
+ | **ID & Code Generators** | | |
138
+ | `qr-generate` | Generate QR codes for any content | `text: string`, `size?: number` - Supports URLs, WiFi (WIFI:T:WPA;S:network;P:password;;), contact info, etc. |
139
+ | `svg-placeholder-generator` | Generate SVG placeholder | `width?: number`, `height?: number`, `text?: string`, `backgroundColor?: string`, `textColor?: string` |
140
+ | `ulid-generate` | Generate ULID | None |
141
+ | `uuid-generate` | Generate UUID v4 | None |
142
+ | **Math & Calculations** | | |
143
+ | `math-evaluate` | Evaluate expressions | `expression: string` |
144
+ | `number-base-converter` | Convert number bases | `number: string`, `fromBase: number`, `toBase: number` |
145
+ | `percentage-calculator` | Calculate percentages | `operation: 'percentage-of' \| 'what-percentage' \| 'percentage-change'`, `value1: number`, `value2: number` |
146
+ | `roman-numeral-converter` | Convert Roman numerals | `input: string` |
147
+ | `temperature-converter` | Convert temperatures | `temperature: number`, `from: 'celsius' \| 'fahrenheit' \| 'kelvin'`, `to: 'celsius' \| 'fahrenheit' \| 'kelvin'` |
148
+ | `unix-timestamp-converter` | Convert timestamps | `input: string` |
149
+ | **Network & System** | | |
150
+ | `cat` | Display file content | `file: string` |
151
+ | `curl` | HTTP client (GET, POST, etc.) | `url: string`, `method?: string`, `headers?: Record<string, string>`, `body?: string` |
152
+ | `dig` | DNS query (custom type) | `target: string`, `type?: string` |
153
+ | `grep` | Search for pattern in file | `file: string`, `pattern: string` |
154
+ | `head` | Show first N lines of file | `file: string`, `lines?: number` |
155
+ | `iban-validate` | Validate IBAN | `iban: string` |
156
+ | `ip-subnet-calculator` | Calculate IPv4 subnet | `ip: string`, `cidr: number` |
157
+ | `ipv4-subnet-calc` | Enhanced IPv4 subnet calc | `cidr: string` |
158
+ | `ipv6-ula-generator` | Generate IPv6 ULA | `globalId?: string` |
159
+ | `mac-address-generate` | Generate MAC address | `prefix?: string`, `separator?: ':' \| '-'` |
160
+ | `nslookup` | DNS lookup (A/AAAA/CNAME) | `target: string` |
161
+ | `ping` | Ping a host | `target: string`, `count?: number` |
162
+ | `ps` | List running processes | None |
163
+ | `random-port` | Generate random ports | `count?: number`, `min?: number`, `max?: number`, `exclude?: number[]` |
164
+ | `scp` | Copy files to/from remote host (SFTP) | `target: string`, `user: string`, `direction: 'upload'\|'download'`, `localPath: string`, `remotePath: string`, `privateKey?: string` |
165
+ | `ssh` | SSH command execution | `target: string`, `user: string`, `command: string` |
166
+ | `tail` | Show last N lines of file | `file: string`, `lines?: number` |
167
+ | `telnet` | Test TCP connectivity | `target: string`, `port: number` |
168
+ | `top` | Show top processes (by CPU) | None |
169
+ | `url-parse` | Parse URL components | `url: string` |
132
170
  | **Security & Crypto** | | |
171
+ | `basic-auth-generator` | Generate Basic Auth header | `username: string`, `password: string` |
172
+ | `bcrypt-hash` | Generate/verify bcrypt hash | `password: string`, `rounds?: number`, `hash?: string` |
173
+ | `bip39-generate` | Generate BIP39 mnemonic | `wordCount?: '12' \| '15' \| '18' \| '21' \| '24'` |
133
174
  | `hash-md5` | Generate MD5 hash | `text: string` |
134
175
  | `hash-sha1` | Generate SHA1 hash | `text: string` |
135
176
  | `hash-sha256` | Generate SHA256 hash | `text: string` |
136
177
  | `hash-sha512` | Generate SHA512 hash | `text: string` |
137
178
  | `hmac-generator` | Generate HMAC | `message: string`, `key: string`, `algorithm?: 'sha1' \| 'sha256' \| 'sha512'` |
138
179
  | `jwt-decode` | Decode JWT token | `token: string` |
139
- | `basic-auth-generator` | Generate Basic Auth header | `username: string`, `password: string` |
140
- | `bcrypt-hash` | Generate/verify bcrypt hash | `password: string`, `rounds?: number`, `hash?: string` |
141
- | `bip39-generate` | Generate BIP39 mnemonic | `wordCount?: '12' \| '15' \| '18' \| '21' \| '24'` |
180
+ | `otp-code-generator` | Generate TOTP codes | `secret: string`, `digits?: number`, `period?: number` |
142
181
  | `password-generate` | Generate secure password | `length?: number`, `includeUppercase?: boolean`, `includeLowercase?: boolean`, `includeNumbers?: boolean`, `includeSymbols?: boolean` |
143
182
  | `token-generator` | Generate secure token | `length?: number`, `charset?: 'alphanumeric' \| 'hex' \| 'base64' \| 'custom'`, `customChars?: string` |
144
- | `otp-code-generator` | Generate TOTP codes | `secret: string`, `digits?: number`, `period?: number` |
145
183
  | **Text Processing** | | |
146
- | `text-uppercase` | Convert to uppercase | `text: string` |
147
- | `text-lowercase` | Convert to lowercase | `text: string` |
148
- | `text-capitalize` | Capitalize words | `text: string` |
184
+ | `ascii-art-text` | Generate ASCII art | `text: string`, `font?: string` (supports 295+ figlet fonts) |
185
+ | `emoji-search` | Search emojis | `query: string` |
186
+ | `lorem-ipsum-generator` | Generate Lorem Ipsum | `type?: 'words' \| 'sentences' \| 'paragraphs'`, `count?: number` |
187
+ | `numeronym-generator` | Generate numeronyms | `text: string` |
188
+ | `slugify-string` | Convert to URL slug | `text: string`, `separator?: string`, `lowercase?: boolean` |
189
+ | `string-obfuscator` | Obfuscate text | `text: string`, `method?: 'html-entities' \| 'unicode' \| 'base64'` |
149
190
  | `text-camelcase` | Convert to camelCase | `text: string` |
150
- | `text-pascalcase` | Convert to PascalCase | `text: string` |
191
+ | `text-capitalize` | Capitalize words | `text: string` |
192
+ | `text-diff` | Compare texts | `text1: string`, `text2: string` |
151
193
  | `text-kebabcase` | Convert to kebab-case | `text: string` |
194
+ | `text-lowercase` | Convert to lowercase | `text: string` |
195
+ | `text-pascalcase` | Convert to PascalCase | `text: string` |
152
196
  | `text-snakecase` | Convert to snake_case | `text: string` |
153
197
  | `text-stats` | Get text statistics | `text: string` |
154
- | `text-diff` | Compare texts | `text1: string`, `text2: string` |
155
- | `ascii-art-text` | Generate ASCII art | `text: string`, `font?: string` (supports 295+ figlet fonts) |
156
198
  | `text-to-nato-alphabet` | Convert to NATO alphabet | `text: string` |
157
- | `string-obfuscator` | Obfuscate text | `text: string`, `method?: 'html-entities' \| 'unicode' \| 'base64'` |
158
- | `slugify-string` | Convert to URL slug | `text: string`, `separator?: string`, `lowercase?: boolean` |
159
- | `lorem-ipsum-generator` | Generate Lorem Ipsum | `type?: 'words' \| 'sentences' \| 'paragraphs'`, `count?: number` |
160
- | `numeronym-generator` | Generate numeronyms | `text: string` |
161
- | `emoji-search` | Search emojis | `query: string` |
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` |
174
- | `scp` | Copy files to/from remote host (SFTP) | `target: string`, `user: string`, `direction: 'upload'\|'download'`, `localPath: string`, `remotePath: string`, `privateKey?: string` |
175
- | `ip-subnet-calculator` | Calculate IPv4 subnet | `ip: string`, `cidr: number` |
176
- | `ipv4-subnet-calc` | Enhanced IPv4 subnet calc | `cidr: string` |
177
- | `ipv6-ula-generator` | Generate IPv6 ULA | `globalId?: string` |
178
- | `url-parse` | Parse URL components | `url: string` |
179
- | `random-port` | Generate random ports | `count?: number`, `min?: number`, `max?: number`, `exclude?: number[]` |
180
- | `mac-address-generate` | Generate MAC address | `prefix?: string`, `separator?: ':' \| '-'` |
181
- | `phone-format` | Parse and format phone numbers | `phoneNumber: string`, `countryCode?: string` |
182
- | `iban-validate` | Validate IBAN | `iban: string` |
183
- | **Math & Calculations** | | |
184
- | `math-evaluate` | Evaluate expressions | `expression: string` |
185
- | `number-base-converter` | Convert number bases | `number: string`, `fromBase: number`, `toBase: number` |
186
- | `roman-numeral-converter` | Convert Roman numerals | `input: string` |
187
- | `temperature-converter` | Convert temperatures | `temperature: number`, `from: 'celsius' \| 'fahrenheit' \| 'kelvin'`, `to: 'celsius' \| 'fahrenheit' \| 'kelvin'` |
188
- | `percentage-calculator` | Calculate percentages | `operation: 'percentage-of' \| 'what-percentage' \| 'percentage-change'`, `value1: number`, `value2: number` |
189
- | `unix-timestamp-converter` | Convert timestamps | `input: string` |
190
- | **ID & Code Generators** | | |
191
- | `uuid-generate` | Generate UUID v4 | None |
192
- | `ulid-generate` | Generate ULID | None |
193
- | `qr-generate` | Generate QR codes for any content | `text: string`, `size?: number` - Supports URLs, WiFi (WIFI:T:WPA;S:network;P:password;;), contact info, etc. |
194
- | `svg-placeholder-generator` | Generate SVG placeholder | `width?: number`, `height?: number`, `text?: string`, `backgroundColor?: string`, `textColor?: string` |
195
- | **Development Tools** | | |
196
- | `regex-tester` | Test regular expressions | `pattern: string`, `text: string`, `flags?: string` |
197
- | `crontab-generate` | Generate cron expressions | `minute?: string`, `hour?: string`, `dayOfMonth?: string`, `month?: string`, `dayOfWeek?: string` |
198
- | `list-converter` | Convert list formats | `list: string`, `inputFormat: 'comma' \| 'semicolon' \| 'newline' \| 'space' \| 'pipe'`, `outputFormat: 'comma' \| 'semicolon' \| 'newline' \| 'space' \| 'pipe' \| 'json' \| 'quoted'`, `trim?: boolean` |
199
+ | `text-uppercase` | Convert to uppercase | `text: string` |
199
200
  | **Utility Tools** | | |
200
201
  | `color-hex-to-rgb` | Convert HEX to RGB | `hex: string` |
201
202
  | `color-rgb-to-hex` | Convert RGB to HEX | `r: number`, `g: number`, `b: number` |
202
- | `email-normalizer` | Normalize email addresses | `email: string` |
203
- | `mime-types` | Look up MIME types | `input: string`, `lookupType?: 'extension-to-mime' \| 'mime-to-extension'` |
204
203
  | `device-info` | Get system information | None |
204
+ | `email-normalizer` | Normalize email addresses | `email: string` |
205
205
  | `http-status-codes` | HTTP status reference | `code?: number` |
206
+ | `mime-types` | Look up MIME types | `input: string`, `lookupType?: 'extension-to-mime' \| 'mime-to-extension'` |
206
207
 
207
208
  ## 📱 QR Code Usage Examples
208
209
 
package/build/index.js CHANGED
@@ -1,9 +1,209 @@
1
1
  #!/usr/bin/env node
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { getResourceUsage } from "./security.js";
4
+ import { z } from "zod";
5
5
  import fs from 'fs';
6
6
  import path from 'path';
7
+ /**
8
+ * Security utilities for IT Tools MCP Server
9
+ */
10
+ // Input size limits to prevent DoS attacks
11
+ export const INPUT_LIMITS = {
12
+ TEXT_MAX: 1000000, // 1MB for text input
13
+ JSON_MAX: 500000, // 500KB for JSON
14
+ HTML_MAX: 500000, // 500KB for HTML
15
+ XML_MAX: 500000, // 500KB for XML
16
+ YAML_MAX: 100000, // 100KB for YAML
17
+ CSV_MAX: 1000000, // 1MB for CSV
18
+ PASSWORD_MAX: 128, // Max password length
19
+ TOKEN_LENGTH_MAX: 1024, // Max token length
20
+ LIST_ITEMS_MAX: 10000, // Max list items
21
+ REGEX_MAX: 1000, // Max regex pattern length
22
+ };
23
+ // Base schema with common security validations
24
+ export const secureTextSchema = (maxLength = INPUT_LIMITS.TEXT_MAX) => z.string()
25
+ .max(maxLength, `Input too large (max ${maxLength} characters)`)
26
+ .refine((text) => !text.includes('\0'), "Null bytes not allowed");
27
+ // Secure schemas for different input types
28
+ export const secureSchemas = {
29
+ text: secureTextSchema(),
30
+ shortText: secureTextSchema(1000),
31
+ password: secureTextSchema(INPUT_LIMITS.PASSWORD_MAX),
32
+ json: secureTextSchema(INPUT_LIMITS.JSON_MAX),
33
+ html: secureTextSchema(INPUT_LIMITS.HTML_MAX),
34
+ xml: secureTextSchema(INPUT_LIMITS.XML_MAX),
35
+ yaml: secureTextSchema(INPUT_LIMITS.YAML_MAX),
36
+ csv: secureTextSchema(INPUT_LIMITS.CSV_MAX),
37
+ regex: secureTextSchema(INPUT_LIMITS.REGEX_MAX),
38
+ // Numeric with bounds
39
+ positiveInt: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
40
+ boundedInt: (min, max) => z.number().int().min(min).max(max),
41
+ // Safe URL validation
42
+ url: z.string().url().max(2048),
43
+ // Safe email validation
44
+ email: z.string().email().max(254),
45
+ // Base64 validation
46
+ base64: z.string().regex(/^[A-Za-z0-9+/]*={0,2}$/, "Invalid Base64 format"),
47
+ // Hex validation
48
+ hexColor: z.string().regex(/^#?[0-9A-Fa-f]{6}$/, "Invalid hex color format"),
49
+ // Safe filename
50
+ filename: z.string()
51
+ .max(255)
52
+ .regex(/^[a-zA-Z0-9._-]+$/, "Filename contains invalid characters"),
53
+ };
54
+ /**
55
+ * Rate limiting for tools (simple in-memory implementation)
56
+ */
57
+ class SimpleRateLimiter {
58
+ requests = new Map();
59
+ windowMs;
60
+ maxRequests;
61
+ constructor(windowMs = 60000, maxRequests = 100) {
62
+ this.windowMs = windowMs;
63
+ this.maxRequests = maxRequests;
64
+ }
65
+ isAllowed(identifier) {
66
+ const now = Date.now();
67
+ const windowStart = now - this.windowMs;
68
+ if (!this.requests.has(identifier)) {
69
+ this.requests.set(identifier, []);
70
+ }
71
+ const requests = this.requests.get(identifier);
72
+ // Remove old requests outside the window
73
+ while (requests.length > 0 && requests[0] < windowStart) {
74
+ requests.shift();
75
+ }
76
+ if (requests.length >= this.maxRequests) {
77
+ return false;
78
+ }
79
+ requests.push(now);
80
+ return true;
81
+ }
82
+ reset(identifier) {
83
+ if (identifier) {
84
+ this.requests.delete(identifier);
85
+ }
86
+ else {
87
+ this.requests.clear();
88
+ }
89
+ }
90
+ }
91
+ // Global rate limiter instance
92
+ export const rateLimiter = new SimpleRateLimiter();
93
+ /**
94
+ * Security wrapper for tool handlers
95
+ */
96
+ export function secureToolHandler(handler, identifier = 'default') {
97
+ return async (params) => {
98
+ // Rate limiting check
99
+ if (!rateLimiter.isAllowed(identifier)) {
100
+ throw new Error('Rate limit exceeded. Please try again later.');
101
+ }
102
+ try {
103
+ return await handler(params);
104
+ }
105
+ catch (error) {
106
+ // Log error without exposing sensitive information
107
+ console.error(`Tool error for ${identifier}:`, error instanceof Error ? error.message : 'Unknown error');
108
+ // Return safe error message
109
+ throw new Error('Tool execution failed. Please check your input and try again.');
110
+ }
111
+ };
112
+ }
113
+ /**
114
+ * Input sanitization utilities
115
+ */
116
+ export const sanitize = {
117
+ /**
118
+ * Remove potentially dangerous characters from text
119
+ */
120
+ text: (input) => {
121
+ return input
122
+ .replace(/[\0\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control characters
123
+ .normalize('NFKC'); // Normalize Unicode
124
+ },
125
+ /**
126
+ * Escape HTML entities
127
+ */
128
+ html: (input) => {
129
+ return input
130
+ .replace(/&/g, '&amp;')
131
+ .replace(/</g, '&lt;')
132
+ .replace(/>/g, '&gt;')
133
+ .replace(/"/g, '&quot;')
134
+ .replace(/'/g, '&#x27;');
135
+ },
136
+ /**
137
+ * Safe regex pattern validation
138
+ */
139
+ regex: (pattern) => {
140
+ // Basic validation to prevent ReDoS
141
+ if (pattern.length > INPUT_LIMITS.REGEX_MAX) {
142
+ throw new Error('Regex pattern too long');
143
+ }
144
+ // Check for potentially dangerous patterns
145
+ const dangerousPatterns = [
146
+ /(\*\+|\+\*|\?\+|\+\?|\*\?|\?\*)/, // Nested quantifiers
147
+ /(\([^)]*){10,}/, // Excessive grouping
148
+ /(\|.*){20,}/, // Excessive alternation
149
+ ];
150
+ for (const dangerous of dangerousPatterns) {
151
+ if (dangerous.test(pattern)) {
152
+ throw new Error('Potentially dangerous regex pattern detected');
153
+ }
154
+ }
155
+ return pattern;
156
+ }
157
+ };
158
+ /**
159
+ * Format bytes as human-readable string (e.g., 1.2 MB, 512 KB)
160
+ */
161
+ function formatBytes(bytes) {
162
+ if (bytes < 1024)
163
+ return `${bytes} B`;
164
+ if (bytes < 1024 * 1024)
165
+ return `${(bytes / 1024).toFixed(1)} KB`;
166
+ if (bytes < 1024 * 1024 * 1024)
167
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
168
+ return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
169
+ }
170
+ /**
171
+ * Memory and CPU usage monitoring (human-readable + raw values)
172
+ */
173
+ export function getResourceUsage() {
174
+ const usage = process.memoryUsage();
175
+ const cpuUsage = process.cpuUsage();
176
+ const uptime = process.uptime();
177
+ return {
178
+ memory: {
179
+ heapUsed: formatBytes(usage.heapUsed),
180
+ heapUsedBytes: usage.heapUsed,
181
+ heapTotal: formatBytes(usage.heapTotal),
182
+ heapTotalBytes: usage.heapTotal,
183
+ external: formatBytes(usage.external),
184
+ externalBytes: usage.external,
185
+ rss: formatBytes(usage.rss),
186
+ rssBytes: usage.rss,
187
+ },
188
+ cpu: {
189
+ user: `${(cpuUsage.user / 1000).toFixed(1)} ms`, // microseconds to ms
190
+ userMicros: cpuUsage.user,
191
+ system: `${(cpuUsage.system / 1000).toFixed(1)} ms`,
192
+ systemMicros: cpuUsage.system,
193
+ },
194
+ uptime: `${uptime.toFixed(1)} s`,
195
+ uptimeSeconds: uptime,
196
+ };
197
+ }
198
+ /**
199
+ * Security headers for responses (if applicable)
200
+ */
201
+ export const SECURITY_HEADERS = {
202
+ 'X-Content-Type-Options': 'nosniff',
203
+ 'X-Frame-Options': 'DENY',
204
+ 'X-XSS-Protection': '1; mode=block',
205
+ 'Referrer-Policy': 'strict-origin-when-cross-origin',
206
+ };
7
207
  // Helper to read version from package.json at runtime (ESM compatible)
8
208
  function getPackageVersion() {
9
209
  // Use import.meta.url to get the directory in ESM
@@ -882,4 +882,52 @@ Common issues:
882
882
  return { content: [{ type: "text", text: `SCP fatal error: ${fatalErr.message || fatalErr}` }] };
883
883
  }
884
884
  });
885
+ // curl Tool (HTTP client)
886
+ server.tool("curl", "Make HTTP requests (GET, POST, etc.) like curl", {
887
+ url: z.string().describe("URL to request"),
888
+ method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"]).default("GET").describe("HTTP method"),
889
+ headers: z.record(z.string()).optional().describe("Request headers (object of key-value pairs)"),
890
+ body: z.string().optional().describe("Request body (for POST/PUT/PATCH)")
891
+ }, async ({ url, method, headers, body }) => {
892
+ try {
893
+ // Use native fetch if available (Node 18+), fallback to node-fetch
894
+ let fetchImpl;
895
+ if (typeof globalThis.fetch === 'function') {
896
+ fetchImpl = globalThis.fetch;
897
+ }
898
+ else {
899
+ fetchImpl = (await import('node-fetch')).default;
900
+ }
901
+ const options = {
902
+ method,
903
+ headers: headers || {},
904
+ };
905
+ if (body && ["POST", "PUT", "PATCH"].includes(method)) {
906
+ options.body = body;
907
+ }
908
+ const response = await fetchImpl(url, options);
909
+ let contentType = '';
910
+ if (response.headers && typeof response.headers.get === 'function') {
911
+ contentType = response.headers.get('content-type') || '';
912
+ }
913
+ let responseBody;
914
+ if (contentType.includes('application/json')) {
915
+ responseBody = await response.json();
916
+ responseBody = JSON.stringify(responseBody, null, 2);
917
+ }
918
+ else {
919
+ responseBody = await response.text();
920
+ }
921
+ return {
922
+ content: [
923
+ { type: "text", text: `Status: ${response.status} ${response.statusText}` },
924
+ { type: "text", text: `Headers:\n${JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2)}` },
925
+ { type: "text", text: `Body:\n${responseBody}` }
926
+ ]
927
+ };
928
+ }
929
+ catch (error) {
930
+ return { content: [{ type: "text", text: `curl failed: ${error instanceof Error ? error.message : error}` }] };
931
+ }
932
+ });
885
933
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "it-tools-mcp",
3
- "version": "3.0.16",
3
+ "version": "3.0.18",
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",
@@ -14,7 +14,6 @@
14
14
  "dev": "tsc && node build/index.js",
15
15
  "test": "node tests/test-server.mjs",
16
16
  "test:all": "node tests/all-tools-test.mjs",
17
- "test:security": "node tests/security-test.mjs",
18
17
  "docker:build": "docker buildx build --platform linux/amd64,linux/arm64 --provenance=true --sbom=true -t it-tools-mcp .",
19
18
  "docker:build:local": "docker build -t it-tools-mcp .",
20
19
  "docker:run": "docker-compose up --build",
@@ -84,6 +83,7 @@
84
83
  "marked": "^15.0.12",
85
84
  "mathjs": "^14.5.2",
86
85
  "mime-types": "^3.0.1",
86
+ "node-fetch": "^3.3.2",
87
87
  "papaparse": "^5.5.3",
88
88
  "ping": "^0.4.4",
89
89
  "ps-list": "^8.1.1",
package/build/security.js DELETED
@@ -1,201 +0,0 @@
1
- import { z } from "zod";
2
- /**
3
- * Security utilities for IT Tools MCP Server
4
- */
5
- // Input size limits to prevent DoS attacks
6
- export const INPUT_LIMITS = {
7
- TEXT_MAX: 1000000, // 1MB for text input
8
- JSON_MAX: 500000, // 500KB for JSON
9
- HTML_MAX: 500000, // 500KB for HTML
10
- XML_MAX: 500000, // 500KB for XML
11
- YAML_MAX: 100000, // 100KB for YAML
12
- CSV_MAX: 1000000, // 1MB for CSV
13
- PASSWORD_MAX: 128, // Max password length
14
- TOKEN_LENGTH_MAX: 1024, // Max token length
15
- LIST_ITEMS_MAX: 10000, // Max list items
16
- REGEX_MAX: 1000, // Max regex pattern length
17
- };
18
- // Base schema with common security validations
19
- export const secureTextSchema = (maxLength = INPUT_LIMITS.TEXT_MAX) => z.string()
20
- .max(maxLength, `Input too large (max ${maxLength} characters)`)
21
- .refine((text) => !text.includes('\0'), "Null bytes not allowed");
22
- // Secure schemas for different input types
23
- export const secureSchemas = {
24
- text: secureTextSchema(),
25
- shortText: secureTextSchema(1000),
26
- password: secureTextSchema(INPUT_LIMITS.PASSWORD_MAX),
27
- json: secureTextSchema(INPUT_LIMITS.JSON_MAX),
28
- html: secureTextSchema(INPUT_LIMITS.HTML_MAX),
29
- xml: secureTextSchema(INPUT_LIMITS.XML_MAX),
30
- yaml: secureTextSchema(INPUT_LIMITS.YAML_MAX),
31
- csv: secureTextSchema(INPUT_LIMITS.CSV_MAX),
32
- regex: secureTextSchema(INPUT_LIMITS.REGEX_MAX),
33
- // Numeric with bounds
34
- positiveInt: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
35
- boundedInt: (min, max) => z.number().int().min(min).max(max),
36
- // Safe URL validation
37
- url: z.string().url().max(2048),
38
- // Safe email validation
39
- email: z.string().email().max(254),
40
- // Base64 validation
41
- base64: z.string().regex(/^[A-Za-z0-9+/]*={0,2}$/, "Invalid Base64 format"),
42
- // Hex validation
43
- hexColor: z.string().regex(/^#?[0-9A-Fa-f]{6}$/, "Invalid hex color format"),
44
- // Safe filename
45
- filename: z.string()
46
- .max(255)
47
- .regex(/^[a-zA-Z0-9._-]+$/, "Filename contains invalid characters"),
48
- };
49
- /**
50
- * Rate limiting for tools (simple in-memory implementation)
51
- */
52
- class SimpleRateLimiter {
53
- requests = new Map();
54
- windowMs;
55
- maxRequests;
56
- constructor(windowMs = 60000, maxRequests = 100) {
57
- this.windowMs = windowMs;
58
- this.maxRequests = maxRequests;
59
- }
60
- isAllowed(identifier) {
61
- const now = Date.now();
62
- const windowStart = now - this.windowMs;
63
- if (!this.requests.has(identifier)) {
64
- this.requests.set(identifier, []);
65
- }
66
- const requests = this.requests.get(identifier);
67
- // Remove old requests outside the window
68
- while (requests.length > 0 && requests[0] < windowStart) {
69
- requests.shift();
70
- }
71
- if (requests.length >= this.maxRequests) {
72
- return false;
73
- }
74
- requests.push(now);
75
- return true;
76
- }
77
- reset(identifier) {
78
- if (identifier) {
79
- this.requests.delete(identifier);
80
- }
81
- else {
82
- this.requests.clear();
83
- }
84
- }
85
- }
86
- // Global rate limiter instance
87
- export const rateLimiter = new SimpleRateLimiter();
88
- /**
89
- * Security wrapper for tool handlers
90
- */
91
- export function secureToolHandler(handler, identifier = 'default') {
92
- return async (params) => {
93
- // Rate limiting check
94
- if (!rateLimiter.isAllowed(identifier)) {
95
- throw new Error('Rate limit exceeded. Please try again later.');
96
- }
97
- try {
98
- return await handler(params);
99
- }
100
- catch (error) {
101
- // Log error without exposing sensitive information
102
- console.error(`Tool error for ${identifier}:`, error instanceof Error ? error.message : 'Unknown error');
103
- // Return safe error message
104
- throw new Error('Tool execution failed. Please check your input and try again.');
105
- }
106
- };
107
- }
108
- /**
109
- * Input sanitization utilities
110
- */
111
- export const sanitize = {
112
- /**
113
- * Remove potentially dangerous characters from text
114
- */
115
- text: (input) => {
116
- return input
117
- .replace(/[\0\x08\x0B\x0C\x0E-\x1F\x7F]/g, '') // Remove control characters
118
- .normalize('NFKC'); // Normalize Unicode
119
- },
120
- /**
121
- * Escape HTML entities
122
- */
123
- html: (input) => {
124
- return input
125
- .replace(/&/g, '&amp;')
126
- .replace(/</g, '&lt;')
127
- .replace(/>/g, '&gt;')
128
- .replace(/"/g, '&quot;')
129
- .replace(/'/g, '&#x27;');
130
- },
131
- /**
132
- * Safe regex pattern validation
133
- */
134
- regex: (pattern) => {
135
- // Basic validation to prevent ReDoS
136
- if (pattern.length > INPUT_LIMITS.REGEX_MAX) {
137
- throw new Error('Regex pattern too long');
138
- }
139
- // Check for potentially dangerous patterns
140
- const dangerousPatterns = [
141
- /(\*\+|\+\*|\?\+|\+\?|\*\?|\?\*)/, // Nested quantifiers
142
- /(\([^)]*){10,}/, // Excessive grouping
143
- /(\|.*){20,}/, // Excessive alternation
144
- ];
145
- for (const dangerous of dangerousPatterns) {
146
- if (dangerous.test(pattern)) {
147
- throw new Error('Potentially dangerous regex pattern detected');
148
- }
149
- }
150
- return pattern;
151
- }
152
- };
153
- /**
154
- * Format bytes as human-readable string (e.g., 1.2 MB, 512 KB)
155
- */
156
- function formatBytes(bytes) {
157
- if (bytes < 1024)
158
- return `${bytes} B`;
159
- if (bytes < 1024 * 1024)
160
- return `${(bytes / 1024).toFixed(1)} KB`;
161
- if (bytes < 1024 * 1024 * 1024)
162
- return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
163
- return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
164
- }
165
- /**
166
- * Memory and CPU usage monitoring (human-readable + raw values)
167
- */
168
- export function getResourceUsage() {
169
- const usage = process.memoryUsage();
170
- const cpuUsage = process.cpuUsage();
171
- const uptime = process.uptime();
172
- return {
173
- memory: {
174
- heapUsed: formatBytes(usage.heapUsed),
175
- heapUsedBytes: usage.heapUsed,
176
- heapTotal: formatBytes(usage.heapTotal),
177
- heapTotalBytes: usage.heapTotal,
178
- external: formatBytes(usage.external),
179
- externalBytes: usage.external,
180
- rss: formatBytes(usage.rss),
181
- rssBytes: usage.rss,
182
- },
183
- cpu: {
184
- user: `${(cpuUsage.user / 1000).toFixed(1)} ms`, // microseconds to ms
185
- userMicros: cpuUsage.user,
186
- system: `${(cpuUsage.system / 1000).toFixed(1)} ms`,
187
- systemMicros: cpuUsage.system,
188
- },
189
- uptime: `${uptime.toFixed(1)} s`,
190
- uptimeSeconds: uptime,
191
- };
192
- }
193
- /**
194
- * Security headers for responses (if applicable)
195
- */
196
- export const SECURITY_HEADERS = {
197
- 'X-Content-Type-Options': 'nosniff',
198
- 'X-Frame-Options': 'DENY',
199
- 'X-XSS-Protection': '1; mode=block',
200
- 'Referrer-Policy': 'strict-origin-when-cross-origin',
201
- };