@utilix-tech/mcp 0.32.0 → 0.33.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/CHANGELOG.md +4 -0
- package/README.md +5 -3
- package/dist/index.js +92 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Full release notes for all Utilix surfaces (browser tools, REST API, SDKs, MCP server) live at [utilix.tech/changelog](https://utilix.tech/changelog). This file tracks just this package.
|
|
4
4
|
|
|
5
|
+
## 0.33.0
|
|
6
|
+
- Add `analyze_sentence_lengths` tool: histogram of sentence lengths in words, plus mean, median, standard deviation, and a coefficient-of-variation consistency label, distinct from readability grade scores.
|
|
7
|
+
- Add `format_few_shot_examples` tool: format input/output example pairs into a numbered, XML-tagged, or delimiter-separated few-shot prompt template.
|
|
8
|
+
|
|
5
9
|
## 0.32.0
|
|
6
10
|
- Add `calculate_emi` tool: equated monthly installment, total interest, and a year-by-year principal/interest breakdown from principal, annual rate, and tenure in years or months.
|
|
7
11
|
- Add `parse_markdown_front_matter` tool: split a Markdown document into its YAML front matter fields and body content, parsing scalars, inline arrays, and block lists.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/mcp
|
|
2
2
|
|
|
3
|
-
MCP server exposing
|
|
3
|
+
MCP server exposing 152 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. Requires Node.js 18 or later.
|
|
6
6
|
|
|
@@ -128,7 +128,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
|
|
|
128
128
|
| `generate_qr` | Generate a QR code as an SVG string |
|
|
129
129
|
| `generate_random_data` | Generate random mock data: names, emails, UUIDs, IPs, etc. |
|
|
130
130
|
|
|
131
|
-
### Text (
|
|
131
|
+
### Text (14 tools)
|
|
132
132
|
| Tool | Description |
|
|
133
133
|
|------|-------------|
|
|
134
134
|
| `convert_case` | Convert text case: camelCase, snake_case, PascalCase, etc. |
|
|
@@ -144,6 +144,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
|
|
|
144
144
|
| `score_readability` | Score text with Flesch Reading Ease, Flesch-Kincaid Grade Level, and Gunning Fog Index |
|
|
145
145
|
| `detect_filler_words` | Scan text for filler words, hedge phrases, and clichés with per-phrase counts and a density score |
|
|
146
146
|
| `calculate_string_distance` | Compute the Levenshtein (or Damerau) edit distance and normalized similarity between two strings |
|
|
147
|
+
| `analyze_sentence_lengths` | Split text into sentences and report a histogram of sentence lengths, plus mean, median, standard deviation, and a consistency label |
|
|
147
148
|
|
|
148
149
|
### Time (6 tools)
|
|
149
150
|
| Tool | Description |
|
|
@@ -242,7 +243,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
|
|
|
242
243
|
| `unicode_inspect` | Inspect Unicode code points of a string |
|
|
243
244
|
| `optimize_svg` | Optimize and minify an SVG string |
|
|
244
245
|
|
|
245
|
-
### AI / Agent (
|
|
246
|
+
### AI / Agent (27 tools)
|
|
246
247
|
| Tool | Description |
|
|
247
248
|
|------|-------------|
|
|
248
249
|
| `estimate_tokens` | Estimate token count and cost for an LLM prompt |
|
|
@@ -271,6 +272,7 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
|
|
|
271
272
|
| `compress_json` | Compress JSON for LLM context budgets |
|
|
272
273
|
| `diff_json_detailed` | Diff two parsed JSON values, returning every path with its op and unchanged paths |
|
|
273
274
|
| `vector_similarity` | Cosine similarity, dot product, and Euclidean / Manhattan distance between two numeric vectors |
|
|
275
|
+
| `format_few_shot_examples` | Format input/output example pairs into a numbered, XML-tagged, or delimiter-separated few-shot prompt template |
|
|
274
276
|
|
|
275
277
|
### Image (3 tools)
|
|
276
278
|
| Tool | Description |
|
package/dist/index.js
CHANGED
|
@@ -1092,6 +1092,30 @@ server.tool("chunk_text", "Split text into overlapping chunks for RAG.", { text:
|
|
|
1092
1092
|
server.tool("extract_urls", "Extract all URLs from text or HTML.", { text: z.string() }, async ({ text: text2 }) => {
|
|
1093
1093
|
return { content: [{ type: "text", text: JSON.stringify(extractUrls(text2), null, 2) }] };
|
|
1094
1094
|
});
|
|
1095
|
+
function _formatFewShotExamples(examples, format, delimiter) {
|
|
1096
|
+
const valid = (examples ?? []).filter((e) => e?.input?.trim() && e?.output?.trim());
|
|
1097
|
+
if (valid.length === 0) return { formatted: "", exampleCount: 0, format };
|
|
1098
|
+
let formatted;
|
|
1099
|
+
if (format === "xml") {
|
|
1100
|
+
formatted = valid.map((e) => `<example>
|
|
1101
|
+
<input>${e.input.trim()}</input>
|
|
1102
|
+
<output>${e.output.trim()}</output>
|
|
1103
|
+
</example>`).join("\n\n");
|
|
1104
|
+
} else if (format === "delimiter") {
|
|
1105
|
+
formatted = valid.map((e) => `Input: ${e.input.trim()}
|
|
1106
|
+
Output: ${e.output.trim()}`).join(`
|
|
1107
|
+
${delimiter}
|
|
1108
|
+
`);
|
|
1109
|
+
} else {
|
|
1110
|
+
formatted = valid.map((e, i) => `Example ${i + 1}:
|
|
1111
|
+
Input: ${e.input.trim()}
|
|
1112
|
+
Output: ${e.output.trim()}`).join("\n\n");
|
|
1113
|
+
}
|
|
1114
|
+
return { formatted, exampleCount: valid.length, format };
|
|
1115
|
+
}
|
|
1116
|
+
server.tool("format_few_shot_examples", "Format a list of input/output example pairs into a standard few-shot prompt template: numbered, XML-tagged, or delimiter-separated.", { examples: z.array(z.object({ input: z.string(), output: z.string() })), format: z.enum(["numbered", "xml", "delimiter"]).default("numbered"), delimiter: z.string().default("---") }, async ({ examples, format, delimiter }) => {
|
|
1117
|
+
return { content: [{ type: "text", text: JSON.stringify(_formatFewShotExamples(examples, format, delimiter), null, 2) }] };
|
|
1118
|
+
});
|
|
1095
1119
|
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 }) => {
|
|
1096
1120
|
return { content: [{ type: "text", text: JSON.stringify(sanitizeHtml(html, keep_links), null, 2) }] };
|
|
1097
1121
|
});
|
|
@@ -3138,6 +3162,74 @@ function _scoreReadability(input) {
|
|
|
3138
3162
|
server.tool("score_readability", "Score text with Flesch Reading Ease, Flesch-Kincaid Grade Level, and Gunning Fog Index, using a heuristic syllable counter.", { text: z.string() }, async ({ text: input }) => {
|
|
3139
3163
|
return { content: [{ type: "text", text: JSON.stringify(_scoreReadability(input), null, 2) }] };
|
|
3140
3164
|
});
|
|
3165
|
+
function _splitIntoSentencesForLengthDist(text2) {
|
|
3166
|
+
const matches = text2.match(/[^.!?]+[.!?]*/g);
|
|
3167
|
+
if (!matches) return [];
|
|
3168
|
+
return matches.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
3169
|
+
}
|
|
3170
|
+
function _countWordsInSentenceForLengthDist(sentence) {
|
|
3171
|
+
return (sentence.match(/[a-zA-Z']+/g) ?? []).length;
|
|
3172
|
+
}
|
|
3173
|
+
function _analyzeSentenceLengths(input) {
|
|
3174
|
+
const sentences = _splitIntoSentencesForLengthDist(input);
|
|
3175
|
+
const lengths = sentences.map(_countWordsInSentenceForLengthDist).filter((n) => n > 0);
|
|
3176
|
+
if (lengths.length === 0) {
|
|
3177
|
+
return {
|
|
3178
|
+
sentenceCount: 0,
|
|
3179
|
+
lengths: [],
|
|
3180
|
+
minLength: 0,
|
|
3181
|
+
maxLength: 0,
|
|
3182
|
+
meanLength: 0,
|
|
3183
|
+
medianLength: 0,
|
|
3184
|
+
stdDev: 0,
|
|
3185
|
+
coefficientOfVariation: 0,
|
|
3186
|
+
consistency: "No sentences to analyze",
|
|
3187
|
+
buckets: []
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
const sentenceCount = lengths.length;
|
|
3191
|
+
const minLength = Math.min(...lengths);
|
|
3192
|
+
const maxLength = Math.max(...lengths);
|
|
3193
|
+
const meanLength = lengths.reduce((a, b) => a + b, 0) / sentenceCount;
|
|
3194
|
+
const sorted = [...lengths].sort((a, b) => a - b);
|
|
3195
|
+
const mid = Math.floor(sorted.length / 2);
|
|
3196
|
+
const medianLength = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
3197
|
+
const variance = lengths.reduce((sum, n) => sum + (n - meanLength) ** 2, 0) / sentenceCount;
|
|
3198
|
+
const stdDev = Math.sqrt(variance);
|
|
3199
|
+
const coefficientOfVariation = meanLength > 0 ? stdDev / meanLength : 0;
|
|
3200
|
+
let consistency;
|
|
3201
|
+
if (coefficientOfVariation < 0.3) consistency = "Consistent \u2014 sentence lengths vary little";
|
|
3202
|
+
else if (coefficientOfVariation < 0.6) consistency = "Moderate variation in sentence length";
|
|
3203
|
+
else consistency = "Highly variable sentence length";
|
|
3204
|
+
const bucketWidth = 5;
|
|
3205
|
+
const bucketCount = Math.max(1, Math.ceil(maxLength / bucketWidth));
|
|
3206
|
+
const buckets = [];
|
|
3207
|
+
for (let i = 0; i < bucketCount; i++) {
|
|
3208
|
+
const min = i * bucketWidth + 1;
|
|
3209
|
+
const max = (i + 1) * bucketWidth;
|
|
3210
|
+
buckets.push({ label: `${min}-${max}`, min, max, count: 0 });
|
|
3211
|
+
}
|
|
3212
|
+
for (const len of lengths) {
|
|
3213
|
+
const idx = Math.min(Math.floor((len - 1) / bucketWidth), bucketCount - 1);
|
|
3214
|
+
buckets[idx].count++;
|
|
3215
|
+
}
|
|
3216
|
+
const round2 = (n) => Math.round(n * 100) / 100;
|
|
3217
|
+
return {
|
|
3218
|
+
sentenceCount,
|
|
3219
|
+
lengths,
|
|
3220
|
+
minLength,
|
|
3221
|
+
maxLength,
|
|
3222
|
+
meanLength: round2(meanLength),
|
|
3223
|
+
medianLength: round2(medianLength),
|
|
3224
|
+
stdDev: round2(stdDev),
|
|
3225
|
+
coefficientOfVariation: round2(coefficientOfVariation),
|
|
3226
|
+
consistency,
|
|
3227
|
+
buckets
|
|
3228
|
+
};
|
|
3229
|
+
}
|
|
3230
|
+
server.tool("analyze_sentence_lengths", "Split text into sentences and report a histogram of sentence lengths in words, plus mean, median, standard deviation, and a consistency label. Distinct from readability grade scores.", { text: z.string() }, async ({ text: input }) => {
|
|
3231
|
+
return { content: [{ type: "text", text: JSON.stringify(_analyzeSentenceLengths(input), null, 2) }] };
|
|
3232
|
+
});
|
|
3141
3233
|
var _ID3V1_GENRES = [
|
|
3142
3234
|
"Blues",
|
|
3143
3235
|
"Classic Rock",
|
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.33.0",
|
|
4
|
+
"description": "MCP server exposing 152 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/mcp",
|