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.
- package/README.dockerhub.md +3 -3
- package/README.md +73 -72
- package/build/index.js +201 -1
- package/build/tools/network.js +48 -0
- package/package.json +2 -2
- package/build/security.js +0 -201
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 **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
|
|
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
|
|
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
|
|
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 **
|
|
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** (
|
|
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
|
-
| `
|
|
126
|
-
| `
|
|
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
|
-
| `
|
|
131
|
-
| `
|
|
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
|
-
| `
|
|
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
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
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-
|
|
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
|
-
| `
|
|
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 {
|
|
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, '&')
|
|
131
|
+
.replace(/</g, '<')
|
|
132
|
+
.replace(/>/g, '>')
|
|
133
|
+
.replace(/"/g, '"')
|
|
134
|
+
.replace(/'/g, ''');
|
|
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
|
package/build/tools/network.js
CHANGED
|
@@ -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.
|
|
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, '&')
|
|
126
|
-
.replace(/</g, '<')
|
|
127
|
-
.replace(/>/g, '>')
|
|
128
|
-
.replace(/"/g, '"')
|
|
129
|
-
.replace(/'/g, ''');
|
|
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
|
-
};
|