@utilix-tech/mcp 0.2.0 → 0.3.1
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 +53 -1
- package/dist/index.js +116 -0
- package/package.json +3 -3
- package/smithery.yaml +3 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/mcp
|
|
2
2
|
|
|
3
|
-
MCP server exposing
|
|
3
|
+
MCP server exposing 95 developer utility tools to Claude, Cursor, VS Code Copilot, and any [Model Context Protocol](https://modelcontextprotocol.io) compatible AI assistant.
|
|
4
4
|
|
|
5
5
|
No API key required. All tools run locally.
|
|
6
6
|
|
|
@@ -52,6 +52,27 @@ Add to `.vscode/mcp.json`:
|
|
|
52
52
|
}
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
### Windsurf
|
|
56
|
+
|
|
57
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"utilix": {
|
|
63
|
+
"command": "npx",
|
|
64
|
+
"args": ["-y", "@utilix-tech/mcp"]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Claude Code
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
claude mcp add utilix -- npx -y @utilix-tech/mcp
|
|
74
|
+
```
|
|
75
|
+
|
|
55
76
|
## Tools
|
|
56
77
|
|
|
57
78
|
### JSON (13 tools)
|
|
@@ -176,6 +197,35 @@ Add to `.vscode/mcp.json`:
|
|
|
176
197
|
| `unicode_inspect` | Inspect Unicode code points of a string |
|
|
177
198
|
| `optimize_svg` | Optimize and minify an SVG string |
|
|
178
199
|
|
|
200
|
+
### AI / Agent (25 tools)
|
|
201
|
+
| Tool | Description |
|
|
202
|
+
|------|-------------|
|
|
203
|
+
| `estimate_tokens` | Estimate token count and cost for an LLM prompt |
|
|
204
|
+
| `trim_to_tokens` | Trim text to fit a token budget |
|
|
205
|
+
| `chunk_text` | Split text into overlapping chunks for RAG pipelines |
|
|
206
|
+
| `rerank_chunks` | Rerank retrieved chunks by relevance to a query |
|
|
207
|
+
| `score_relevance` | Score a chunk's relevance to a query |
|
|
208
|
+
| `expand_query` | Expand a search query with synonyms/related terms |
|
|
209
|
+
| `summarize_for_llm` | Summarize text to fit a target length or token budget |
|
|
210
|
+
| `detect_pii` | Find emails, phones, SSNs, credit cards in text |
|
|
211
|
+
| `detect_secrets` | Scan text for leaked API keys, tokens, passwords |
|
|
212
|
+
| `detect_prompt_injection` | Score and flag adversarial/injection-style inputs |
|
|
213
|
+
| `repair_json` | Fix malformed JSON with a list of applied fixes |
|
|
214
|
+
| `sanitize_html` | Strip unsafe tags/attributes from HTML |
|
|
215
|
+
| `flatten_json` | Flatten nested JSON into dot-notation keys |
|
|
216
|
+
| `merge_json` | Deep or shallow merge two JSON objects |
|
|
217
|
+
| `extract_json` | Extract JSON blocks embedded in free text |
|
|
218
|
+
| `extract_urls` | Extract all URLs from text |
|
|
219
|
+
| `extract_entities` | Extract named entities from text |
|
|
220
|
+
| `extract_keywords` | Extract keywords from text |
|
|
221
|
+
| `extract_tables` | Extract tabular data from text |
|
|
222
|
+
| `deduplicate_lines` | Remove duplicate lines from text |
|
|
223
|
+
| `validate_json_schema` | Validate JSON against a JSON Schema |
|
|
224
|
+
| `compress_html` | Compress HTML for LLM context budgets |
|
|
225
|
+
| `compress_markdown` | Compress Markdown for LLM context budgets |
|
|
226
|
+
| `compress_json` | Compress JSON for LLM context budgets |
|
|
227
|
+
| `diff_json_detailed` | Diff two parsed JSON values, returning every path with its op and unchanged paths |
|
|
228
|
+
|
|
179
229
|
## Requirements
|
|
180
230
|
|
|
181
231
|
- Node.js 18+
|
|
@@ -183,5 +233,7 @@ Add to `.vscode/mcp.json`:
|
|
|
183
233
|
## Links
|
|
184
234
|
|
|
185
235
|
- [Utilix web app](https://utilix.tech) — use these tools in the browser
|
|
236
|
+
- [API Playground](https://utilix.tech/api) — try 10 endpoints live, no signup required
|
|
237
|
+
- [REST API docs](https://utilix.tech/docs#rest-api) — 100+ endpoints at `api.utilix.tech/v1` (1,000 req/day free)
|
|
186
238
|
- [Node.js SDK](https://www.npmjs.com/package/@utilix-tech/sdk) — use in your Node.js projects
|
|
187
239
|
- [Python SDK](https://pypi.org/project/utilix-sdk/) — use in your Python projects
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,7 @@ import { formatSql, formatHtml, testRegex, minifyJs, formatGql, parseDockerImage
|
|
|
74
74
|
import { validateYaml, tomlToJson, xmlToJson, parseCsv } from "@utilix-tech/sdk/data";
|
|
75
75
|
import { generateGradient, minifyCss } from "@utilix-tech/sdk/css";
|
|
76
76
|
import { optimizeSvg, charToCodePoint, numberToWords } from "@utilix-tech/sdk/misc";
|
|
77
|
+
import { estimateTokens, estimateCost, detectPii, redactPii, detectSecrets, detectPromptInjection, repairJson, trimToTokens, chunkText, extractUrls, sanitizeHtml, flattenJson, unflattenJson, mergeJson, extractJson, deduplicateLines, extractKeywords, validateJsonSchema, diffJson as diffJsonDetailed, extractTables, extractEntities, compressHtml, compressMarkdown, compressJson, rerankChunks, scoreRelevance, expandQuery, summarizeForLlm } from "@utilix-tech/sdk/ai_agent";
|
|
77
78
|
var CRON_DAY_MAP = {
|
|
78
79
|
SUN: "0",
|
|
79
80
|
MON: "1",
|
|
@@ -1027,5 +1028,120 @@ server.tool(
|
|
|
1027
1028
|
(${original}B \u2192 ${optimized}B, saved ${saved}%)`);
|
|
1028
1029
|
}
|
|
1029
1030
|
);
|
|
1031
|
+
server.tool(
|
|
1032
|
+
"estimate_tokens",
|
|
1033
|
+
"Estimate the token count and API cost for a text string across popular LLMs (GPT-4o, Claude, Gemini, etc.).",
|
|
1034
|
+
{
|
|
1035
|
+
text: z.string().describe("Text to estimate tokens for"),
|
|
1036
|
+
model: z.string().optional().describe("Model slug (e.g. gpt-4o, claude-sonnet-4) \u2014 omit for all models"),
|
|
1037
|
+
output_tokens: z.number().int().min(0).optional().describe("Expected output tokens (defaults to same as input)")
|
|
1038
|
+
},
|
|
1039
|
+
async ({ text: text2, model, output_tokens }) => {
|
|
1040
|
+
const est = estimateTokens(text2);
|
|
1041
|
+
const result = estimateCost(est.tokens, output_tokens, model);
|
|
1042
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1043
|
+
}
|
|
1044
|
+
);
|
|
1045
|
+
server.tool(
|
|
1046
|
+
"detect_pii",
|
|
1047
|
+
"Detect personally identifiable information (emails, phones, SSNs, credit cards, IPs, IBANs, crypto wallets) in text.",
|
|
1048
|
+
{
|
|
1049
|
+
text: z.string().describe("Text to scan for PII"),
|
|
1050
|
+
redact: z.boolean().default(false).describe("If true, return redacted text instead of findings list"),
|
|
1051
|
+
replacement: z.string().default("[REDACTED]").describe("Replacement string when redacting")
|
|
1052
|
+
},
|
|
1053
|
+
async ({ text: text2, redact, replacement }) => {
|
|
1054
|
+
const result = redact ? redactPii(text2, replacement) : detectPii(text2);
|
|
1055
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1056
|
+
}
|
|
1057
|
+
);
|
|
1058
|
+
server.tool(
|
|
1059
|
+
"detect_secrets",
|
|
1060
|
+
"Scan text for leaked API keys, tokens, and credentials (OpenAI, Anthropic, AWS, GitHub, Stripe, etc.).",
|
|
1061
|
+
{ text: z.string().describe("Text or code to scan for secrets") },
|
|
1062
|
+
async ({ text: text2 }) => {
|
|
1063
|
+
const result = detectSecrets(text2);
|
|
1064
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1065
|
+
}
|
|
1066
|
+
);
|
|
1067
|
+
server.tool(
|
|
1068
|
+
"detect_prompt_injection",
|
|
1069
|
+
"Detect prompt injection and jailbreak attempts in user-provided text before passing to an LLM.",
|
|
1070
|
+
{ text: z.string().describe("User-provided text to check for injection attempts") },
|
|
1071
|
+
async ({ text: text2 }) => {
|
|
1072
|
+
const result = detectPromptInjection(text2);
|
|
1073
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1074
|
+
}
|
|
1075
|
+
);
|
|
1076
|
+
server.tool(
|
|
1077
|
+
"repair_json",
|
|
1078
|
+
"Fix malformed JSON: unquoted keys, single quotes, trailing commas, JS comments, undefined/NaN values, unclosed brackets.",
|
|
1079
|
+
{ input: z.string().describe("Malformed JSON string to repair") },
|
|
1080
|
+
async ({ input }) => {
|
|
1081
|
+
const result = repairJson(input);
|
|
1082
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1083
|
+
}
|
|
1084
|
+
);
|
|
1085
|
+
server.tool("trim_to_tokens", "Truncate text to a token budget (end/start/middle strategy).", { text: z.string(), max_tokens: z.number().int().min(1), strategy: z.enum(["end", "start", "middle"]).default("end") }, async ({ text: text2, max_tokens, strategy }) => {
|
|
1086
|
+
return { content: [{ type: "text", text: JSON.stringify(trimToTokens(text2, max_tokens, strategy), null, 2) }] };
|
|
1087
|
+
});
|
|
1088
|
+
server.tool("chunk_text", "Split text into overlapping chunks for RAG.", { text: z.string(), chunk_size: z.number().int().min(10).default(200), overlap: z.number().int().min(0).default(20), strategy: z.enum(["paragraph", "sentence", "fixed"]).default("paragraph") }, async ({ text: text2, chunk_size, overlap, strategy }) => {
|
|
1089
|
+
return { content: [{ type: "text", text: JSON.stringify(chunkText(text2, chunk_size, overlap, strategy), null, 2) }] };
|
|
1090
|
+
});
|
|
1091
|
+
server.tool("extract_urls", "Extract all URLs from text or HTML.", { text: z.string() }, async ({ text: text2 }) => {
|
|
1092
|
+
return { content: [{ type: "text", text: JSON.stringify(extractUrls(text2), null, 2) }] };
|
|
1093
|
+
});
|
|
1094
|
+
server.tool("sanitize_html", "Strip HTML tags, scripts, and event handlers for LLM ingestion.", { html: z.string(), keep_links: z.boolean().default(false) }, async ({ html, keep_links }) => {
|
|
1095
|
+
return { content: [{ type: "text", text: JSON.stringify(sanitizeHtml(html, keep_links), null, 2) }] };
|
|
1096
|
+
});
|
|
1097
|
+
server.tool("flatten_json", "Flatten nested JSON to dot-notation keys.", { json: z.unknown(), separator: z.string().default("."), unflatten: z.boolean().default(false) }, async ({ json, separator, unflatten }) => {
|
|
1098
|
+
const result = unflatten ? unflattenJson(json, separator) : flattenJson(json, separator);
|
|
1099
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
1100
|
+
});
|
|
1101
|
+
server.tool("merge_json", "Deep merge two JSON objects.", { base: z.unknown(), override: z.unknown(), strategy: z.enum(["deep", "shallow", "replace-arrays"]).default("deep") }, async ({ base, override, strategy }) => {
|
|
1102
|
+
return { content: [{ type: "text", text: JSON.stringify(mergeJson(base, override, strategy), null, 2) }] };
|
|
1103
|
+
});
|
|
1104
|
+
server.tool("extract_json", "Extract JSON blocks from mixed LLM output text.", { text: z.string() }, async ({ text: text2 }) => {
|
|
1105
|
+
return { content: [{ type: "text", text: JSON.stringify(extractJson(text2), null, 2) }] };
|
|
1106
|
+
});
|
|
1107
|
+
server.tool("deduplicate_lines", "Remove duplicate lines from text.", { text: z.string(), strategy: z.enum(["exact", "case-insensitive", "trimmed", "normalized"]).default("exact") }, async ({ text: text2, strategy }) => {
|
|
1108
|
+
return { content: [{ type: "text", text: JSON.stringify(deduplicateLines(text2, strategy), null, 2) }] };
|
|
1109
|
+
});
|
|
1110
|
+
server.tool("extract_keywords", "Extract top keywords using TF-IDF scoring.", { text: z.string(), max_keywords: z.number().int().min(1).max(100).default(20), min_word_len: z.number().int().min(2).default(3) }, async ({ text: text2, max_keywords, min_word_len }) => {
|
|
1111
|
+
return { content: [{ type: "text", text: JSON.stringify(extractKeywords(text2, max_keywords, min_word_len), null, 2) }] };
|
|
1112
|
+
});
|
|
1113
|
+
server.tool("validate_json_schema", "Validate JSON data against a JSON Schema (Draft-07).", { data: z.unknown(), schema: z.record(z.unknown()) }, async ({ data, schema }) => {
|
|
1114
|
+
return { content: [{ type: "text", text: JSON.stringify(validateJsonSchema(data, schema), null, 2) }] };
|
|
1115
|
+
});
|
|
1116
|
+
server.tool("diff_json_detailed", "Diff two JSON objects (parsed values, not strings) \u2014 returns a flat list of every path with its op (added/removed/changed/unchanged), plus counts.", { a: z.unknown(), b: z.unknown() }, async ({ a, b }) => {
|
|
1117
|
+
return { content: [{ type: "text", text: JSON.stringify(diffJsonDetailed(a, b), null, 2) }] };
|
|
1118
|
+
});
|
|
1119
|
+
server.tool("extract_tables", "Extract HTML tables into JSON arrays with headers and rows.", { html: z.string() }, async ({ html }) => {
|
|
1120
|
+
return { content: [{ type: "text", text: JSON.stringify(extractTables(html), null, 2) }] };
|
|
1121
|
+
});
|
|
1122
|
+
server.tool("extract_entities", "Extract emails, phones, dates, IPs, currencies, hashtags from text.", { text: z.string() }, async ({ text: text2 }) => {
|
|
1123
|
+
return { content: [{ type: "text", text: JSON.stringify(extractEntities(text2), null, 2) }] };
|
|
1124
|
+
});
|
|
1125
|
+
server.tool("compress_html", "Strip scripts, styles, classes, and whitespace from HTML to minimize tokens.", { html: z.string(), remove_comments: z.boolean().default(true), remove_scripts: z.boolean().default(true), remove_styles: z.boolean().default(true), collapse_whitespace: z.boolean().default(true) }, async ({ html, remove_comments, remove_scripts, remove_styles, collapse_whitespace }) => {
|
|
1126
|
+
return { content: [{ type: "text", text: JSON.stringify(compressHtml(html, { removeComments: remove_comments, removeScripts: remove_scripts, removeStyles: remove_styles, collapseWhitespace: collapse_whitespace }), null, 2) }] };
|
|
1127
|
+
});
|
|
1128
|
+
server.tool("compress_markdown", "Normalize and compress markdown to reduce token count.", { markdown: z.string(), collapse_blank_lines: z.boolean().default(true), remove_comments: z.boolean().default(true), strip_frontmatter: z.boolean().default(false) }, async ({ markdown, collapse_blank_lines, remove_comments, strip_frontmatter }) => {
|
|
1129
|
+
return { content: [{ type: "text", text: JSON.stringify(compressMarkdown(markdown, { collapseBlankLines: collapse_blank_lines, removeComments: remove_comments, stripFrontmatter: strip_frontmatter }), null, 2) }] };
|
|
1130
|
+
});
|
|
1131
|
+
server.tool("compress_json", "Remove nulls, empty arrays, and empty objects from JSON to reduce tokens.", { json: z.unknown(), remove_nulls: z.boolean().default(true), remove_empty_arrays: z.boolean().default(true), remove_empty_objects: z.boolean().default(true), sort_keys: z.boolean().default(false) }, async ({ json, remove_nulls, remove_empty_arrays, remove_empty_objects, sort_keys }) => {
|
|
1132
|
+
return { content: [{ type: "text", text: JSON.stringify(compressJson(json, { removeNulls: remove_nulls, removeEmptyArrays: remove_empty_arrays, removeEmptyObjects: remove_empty_objects, sortKeys: sort_keys }), null, 2) }] };
|
|
1133
|
+
});
|
|
1134
|
+
server.tool("rerank_chunks", "Score and rerank text chunks by TF-IDF relevance to a query.", { query: z.string(), chunks: z.array(z.string()), top_k: z.number().int().min(1).optional() }, async ({ query, chunks, top_k }) => {
|
|
1135
|
+
return { content: [{ type: "text", text: JSON.stringify(rerankChunks(query, chunks, top_k), null, 2) }] };
|
|
1136
|
+
});
|
|
1137
|
+
server.tool("score_relevance", "Score a passage relevance to a query (0-1 score with grade).", { query: z.string(), passage: z.string() }, async ({ query, passage }) => {
|
|
1138
|
+
return { content: [{ type: "text", text: JSON.stringify(scoreRelevance(query, passage), null, 2) }] };
|
|
1139
|
+
});
|
|
1140
|
+
server.tool("expand_query", "Expand a search query with synonyms and stemmed variants for better retrieval.", { query: z.string(), max_synonyms: z.number().int().min(1).max(5).default(2) }, async ({ query, max_synonyms }) => {
|
|
1141
|
+
return { content: [{ type: "text", text: JSON.stringify(expandQuery(query, max_synonyms), null, 2) }] };
|
|
1142
|
+
});
|
|
1143
|
+
server.tool("summarize_for_llm", "Extractive summarization \u2014 pick key sentences to fit a token budget.", { text: z.string(), max_tokens: z.number().int().min(10).default(200), strategy: z.enum(["extractive", "first", "last"]).default("extractive") }, async ({ text: text2, max_tokens, strategy }) => {
|
|
1144
|
+
return { content: [{ type: "text", text: JSON.stringify(summarizeForLlm(text2, max_tokens, strategy), null, 2) }] };
|
|
1145
|
+
});
|
|
1030
1146
|
var transport = new StdioServerTransport();
|
|
1031
1147
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilix-tech/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server exposing
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "MCP server exposing 95 Utilix developer tools to Claude, Cursor, VS Code Copilot, and any MCP-compatible AI assistant.",
|
|
5
5
|
"author": "Utilix <hello@utilix.tech>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://utilix.tech/docs",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"README.md"
|
|
33
33
|
],
|
|
34
34
|
"scripts": {
|
|
35
|
-
"build": "tsup",
|
|
35
|
+
"build": "tsup && chmod +x dist/index.js",
|
|
36
36
|
"dev": "tsup --watch",
|
|
37
37
|
"start": "node dist/index.js",
|
|
38
38
|
"prepublishOnly": "npm run build"
|
package/smithery.yaml
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
name: utilix
|
|
2
|
-
description: 70 developer utility tools
|
|
3
|
-
homepage: https://utilix.tech
|
|
2
|
+
description: 70 developer utility tools for Claude, Cursor, VS Code, Windsurf, and any MCP-compatible AI assistant. Covers JSON, hashing, encoding, JWT, UUID, cron, color, SQL, regex, CSS, QR codes, and more. All tools run locally — no API key required.
|
|
3
|
+
homepage: https://utilix.tech/mcp
|
|
4
4
|
license: MIT
|
|
5
|
+
repository: https://github.com/utilix-tech/utilix-mcp
|
|
5
6
|
|
|
6
7
|
startCommand:
|
|
7
8
|
type: stdio
|