@utilix-tech/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -0
- package/dist/index.js +743 -0
- package/package.json +50 -0
- package/smithery.yaml +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# @utilix-tech/mcp
|
|
2
|
+
|
|
3
|
+
MCP server exposing 51 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
|
|
4
|
+
|
|
5
|
+
No API key required. All tools run locally.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Claude Desktop
|
|
10
|
+
|
|
11
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"utilix": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": ["-y", "@utilix-tech/mcp"]
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Cursor
|
|
25
|
+
|
|
26
|
+
Add to `.cursor/mcp.json` in your project, or `~/.cursor/mcp.json` globally:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"mcpServers": {
|
|
31
|
+
"utilix": {
|
|
32
|
+
"command": "npx",
|
|
33
|
+
"args": ["-y", "@utilix-tech/mcp"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### VS Code Copilot
|
|
40
|
+
|
|
41
|
+
Add to `.vscode/mcp.json`:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"servers": {
|
|
46
|
+
"utilix": {
|
|
47
|
+
"type": "stdio",
|
|
48
|
+
"command": "npx",
|
|
49
|
+
"args": ["-y", "@utilix-tech/mcp"]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Tools
|
|
56
|
+
|
|
57
|
+
### JSON (13 tools)
|
|
58
|
+
| Tool | Description |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| `format_json` | Pretty-print and validate a JSON string |
|
|
61
|
+
| `minify_json` | Remove all whitespace from JSON |
|
|
62
|
+
| `diff_json` | Compare two JSON objects and show changes |
|
|
63
|
+
| `json_to_csv` | Convert a JSON array of objects to CSV |
|
|
64
|
+
| `csv_to_json` | Convert CSV text to a JSON array |
|
|
65
|
+
| `jsonpath` | Evaluate a JSONPath expression |
|
|
66
|
+
| `validate_json` | Validate JSON against a JSON Schema |
|
|
67
|
+
| `yaml_to_json` | Convert YAML to JSON |
|
|
68
|
+
| `json_to_yaml` | Convert JSON to YAML |
|
|
69
|
+
| `json_to_typescript` | Generate TypeScript interfaces from JSON |
|
|
70
|
+
| `json_to_go` | Generate Go structs from JSON |
|
|
71
|
+
| `json_to_python` | Generate Python dataclasses from JSON |
|
|
72
|
+
| `json_to_zod` | Generate a Zod schema from JSON |
|
|
73
|
+
|
|
74
|
+
### Encoding (8 tools)
|
|
75
|
+
| Tool | Description |
|
|
76
|
+
|------|-------------|
|
|
77
|
+
| `base64_encode` | Encode a string to Base64 |
|
|
78
|
+
| `base64_decode` | Decode a Base64 string |
|
|
79
|
+
| `url_encode` | Percent-encode a URL or component |
|
|
80
|
+
| `url_decode` | Decode a percent-encoded string |
|
|
81
|
+
| `html_entities_encode` | Encode HTML entities |
|
|
82
|
+
| `html_entities_decode` | Decode HTML entities |
|
|
83
|
+
| `base32_encode` | Encode a string to Base32 |
|
|
84
|
+
| `base32_decode` | Decode a Base32 string |
|
|
85
|
+
|
|
86
|
+
### Hashing (4 tools)
|
|
87
|
+
| Tool | Description |
|
|
88
|
+
|------|-------------|
|
|
89
|
+
| `hash` | Hash a string with MD5, SHA-1, SHA-256, SHA-384, or SHA-512 |
|
|
90
|
+
| `hash_all` | Hash a string with all algorithms at once |
|
|
91
|
+
| `bcrypt_hash` | Hash a password using bcrypt |
|
|
92
|
+
| `bcrypt_verify` | Verify a password against a bcrypt hash |
|
|
93
|
+
|
|
94
|
+
### Generators (3 tools)
|
|
95
|
+
| Tool | Description |
|
|
96
|
+
|------|-------------|
|
|
97
|
+
| `generate_uuid` | Generate UUID v4 or v7 |
|
|
98
|
+
| `generate_ulid` | Generate a ULID |
|
|
99
|
+
| `generate_password` | Generate a secure random password |
|
|
100
|
+
|
|
101
|
+
### Text (8 tools)
|
|
102
|
+
| Tool | Description |
|
|
103
|
+
|------|-------------|
|
|
104
|
+
| `convert_case` | Convert text case: camelCase, snake_case, PascalCase, etc. |
|
|
105
|
+
| `slugify` | Convert text to a URL-friendly slug |
|
|
106
|
+
| `word_count` | Count words, characters, sentences, and reading time |
|
|
107
|
+
| `escape_string` | Escape characters for JSON, JavaScript, HTML, URL, or CSV |
|
|
108
|
+
| `unescape_string` | Unescape JSON, JavaScript, HTML, URL, or CSV strings |
|
|
109
|
+
| `lorem_ipsum` | Generate Lorem Ipsum placeholder text |
|
|
110
|
+
|
|
111
|
+
### Time (4 tools)
|
|
112
|
+
| Tool | Description |
|
|
113
|
+
|------|-------------|
|
|
114
|
+
| `unix_timestamp` | Convert a Unix timestamp to human-readable date |
|
|
115
|
+
| `parse_cron` | Parse a cron expression into a readable description |
|
|
116
|
+
| `cron_next_runs` | Show the next N scheduled run times for a cron expression |
|
|
117
|
+
| `date_diff` | Calculate the difference between two dates |
|
|
118
|
+
| `convert_timezone` | Convert a date/time between timezones |
|
|
119
|
+
|
|
120
|
+
### Units (2 tools)
|
|
121
|
+
| Tool | Description |
|
|
122
|
+
|------|-------------|
|
|
123
|
+
| `convert_bytes` | Convert between B, KB, MB, GB, TB, KiB, MiB, GiB, TiB |
|
|
124
|
+
| `px_to_units` | Convert pixels to rem, em, pt, and vw |
|
|
125
|
+
|
|
126
|
+
### API / Network (3 tools)
|
|
127
|
+
| Tool | Description |
|
|
128
|
+
|------|-------------|
|
|
129
|
+
| `decode_jwt` | Decode a JWT — header, payload, and expiry |
|
|
130
|
+
| `build_curl` | Build a cURL command from method, URL, headers, and body |
|
|
131
|
+
| `curl_to_code` | Convert a cURL command to fetch, axios, Python, Go, PHP, or Ruby |
|
|
132
|
+
|
|
133
|
+
### Color (1 tool)
|
|
134
|
+
| Tool | Description |
|
|
135
|
+
|------|-------------|
|
|
136
|
+
| `convert_color` | Convert a color between HEX, RGB, HSL, and HSV |
|
|
137
|
+
|
|
138
|
+
### Code (3 tools)
|
|
139
|
+
| Tool | Description |
|
|
140
|
+
|------|-------------|
|
|
141
|
+
| `format_sql` | Format a SQL query with proper indentation |
|
|
142
|
+
| `format_html` | Format and indent HTML markup |
|
|
143
|
+
| `test_regex` | Test a regular expression and return all matches |
|
|
144
|
+
|
|
145
|
+
### Data (3 tools)
|
|
146
|
+
| Tool | Description |
|
|
147
|
+
|------|-------------|
|
|
148
|
+
| `validate_yaml` | Validate YAML syntax |
|
|
149
|
+
| `toml_to_json` | Convert TOML to JSON |
|
|
150
|
+
| `xml_to_json` | Convert XML to JSON |
|
|
151
|
+
|
|
152
|
+
## Requirements
|
|
153
|
+
|
|
154
|
+
- Node.js 18+
|
|
155
|
+
|
|
156
|
+
## Links
|
|
157
|
+
|
|
158
|
+
- [Utilix web app](https://utilix.tech) — use these tools in the browser
|
|
159
|
+
- [Node.js SDK](https://www.npmjs.com/package/@utilix-tech/sdk) — use in your Node.js projects
|
|
160
|
+
- [Python SDK](https://pypi.org/project/utilix-sdk/) — use in your Python projects
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,743 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import {
|
|
8
|
+
parseJson,
|
|
9
|
+
minifyJson,
|
|
10
|
+
diffJson,
|
|
11
|
+
jsonToCsv,
|
|
12
|
+
csvToJson,
|
|
13
|
+
evaluateJsonPath,
|
|
14
|
+
validateJsonString,
|
|
15
|
+
yamlToJson,
|
|
16
|
+
jsonToYaml,
|
|
17
|
+
jsonToTypescript,
|
|
18
|
+
jsonToGo,
|
|
19
|
+
jsonToPython,
|
|
20
|
+
jsonToZod
|
|
21
|
+
} from "@utilix-tech/sdk/json";
|
|
22
|
+
import {
|
|
23
|
+
encodeBase64,
|
|
24
|
+
decodeBase64,
|
|
25
|
+
encodeUrl,
|
|
26
|
+
decodeUrl,
|
|
27
|
+
encodeHtmlEntities,
|
|
28
|
+
decodeHtmlEntities,
|
|
29
|
+
base32Encode,
|
|
30
|
+
base32Decode
|
|
31
|
+
} from "@utilix-tech/sdk/encoding";
|
|
32
|
+
import {
|
|
33
|
+
hashOne,
|
|
34
|
+
hashAll,
|
|
35
|
+
hashPassword,
|
|
36
|
+
verifyPassword
|
|
37
|
+
} from "@utilix-tech/sdk/hashing";
|
|
38
|
+
import {
|
|
39
|
+
generateUuid,
|
|
40
|
+
generatePassword,
|
|
41
|
+
generateUlid
|
|
42
|
+
} from "@utilix-tech/sdk/generators";
|
|
43
|
+
import {
|
|
44
|
+
countWords,
|
|
45
|
+
convertCase,
|
|
46
|
+
slugify,
|
|
47
|
+
generate as loremGenerate,
|
|
48
|
+
escapeString,
|
|
49
|
+
unescapeString
|
|
50
|
+
} from "@utilix-tech/sdk/text";
|
|
51
|
+
import {
|
|
52
|
+
fromUnix,
|
|
53
|
+
parseCron,
|
|
54
|
+
getNextRuns,
|
|
55
|
+
diffDates,
|
|
56
|
+
convertTime
|
|
57
|
+
} from "@utilix-tech/sdk/time";
|
|
58
|
+
import { convertBytes, pxToAll } from "@utilix-tech/sdk/units";
|
|
59
|
+
import {
|
|
60
|
+
decodeJwt,
|
|
61
|
+
buildCurl,
|
|
62
|
+
parseCurlCommand,
|
|
63
|
+
convertToCode
|
|
64
|
+
} from "@utilix-tech/sdk/api";
|
|
65
|
+
import { parseColor } from "@utilix-tech/sdk/color";
|
|
66
|
+
import { formatSql, formatHtml, testRegex } from "@utilix-tech/sdk/code";
|
|
67
|
+
import { validateYaml, tomlToJson, xmlToJson } from "@utilix-tech/sdk/data";
|
|
68
|
+
var CRON_DAY_MAP = {
|
|
69
|
+
SUN: "0",
|
|
70
|
+
MON: "1",
|
|
71
|
+
TUE: "2",
|
|
72
|
+
WED: "3",
|
|
73
|
+
THU: "4",
|
|
74
|
+
FRI: "5",
|
|
75
|
+
SAT: "6"
|
|
76
|
+
};
|
|
77
|
+
var CRON_MON_MAP = {
|
|
78
|
+
JAN: "1",
|
|
79
|
+
FEB: "2",
|
|
80
|
+
MAR: "3",
|
|
81
|
+
APR: "4",
|
|
82
|
+
MAY: "5",
|
|
83
|
+
JUN: "6",
|
|
84
|
+
JUL: "7",
|
|
85
|
+
AUG: "8",
|
|
86
|
+
SEP: "9",
|
|
87
|
+
OCT: "10",
|
|
88
|
+
NOV: "11",
|
|
89
|
+
DEC: "12"
|
|
90
|
+
};
|
|
91
|
+
function normalizeCron(expr) {
|
|
92
|
+
return expr.toUpperCase().replace(/\b(SUN|MON|TUE|WED|THU|FRI|SAT)\b/g, (d) => CRON_DAY_MAP[d]).replace(/\b(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)\b/g, (m) => CRON_MON_MAP[m]);
|
|
93
|
+
}
|
|
94
|
+
function text(t) {
|
|
95
|
+
return { content: [{ type: "text", text: t }] };
|
|
96
|
+
}
|
|
97
|
+
function errText(e) {
|
|
98
|
+
const msg = e instanceof Error ? e.message : typeof e === "object" && e !== null && "error" in e ? String(e.error) : String(e);
|
|
99
|
+
return { content: [{ type: "text", text: `Error: ${msg}` }], isError: true };
|
|
100
|
+
}
|
|
101
|
+
function toText(result) {
|
|
102
|
+
if (typeof result === "string") return result;
|
|
103
|
+
return JSON.stringify(result, null, 2);
|
|
104
|
+
}
|
|
105
|
+
function checkErr(result) {
|
|
106
|
+
return typeof result === "object" && result !== null && "error" in result;
|
|
107
|
+
}
|
|
108
|
+
var server = new McpServer({
|
|
109
|
+
name: "utilix",
|
|
110
|
+
version: "0.1.0"
|
|
111
|
+
});
|
|
112
|
+
server.tool(
|
|
113
|
+
"format_json",
|
|
114
|
+
"Parse, validate and pretty-print a JSON string. Returns formatted JSON or an error message.",
|
|
115
|
+
{ input: z.string().describe("JSON string to format"), indent: z.number().int().min(1).max(8).default(2).describe("Indentation spaces (default 2)") },
|
|
116
|
+
async ({ input, indent }) => {
|
|
117
|
+
const result = parseJson(input, indent);
|
|
118
|
+
if (result.status === "error") return text(`Invalid JSON: ${result.error}`);
|
|
119
|
+
return text(result.output);
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
server.tool(
|
|
123
|
+
"minify_json",
|
|
124
|
+
"Minify a JSON string by removing all whitespace.",
|
|
125
|
+
{ input: z.string().describe("JSON string to minify") },
|
|
126
|
+
async ({ input }) => {
|
|
127
|
+
const result = minifyJson(input);
|
|
128
|
+
if (checkErr(result)) return errText(result);
|
|
129
|
+
return text(result);
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
server.tool(
|
|
133
|
+
"diff_json",
|
|
134
|
+
"Compare two JSON strings and return a structured diff showing added, removed, and changed keys.",
|
|
135
|
+
{
|
|
136
|
+
left: z.string().describe("Original JSON"),
|
|
137
|
+
right: z.string().describe("New/modified JSON")
|
|
138
|
+
},
|
|
139
|
+
async ({ left, right }) => {
|
|
140
|
+
const result = diffJson(left, right);
|
|
141
|
+
if (checkErr(result)) return errText(result);
|
|
142
|
+
return text(toText(result));
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
server.tool(
|
|
146
|
+
"json_to_csv",
|
|
147
|
+
"Convert a JSON array of objects to CSV format.",
|
|
148
|
+
{ input: z.string().describe("JSON array of objects") },
|
|
149
|
+
async ({ input }) => {
|
|
150
|
+
const result = jsonToCsv(input);
|
|
151
|
+
if (checkErr(result)) return errText(result);
|
|
152
|
+
return text(result);
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
server.tool(
|
|
156
|
+
"csv_to_json",
|
|
157
|
+
"Convert CSV text to a JSON array of objects.",
|
|
158
|
+
{
|
|
159
|
+
input: z.string().describe("CSV text"),
|
|
160
|
+
delimiter: z.string().default(",").describe("Field delimiter (default comma)")
|
|
161
|
+
},
|
|
162
|
+
async ({ input, delimiter }) => {
|
|
163
|
+
const result = csvToJson(input, { delimiter });
|
|
164
|
+
if (checkErr(result)) return errText(result);
|
|
165
|
+
return text(toText(result));
|
|
166
|
+
}
|
|
167
|
+
);
|
|
168
|
+
server.tool(
|
|
169
|
+
"jsonpath",
|
|
170
|
+
"Evaluate a JSONPath expression against a JSON string and return matching values.",
|
|
171
|
+
{
|
|
172
|
+
input: z.string().describe("JSON string"),
|
|
173
|
+
path: z.string().describe("JSONPath expression e.g. $.store.book[*].author")
|
|
174
|
+
},
|
|
175
|
+
async ({ input, path }) => {
|
|
176
|
+
const result = evaluateJsonPath(input, path);
|
|
177
|
+
if (!result.valid) return text(`Error: ${result.error ?? "Invalid JSONPath"}`);
|
|
178
|
+
return text(JSON.stringify(result.results, null, 2));
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
server.tool(
|
|
182
|
+
"validate_json",
|
|
183
|
+
"Validate a JSON string against a JSON Schema (Draft-7). Returns pass/fail with error details.",
|
|
184
|
+
{
|
|
185
|
+
data: z.string().describe("JSON data to validate"),
|
|
186
|
+
schema: z.string().describe("JSON Schema string")
|
|
187
|
+
},
|
|
188
|
+
async ({ data, schema }) => {
|
|
189
|
+
let parsedSchema;
|
|
190
|
+
try {
|
|
191
|
+
parsedSchema = JSON.parse(schema);
|
|
192
|
+
} catch {
|
|
193
|
+
return errText("Invalid schema JSON");
|
|
194
|
+
}
|
|
195
|
+
const result = validateJsonString(data, parsedSchema);
|
|
196
|
+
if (checkErr(result)) return errText(result);
|
|
197
|
+
return text(toText(result));
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
server.tool(
|
|
201
|
+
"yaml_to_json",
|
|
202
|
+
"Convert a YAML string to JSON.",
|
|
203
|
+
{ input: z.string().describe("YAML string") },
|
|
204
|
+
async ({ input }) => {
|
|
205
|
+
const result = yamlToJson(input);
|
|
206
|
+
if (checkErr(result)) return errText(result);
|
|
207
|
+
return text(result);
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
server.tool(
|
|
211
|
+
"json_to_yaml",
|
|
212
|
+
"Convert a JSON string to YAML.",
|
|
213
|
+
{ input: z.string().describe("JSON string") },
|
|
214
|
+
async ({ input }) => {
|
|
215
|
+
const result = jsonToYaml(input);
|
|
216
|
+
if (checkErr(result)) return errText(result);
|
|
217
|
+
return text(result);
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
server.tool(
|
|
221
|
+
"json_to_typescript",
|
|
222
|
+
"Generate TypeScript interfaces from a JSON object.",
|
|
223
|
+
{
|
|
224
|
+
input: z.string().describe("JSON string"),
|
|
225
|
+
name: z.string().default("Root").describe("Root interface name")
|
|
226
|
+
},
|
|
227
|
+
async ({ input, name }) => {
|
|
228
|
+
const result = jsonToTypescript(input, name);
|
|
229
|
+
if (checkErr(result)) return errText(result);
|
|
230
|
+
return text(result);
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
server.tool(
|
|
234
|
+
"json_to_go",
|
|
235
|
+
"Generate Go struct definitions from a JSON object.",
|
|
236
|
+
{
|
|
237
|
+
input: z.string().describe("JSON string"),
|
|
238
|
+
name: z.string().default("Root").describe("Root struct name")
|
|
239
|
+
},
|
|
240
|
+
async ({ input, name }) => {
|
|
241
|
+
const result = jsonToGo(input, name);
|
|
242
|
+
if (checkErr(result)) return errText(result);
|
|
243
|
+
return text(result);
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
server.tool(
|
|
247
|
+
"json_to_python",
|
|
248
|
+
"Generate Python TypedDict, dataclass, or Pydantic models from a JSON object.",
|
|
249
|
+
{
|
|
250
|
+
input: z.string().describe("JSON string"),
|
|
251
|
+
style: z.enum(["typeddict", "dataclass", "pydantic"]).default("pydantic").describe("Output style")
|
|
252
|
+
},
|
|
253
|
+
async ({ input, style }) => {
|
|
254
|
+
const result = jsonToPython(input, style);
|
|
255
|
+
if (checkErr(result)) return errText(result);
|
|
256
|
+
return text(result);
|
|
257
|
+
}
|
|
258
|
+
);
|
|
259
|
+
server.tool(
|
|
260
|
+
"json_to_zod",
|
|
261
|
+
"Generate a Zod schema from a JSON object.",
|
|
262
|
+
{ input: z.string().describe("JSON string") },
|
|
263
|
+
async ({ input }) => {
|
|
264
|
+
const result = jsonToZod(input);
|
|
265
|
+
if (checkErr(result)) return errText(result);
|
|
266
|
+
return text(result);
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
server.tool(
|
|
270
|
+
"base64_encode",
|
|
271
|
+
"Encode a string to Base64.",
|
|
272
|
+
{ input: z.string().describe("String to encode") },
|
|
273
|
+
async ({ input }) => {
|
|
274
|
+
const result = encodeBase64(input);
|
|
275
|
+
return text(result.output);
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
server.tool(
|
|
279
|
+
"base64_decode",
|
|
280
|
+
"Decode a Base64 string.",
|
|
281
|
+
{ input: z.string().describe("Base64 string to decode") },
|
|
282
|
+
async ({ input }) => {
|
|
283
|
+
const result = decodeBase64(input);
|
|
284
|
+
if (!result.ok) return text(`Error: invalid Base64`);
|
|
285
|
+
return text(result.output);
|
|
286
|
+
}
|
|
287
|
+
);
|
|
288
|
+
server.tool(
|
|
289
|
+
"url_encode",
|
|
290
|
+
"Percent-encode a URL or URL component.",
|
|
291
|
+
{
|
|
292
|
+
input: z.string().describe("String to encode"),
|
|
293
|
+
mode: z.enum(["component", "full", "form"]).default("component").describe("Encoding mode")
|
|
294
|
+
},
|
|
295
|
+
async ({ input, mode }) => {
|
|
296
|
+
const result = encodeUrl(input, mode);
|
|
297
|
+
return text(result.output);
|
|
298
|
+
}
|
|
299
|
+
);
|
|
300
|
+
server.tool(
|
|
301
|
+
"url_decode",
|
|
302
|
+
"Decode a percent-encoded URL or URL component.",
|
|
303
|
+
{ input: z.string().describe("Encoded string to decode") },
|
|
304
|
+
async ({ input }) => {
|
|
305
|
+
const result = decodeUrl(input);
|
|
306
|
+
return text(result.output);
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
server.tool(
|
|
310
|
+
"html_entities_encode",
|
|
311
|
+
"Encode special characters as HTML entities (e.g. < \u2192 <).",
|
|
312
|
+
{ input: z.string().describe("HTML string to encode") },
|
|
313
|
+
async ({ input }) => text(encodeHtmlEntities(input))
|
|
314
|
+
);
|
|
315
|
+
server.tool(
|
|
316
|
+
"html_entities_decode",
|
|
317
|
+
"Decode HTML entities back to plain text (e.g. < \u2192 <).",
|
|
318
|
+
{ input: z.string().describe("String with HTML entities to decode") },
|
|
319
|
+
async ({ input }) => text(decodeHtmlEntities(input))
|
|
320
|
+
);
|
|
321
|
+
server.tool(
|
|
322
|
+
"base32_encode",
|
|
323
|
+
"Encode a string to Base32.",
|
|
324
|
+
{
|
|
325
|
+
input: z.string().describe("String to encode"),
|
|
326
|
+
alphabet: z.enum(["standard", "extendedHex", "crockford", "zbase32"]).default("standard")
|
|
327
|
+
},
|
|
328
|
+
async ({ input, alphabet }) => text(base32Encode(input, alphabet))
|
|
329
|
+
);
|
|
330
|
+
server.tool(
|
|
331
|
+
"base32_decode",
|
|
332
|
+
"Decode a Base32 string.",
|
|
333
|
+
{
|
|
334
|
+
input: z.string().describe("Base32 string to decode"),
|
|
335
|
+
alphabet: z.enum(["standard", "extendedHex", "crockford", "zbase32"]).default("standard")
|
|
336
|
+
},
|
|
337
|
+
async ({ input, alphabet }) => {
|
|
338
|
+
const result = base32Decode(input, alphabet);
|
|
339
|
+
if (checkErr(result)) return errText(result);
|
|
340
|
+
return text(result);
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
server.tool(
|
|
344
|
+
"hash",
|
|
345
|
+
"Hash a string using MD5, SHA-1, SHA-256, SHA-384, or SHA-512.",
|
|
346
|
+
{
|
|
347
|
+
input: z.string().describe("String to hash"),
|
|
348
|
+
algorithm: z.enum(["MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512"]).default("SHA-256")
|
|
349
|
+
},
|
|
350
|
+
async ({ input, algorithm }) => {
|
|
351
|
+
const result = await hashOne(algorithm, input);
|
|
352
|
+
return text(result);
|
|
353
|
+
}
|
|
354
|
+
);
|
|
355
|
+
server.tool(
|
|
356
|
+
"hash_all",
|
|
357
|
+
"Hash a string with all algorithms (MD5, SHA-1, SHA-256, SHA-384, SHA-512) at once.",
|
|
358
|
+
{ input: z.string().describe("String to hash") },
|
|
359
|
+
async ({ input }) => {
|
|
360
|
+
const results = await hashAll(input);
|
|
361
|
+
const lines = results.map((r) => `${r.algorithm.padEnd(8)}: ${r.hex}`).join("\n");
|
|
362
|
+
return text(lines);
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
server.tool(
|
|
366
|
+
"bcrypt_hash",
|
|
367
|
+
"Hash a password using bcrypt.",
|
|
368
|
+
{
|
|
369
|
+
password: z.string().describe("Password to hash"),
|
|
370
|
+
rounds: z.number().int().min(8).max(14).default(10).describe("Salt rounds (8\u201314, default 10)")
|
|
371
|
+
},
|
|
372
|
+
async ({ password, rounds }) => {
|
|
373
|
+
const hash = await hashPassword(password, rounds);
|
|
374
|
+
return text(hash);
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
server.tool(
|
|
378
|
+
"bcrypt_verify",
|
|
379
|
+
"Verify a password against a bcrypt hash.",
|
|
380
|
+
{
|
|
381
|
+
password: z.string().describe("Plain-text password"),
|
|
382
|
+
hash: z.string().describe("bcrypt hash to verify against")
|
|
383
|
+
},
|
|
384
|
+
async ({ password, hash }) => {
|
|
385
|
+
const valid = await verifyPassword(password, hash);
|
|
386
|
+
return text(valid ? "Valid \u2014 password matches hash." : "Invalid \u2014 password does not match hash.");
|
|
387
|
+
}
|
|
388
|
+
);
|
|
389
|
+
server.tool(
|
|
390
|
+
"generate_uuid",
|
|
391
|
+
"Generate one or more UUIDs (v4 random or v7 time-ordered).",
|
|
392
|
+
{
|
|
393
|
+
version: z.enum(["v4", "v7"]).default("v4").describe("UUID version"),
|
|
394
|
+
count: z.number().int().min(1).max(100).default(1).describe("How many to generate")
|
|
395
|
+
},
|
|
396
|
+
async ({ version, count }) => {
|
|
397
|
+
const ver = version === "v4" ? "v4" : "v7";
|
|
398
|
+
if (count === 1) {
|
|
399
|
+
const result = generateUuid(ver);
|
|
400
|
+
return text(result.value);
|
|
401
|
+
}
|
|
402
|
+
const uuids = [];
|
|
403
|
+
for (let i = 0; i < count; i++) uuids.push(generateUuid(ver).value);
|
|
404
|
+
return text(uuids.join("\n"));
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
server.tool(
|
|
408
|
+
"generate_ulid",
|
|
409
|
+
"Generate a ULID (Universally Unique Lexicographically Sortable Identifier).",
|
|
410
|
+
{ count: z.number().int().min(1).max(100).default(1) },
|
|
411
|
+
async ({ count }) => {
|
|
412
|
+
const ids = [];
|
|
413
|
+
for (let i = 0; i < count; i++) ids.push(generateUlid());
|
|
414
|
+
return text(ids.join("\n"));
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
server.tool(
|
|
418
|
+
"generate_password",
|
|
419
|
+
"Generate a cryptographically secure random password.",
|
|
420
|
+
{
|
|
421
|
+
length: z.number().int().min(8).max(128).default(16).describe("Password length"),
|
|
422
|
+
uppercase: z.boolean().default(true),
|
|
423
|
+
lowercase: z.boolean().default(true),
|
|
424
|
+
numbers: z.boolean().default(true),
|
|
425
|
+
symbols: z.boolean().default(true)
|
|
426
|
+
},
|
|
427
|
+
async ({ length, uppercase, lowercase, numbers, symbols }) => {
|
|
428
|
+
const result = generatePassword({ length, uppercase, lowercase, numbers, symbols });
|
|
429
|
+
return text(result);
|
|
430
|
+
}
|
|
431
|
+
);
|
|
432
|
+
server.tool(
|
|
433
|
+
"convert_case",
|
|
434
|
+
"Convert a string to a different case format: camelCase, snake_case, kebab-case, PascalCase, SCREAMING_SNAKE, Title Case, etc.",
|
|
435
|
+
{
|
|
436
|
+
input: z.string().describe("String to convert"),
|
|
437
|
+
format: z.enum([
|
|
438
|
+
"camelCase",
|
|
439
|
+
"PascalCase",
|
|
440
|
+
"snake_case",
|
|
441
|
+
"kebab-case",
|
|
442
|
+
"SCREAMING_SNAKE",
|
|
443
|
+
"Title Case",
|
|
444
|
+
"lowercase",
|
|
445
|
+
"UPPERCASE",
|
|
446
|
+
"dot.case",
|
|
447
|
+
"path/case"
|
|
448
|
+
]).describe("Target case format")
|
|
449
|
+
},
|
|
450
|
+
async ({ input, format }) => text(convertCase(input, format))
|
|
451
|
+
);
|
|
452
|
+
server.tool(
|
|
453
|
+
"slugify",
|
|
454
|
+
"Convert text to a URL-friendly slug.",
|
|
455
|
+
{
|
|
456
|
+
input: z.string().describe("Text to slugify"),
|
|
457
|
+
separator: z.enum(["-", "_"]).default("-")
|
|
458
|
+
},
|
|
459
|
+
async ({ input, separator }) => text(slugify(input, separator))
|
|
460
|
+
);
|
|
461
|
+
server.tool(
|
|
462
|
+
"word_count",
|
|
463
|
+
"Count words, characters, sentences, and estimate reading time for a block of text.",
|
|
464
|
+
{ input: z.string().describe("Text to analyze") },
|
|
465
|
+
async ({ input }) => {
|
|
466
|
+
const result = countWords(input);
|
|
467
|
+
return text(
|
|
468
|
+
`Words: ${result.words}
|
|
469
|
+
Characters: ${result.chars} (${result.charsNoSpaces} without spaces)
|
|
470
|
+
Lines: ${result.lines}
|
|
471
|
+
Sentences: ${result.sentences}
|
|
472
|
+
Reading: ~${result.readingTimeSec}s (~${Math.ceil(result.readingTimeSec / 60)} min)`
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
server.tool(
|
|
477
|
+
"escape_string",
|
|
478
|
+
"Escape special characters in a string for use in JSON, JavaScript, HTML, URL, or CSV.",
|
|
479
|
+
{
|
|
480
|
+
input: z.string().describe("String to escape"),
|
|
481
|
+
mode: z.enum(["json", "javascript", "html", "url", "csv"]).describe("Escape target format")
|
|
482
|
+
},
|
|
483
|
+
async ({ input, mode }) => text(escapeString(input, mode))
|
|
484
|
+
);
|
|
485
|
+
server.tool(
|
|
486
|
+
"unescape_string",
|
|
487
|
+
"Unescape special characters in a JSON, JavaScript, HTML, URL-encoded, or CSV string.",
|
|
488
|
+
{
|
|
489
|
+
input: z.string().describe("String to unescape"),
|
|
490
|
+
mode: z.enum(["json", "javascript", "html", "url", "csv"]).describe("Format to unescape from")
|
|
491
|
+
},
|
|
492
|
+
async ({ input, mode }) => text(unescapeString(input, mode))
|
|
493
|
+
);
|
|
494
|
+
server.tool(
|
|
495
|
+
"lorem_ipsum",
|
|
496
|
+
"Generate Lorem Ipsum placeholder text.",
|
|
497
|
+
{
|
|
498
|
+
unit: z.enum(["words", "sentences", "paragraphs"]).default("sentences"),
|
|
499
|
+
count: z.number().int().min(1).max(50).default(3)
|
|
500
|
+
},
|
|
501
|
+
async ({ unit, count }) => text(loremGenerate(unit, count))
|
|
502
|
+
);
|
|
503
|
+
server.tool(
|
|
504
|
+
"unix_timestamp",
|
|
505
|
+
"Convert a Unix timestamp (seconds or milliseconds) to a human-readable date.",
|
|
506
|
+
{ timestamp: z.number().describe("Unix timestamp in seconds or milliseconds") },
|
|
507
|
+
async ({ timestamp }) => {
|
|
508
|
+
const result = fromUnix(timestamp);
|
|
509
|
+
return text(
|
|
510
|
+
`UTC: ${result.utc}
|
|
511
|
+
ISO: ${result.iso}
|
|
512
|
+
Local: ${result.local}
|
|
513
|
+
Unix: ${result.unix} (${result.ms ? "ms" : "s"})`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
server.tool(
|
|
518
|
+
"parse_cron",
|
|
519
|
+
"Parse a cron expression and return a human-readable description.",
|
|
520
|
+
{ expression: z.string().describe('Cron expression e.g. "0 9 * * MON-FRI"') },
|
|
521
|
+
async ({ expression }) => {
|
|
522
|
+
const result = parseCron(normalizeCron(expression));
|
|
523
|
+
if (!result.valid) return text(`Invalid cron: ${result.error}`);
|
|
524
|
+
return text(result.summary ?? "Valid cron expression");
|
|
525
|
+
}
|
|
526
|
+
);
|
|
527
|
+
server.tool(
|
|
528
|
+
"cron_next_runs",
|
|
529
|
+
"Show the next N scheduled run times for a cron expression.",
|
|
530
|
+
{
|
|
531
|
+
expression: z.string().describe("Cron expression"),
|
|
532
|
+
count: z.number().int().min(1).max(20).default(5)
|
|
533
|
+
},
|
|
534
|
+
async ({ expression, count }) => {
|
|
535
|
+
const result = getNextRuns(normalizeCron(expression), count);
|
|
536
|
+
if (checkErr(result)) return errText(result);
|
|
537
|
+
const runs = result;
|
|
538
|
+
return text(runs.map((d, i) => `${i + 1}. ${d.toISOString()}`).join("\n"));
|
|
539
|
+
}
|
|
540
|
+
);
|
|
541
|
+
server.tool(
|
|
542
|
+
"date_diff",
|
|
543
|
+
"Calculate the difference between two dates.",
|
|
544
|
+
{
|
|
545
|
+
from: z.string().describe("Start date (ISO 8601 or natural language)"),
|
|
546
|
+
to: z.string().describe("End date (ISO 8601 or natural language)")
|
|
547
|
+
},
|
|
548
|
+
async ({ from, to }) => {
|
|
549
|
+
const result = diffDates(from, to);
|
|
550
|
+
if (checkErr(result)) return errText(result);
|
|
551
|
+
const r = result;
|
|
552
|
+
return text(
|
|
553
|
+
`${r.years}y ${r.months}mo ${r.days}d ${r.hours}h
|
|
554
|
+
Total days: ${r.totalDays}`
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
);
|
|
558
|
+
server.tool(
|
|
559
|
+
"convert_timezone",
|
|
560
|
+
"Convert a date/time from one timezone to another.",
|
|
561
|
+
{
|
|
562
|
+
datetime: z.string().describe("Date-time string (ISO 8601)"),
|
|
563
|
+
from_tz: z.string().describe('Source IANA timezone e.g. "UTC"'),
|
|
564
|
+
to_tz: z.string().describe('Target IANA timezone e.g. "America/New_York"')
|
|
565
|
+
},
|
|
566
|
+
async ({ datetime, from_tz, to_tz }) => {
|
|
567
|
+
const result = convertTime(datetime, from_tz, to_tz);
|
|
568
|
+
if (checkErr(result)) return errText(result);
|
|
569
|
+
const r = result;
|
|
570
|
+
return text(r.result ?? toText(result));
|
|
571
|
+
}
|
|
572
|
+
);
|
|
573
|
+
server.tool(
|
|
574
|
+
"convert_bytes",
|
|
575
|
+
"Convert a byte value between B, KB, MB, GB, TB, KiB, MiB, GiB, TiB.",
|
|
576
|
+
{
|
|
577
|
+
value: z.number().describe("Numeric value to convert"),
|
|
578
|
+
from: z.enum(["B", "KB", "MB", "GB", "TB", "PB", "KiB", "MiB", "GiB", "TiB"]).describe("Source unit")
|
|
579
|
+
},
|
|
580
|
+
async ({ value, from }) => {
|
|
581
|
+
const result = convertBytes(value, from);
|
|
582
|
+
const lines = Object.entries(result).map(([unit, r]) => `${unit.padEnd(5)}: ${r.formatted}`).join("\n");
|
|
583
|
+
return text(lines);
|
|
584
|
+
}
|
|
585
|
+
);
|
|
586
|
+
server.tool(
|
|
587
|
+
"px_to_units",
|
|
588
|
+
"Convert a px value to rem, em, pt, and vw units.",
|
|
589
|
+
{
|
|
590
|
+
px: z.number().describe("Pixel value to convert"),
|
|
591
|
+
base_font_size: z.number().default(16).describe("Base font size in px (default 16)")
|
|
592
|
+
},
|
|
593
|
+
async ({ px, base_font_size }) => {
|
|
594
|
+
const result = pxToAll(px, base_font_size);
|
|
595
|
+
const lines = Object.entries(result).map(([unit, val]) => `${unit.padEnd(6)}: ${val}`).join("\n");
|
|
596
|
+
return text(lines);
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
server.tool(
|
|
600
|
+
"decode_jwt",
|
|
601
|
+
"Decode a JWT token and display header, payload, and expiry info. Does not verify signature.",
|
|
602
|
+
{ token: z.string().describe("JWT token (3 dot-separated base64 segments)") },
|
|
603
|
+
async ({ token }) => {
|
|
604
|
+
const result = decodeJwt(token);
|
|
605
|
+
if (!result.ok) return text(`Error: ${result.error}`);
|
|
606
|
+
const lines = [];
|
|
607
|
+
lines.push("\u2500\u2500 Header \u2500\u2500");
|
|
608
|
+
lines.push(JSON.stringify(result.header, null, 2));
|
|
609
|
+
lines.push("\u2500\u2500 Payload \u2500\u2500");
|
|
610
|
+
lines.push(JSON.stringify(result.payload, null, 2));
|
|
611
|
+
if (result.expiresAt) {
|
|
612
|
+
const expired = result.expiresAt < /* @__PURE__ */ new Date();
|
|
613
|
+
lines.push(`\u2500\u2500 Expiry \u2500\u2500
|
|
614
|
+
${result.expiresAt.toISOString()} (${expired ? "EXPIRED" : "valid"})`);
|
|
615
|
+
}
|
|
616
|
+
lines.push(`Algorithm: ${result.algorithm}`);
|
|
617
|
+
return text(lines.join("\n"));
|
|
618
|
+
}
|
|
619
|
+
);
|
|
620
|
+
server.tool(
|
|
621
|
+
"build_curl",
|
|
622
|
+
"Build a cURL command from URL, method, headers, and body.",
|
|
623
|
+
{
|
|
624
|
+
url: z.string().url().describe("Request URL"),
|
|
625
|
+
method: z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]).default("GET"),
|
|
626
|
+
headers: z.record(z.string()).optional().describe("Key/value headers object"),
|
|
627
|
+
body: z.string().optional().describe("Request body string")
|
|
628
|
+
},
|
|
629
|
+
async ({ url, method, headers, body }) => {
|
|
630
|
+
const result = buildCurl({ url, method, headers: headers ? Object.entries(headers).map(([k, v]) => ({ key: k, value: v })) : [], body: body ?? "", bodyType: body ? "raw" : "none", auth: { type: "none" } });
|
|
631
|
+
return text(result);
|
|
632
|
+
}
|
|
633
|
+
);
|
|
634
|
+
server.tool(
|
|
635
|
+
"curl_to_code",
|
|
636
|
+
"Convert a cURL command to code: fetch, axios, python-requests, go-http, php-curl, or ruby-net-http.",
|
|
637
|
+
{
|
|
638
|
+
curl: z.string().describe("Full cURL command string"),
|
|
639
|
+
language: z.enum(["fetch", "axios", "python-requests", "go-http", "php-curl", "ruby-net-http"]).describe("Target language/library")
|
|
640
|
+
},
|
|
641
|
+
async ({ curl, language }) => {
|
|
642
|
+
const parsed = parseCurlCommand(curl);
|
|
643
|
+
if (checkErr(parsed)) return errText(parsed);
|
|
644
|
+
const result = convertToCode(parsed, language);
|
|
645
|
+
if (!result) return text("Error: could not convert cURL to code");
|
|
646
|
+
return text(result);
|
|
647
|
+
}
|
|
648
|
+
);
|
|
649
|
+
server.tool(
|
|
650
|
+
"convert_color",
|
|
651
|
+
"Parse a color (HEX, RGB, HSL, HSV, or named CSS color) and return all format conversions.",
|
|
652
|
+
{ input: z.string().describe('Color value e.g. "#ff6b35", "rgb(255,107,53)", "hsl(18,100%,60%)"') },
|
|
653
|
+
async ({ input }) => {
|
|
654
|
+
const result = parseColor(input);
|
|
655
|
+
if (!result.valid) return text(`Error: cannot parse color "${input}"`);
|
|
656
|
+
const c = result;
|
|
657
|
+
return text(
|
|
658
|
+
`HEX: ${c.hex}
|
|
659
|
+
RGB: rgb(${c.rgb.r}, ${c.rgb.g}, ${c.rgb.b})
|
|
660
|
+
HSL: hsl(${c.hsl.h}, ${c.hsl.s}%, ${c.hsl.l}%)
|
|
661
|
+
HSV: hsv(${c.hsv.h}, ${c.hsv.s}%, ${c.hsv.v}%)`
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
);
|
|
665
|
+
server.tool(
|
|
666
|
+
"format_sql",
|
|
667
|
+
"Format a SQL query with proper indentation and keyword uppercasing.",
|
|
668
|
+
{
|
|
669
|
+
input: z.string().describe("SQL query to format"),
|
|
670
|
+
uppercase: z.boolean().default(true).describe("Uppercase SQL keywords")
|
|
671
|
+
},
|
|
672
|
+
async ({ input, uppercase }) => {
|
|
673
|
+
const result = formatSql(input, { uppercase });
|
|
674
|
+
return text(result);
|
|
675
|
+
}
|
|
676
|
+
);
|
|
677
|
+
server.tool(
|
|
678
|
+
"format_html",
|
|
679
|
+
"Format and indent HTML markup.",
|
|
680
|
+
{
|
|
681
|
+
input: z.string().describe("HTML string to format"),
|
|
682
|
+
indent: z.number().int().min(1).max(8).default(2)
|
|
683
|
+
},
|
|
684
|
+
async ({ input, indent }) => {
|
|
685
|
+
const result = formatHtml(input, indent);
|
|
686
|
+
if (checkErr(result)) return errText(result);
|
|
687
|
+
return text(result.output ?? toText(result));
|
|
688
|
+
}
|
|
689
|
+
);
|
|
690
|
+
server.tool(
|
|
691
|
+
"test_regex",
|
|
692
|
+
"Test a regular expression against an input string and return all matches with capture groups.",
|
|
693
|
+
{
|
|
694
|
+
pattern: z.string().describe("Regex pattern (without slashes)"),
|
|
695
|
+
flags: z.string().default("g").describe('Regex flags: g, i, m, s, u (default "g")'),
|
|
696
|
+
input: z.string().describe("String to test the pattern against")
|
|
697
|
+
},
|
|
698
|
+
async ({ pattern, flags, input }) => {
|
|
699
|
+
const result = testRegex(pattern, flags.split(""), input);
|
|
700
|
+
if (checkErr(result)) return errText(result);
|
|
701
|
+
const r = result;
|
|
702
|
+
if (r.matchCount === 0) return text("No matches found.");
|
|
703
|
+
const lines = [`${r.matchCount} match${r.matchCount > 1 ? "es" : ""}:`];
|
|
704
|
+
r.matches.forEach((m, i) => {
|
|
705
|
+
lines.push(` ${i + 1}. "${m.fullMatch}" at index ${m.index}${m.groups.length ? ` (groups: ${m.groups.join(", ")})` : ""}`);
|
|
706
|
+
});
|
|
707
|
+
return text(lines.join("\n"));
|
|
708
|
+
}
|
|
709
|
+
);
|
|
710
|
+
server.tool(
|
|
711
|
+
"validate_yaml",
|
|
712
|
+
"Validate YAML syntax and return stats or error details.",
|
|
713
|
+
{ input: z.string().describe("YAML string to validate") },
|
|
714
|
+
async ({ input }) => {
|
|
715
|
+
const result = validateYaml(input);
|
|
716
|
+
if (!result.valid) return text(`Invalid YAML`);
|
|
717
|
+
return text(`Valid YAML
|
|
718
|
+
Documents: ${result.documentCount}
|
|
719
|
+
Keys: ${result.keyCount}`);
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
server.tool(
|
|
723
|
+
"toml_to_json",
|
|
724
|
+
"Convert a TOML string to JSON.",
|
|
725
|
+
{ input: z.string().describe("TOML string") },
|
|
726
|
+
async ({ input }) => {
|
|
727
|
+
const result = tomlToJson(input);
|
|
728
|
+
if (checkErr(result)) return errText(result);
|
|
729
|
+
return text(result);
|
|
730
|
+
}
|
|
731
|
+
);
|
|
732
|
+
server.tool(
|
|
733
|
+
"xml_to_json",
|
|
734
|
+
"Convert an XML document to JSON.",
|
|
735
|
+
{ input: z.string().describe("XML string") },
|
|
736
|
+
async ({ input }) => {
|
|
737
|
+
const result = xmlToJson(input);
|
|
738
|
+
if (checkErr(result)) return errText(result);
|
|
739
|
+
return text(result);
|
|
740
|
+
}
|
|
741
|
+
);
|
|
742
|
+
var transport = new StdioServerTransport();
|
|
743
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@utilix-tech/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server exposing 107 Utilix developer tools to Claude, Cursor, VS Code Copilot, and any MCP-compatible AI assistant.",
|
|
5
|
+
"author": "Utilix <hello@utilix.tech>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://utilix.tech/docs",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"model-context-protocol",
|
|
11
|
+
"developer-tools",
|
|
12
|
+
"utilities",
|
|
13
|
+
"claude",
|
|
14
|
+
"cursor",
|
|
15
|
+
"copilot",
|
|
16
|
+
"json",
|
|
17
|
+
"encoding",
|
|
18
|
+
"hashing",
|
|
19
|
+
"utilix"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"bin": {
|
|
27
|
+
"utilix-mcp": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"smithery.yaml",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"dev": "tsup --watch",
|
|
37
|
+
"start": "node dist/index.js",
|
|
38
|
+
"prepublishOnly": "npm run build"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
42
|
+
"@utilix-tech/sdk": "^0.1.4",
|
|
43
|
+
"zod": "^3.23.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^20.0.0",
|
|
47
|
+
"tsup": "^8.0.0",
|
|
48
|
+
"typescript": "^5.4.0"
|
|
49
|
+
}
|
|
50
|
+
}
|
package/smithery.yaml
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: utilix
|
|
2
|
+
description: 107 developer utility tools — JSON, hashing, encoding, JWT, UUID, cron, color, SQL, regex and more. All run locally, no API key required.
|
|
3
|
+
homepage: https://utilix.tech
|
|
4
|
+
license: MIT
|
|
5
|
+
|
|
6
|
+
startCommand:
|
|
7
|
+
type: stdio
|
|
8
|
+
command: npx
|
|
9
|
+
args:
|
|
10
|
+
- "@utilix-tech/mcp"
|
|
11
|
+
|
|
12
|
+
tools:
|
|
13
|
+
- format_json
|
|
14
|
+
- minify_json
|
|
15
|
+
- diff_json
|
|
16
|
+
- json_to_csv
|
|
17
|
+
- csv_to_json
|
|
18
|
+
- jsonpath
|
|
19
|
+
- validate_json
|
|
20
|
+
- yaml_to_json
|
|
21
|
+
- json_to_yaml
|
|
22
|
+
- json_to_typescript
|
|
23
|
+
- json_to_go
|
|
24
|
+
- json_to_python
|
|
25
|
+
- json_to_zod
|
|
26
|
+
- base64_encode
|
|
27
|
+
- base64_decode
|
|
28
|
+
- url_encode
|
|
29
|
+
- url_decode
|
|
30
|
+
- html_entities_encode
|
|
31
|
+
- html_entities_decode
|
|
32
|
+
- base32_encode
|
|
33
|
+
- base32_decode
|
|
34
|
+
- hash
|
|
35
|
+
- hash_all
|
|
36
|
+
- bcrypt_hash
|
|
37
|
+
- bcrypt_verify
|
|
38
|
+
- generate_uuid
|
|
39
|
+
- generate_ulid
|
|
40
|
+
- generate_password
|
|
41
|
+
- convert_case
|
|
42
|
+
- slugify
|
|
43
|
+
- word_count
|
|
44
|
+
- escape_string
|
|
45
|
+
- unescape_string
|
|
46
|
+
- lorem_ipsum
|
|
47
|
+
- unix_timestamp
|
|
48
|
+
- parse_cron
|
|
49
|
+
- cron_next_runs
|
|
50
|
+
- date_diff
|
|
51
|
+
- convert_timezone
|
|
52
|
+
- convert_bytes
|
|
53
|
+
- px_to_units
|
|
54
|
+
- decode_jwt
|
|
55
|
+
- build_curl
|
|
56
|
+
- curl_to_code
|
|
57
|
+
- convert_color
|
|
58
|
+
- format_sql
|
|
59
|
+
- format_html
|
|
60
|
+
- test_regex
|
|
61
|
+
- validate_yaml
|
|
62
|
+
- toml_to_json
|
|
63
|
+
- xml_to_json
|