@utilix-tech/mcp 0.75.0 → 0.76.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 +3 -1
- package/dist/index.js +108 -0
- package/package.json +1 -1
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.76.0
|
|
6
|
+
- Add `detect_wordy_phrases` tool: scan text against a curated table of wordy/redundant phrases ("due to the fact that", "in order to") and flag each occurrence with a suggested concise replacement, an occurrence count, and character offsets.
|
|
7
|
+
- Add `check_oxford_comma_consistency` tool: scan a document for comma-before-and/or usage in three-or-more-item lists and flag documents that mix Oxford comma styles.
|
|
8
|
+
|
|
5
9
|
## 0.75.0
|
|
6
10
|
- Add `verify_webhook_signature` tool: recompute an HMAC over a raw webhook payload and compare it to a provided signature, supporting the `sha256=` prefix style (Stripe/GitHub-style webhooks) plus raw hex or base64 encoding.
|
|
7
11
|
- Add `estimate_data_transfer_time` tool: estimate the theoretical time to transfer a file over a connection of a given speed, or the reverse: the bandwidth required to hit a target time.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/mcp
|
|
2
2
|
|
|
3
|
-
MCP server exposing
|
|
3
|
+
MCP server exposing 247 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
|
|
|
@@ -147,6 +147,8 @@ claude mcp add utilix -- npx -y @utilix-tech/mcp
|
|
|
147
147
|
| `detect_passive_voice` | Flag sentences written in passive voice, e.g. "was written", "were approved by the team" |
|
|
148
148
|
| `score_readability` | Score text with Flesch Reading Ease, Flesch-Kincaid Grade Level, and Gunning Fog Index |
|
|
149
149
|
| `detect_filler_words` | Scan text for filler words, hedge phrases, and clichés with per-phrase counts and a density score |
|
|
150
|
+
| `detect_wordy_phrases` | Scan text against a curated table of wordy/redundant phrases and suggest a concise replacement for each occurrence |
|
|
151
|
+
| `check_oxford_comma_consistency` | Scan a document for comma-before-and/or usage in three-or-more-item lists and flag documents that mix Oxford comma styles |
|
|
150
152
|
| `calculate_string_distance` | Compute the Levenshtein (or Damerau) edit distance and normalized similarity between two strings |
|
|
151
153
|
| `analyze_sentence_lengths` | Split text into sentences and report a histogram of sentence lengths, plus mean, median, standard deviation, and a consistency label |
|
|
152
154
|
| `lookup_emoji` | Search a curated table of ~280 common emoji by name, keyword, or GitHub-style shortcode, or look one up exactly by shortcode, character, or category |
|
package/dist/index.js
CHANGED
|
@@ -4781,6 +4781,114 @@ server.tool(
|
|
|
4781
4781
|
return text(JSON.stringify(_detectFillerWordsMcp(input), null, 2));
|
|
4782
4782
|
}
|
|
4783
4783
|
);
|
|
4784
|
+
var _WORDY_PHRASES_MCP = [
|
|
4785
|
+
["due to the fact that", "because"],
|
|
4786
|
+
["in spite of the fact that", "although"],
|
|
4787
|
+
["despite the fact that", "although"],
|
|
4788
|
+
["in order to", "to"],
|
|
4789
|
+
["for the purpose of", "for"],
|
|
4790
|
+
["in the event that", "if"],
|
|
4791
|
+
["in the near future", "soon"],
|
|
4792
|
+
["at this point in time", "now"],
|
|
4793
|
+
["at the present time", "now"],
|
|
4794
|
+
["on a daily basis", "daily"],
|
|
4795
|
+
["on a regular basis", "regularly"],
|
|
4796
|
+
["in a timely manner", "promptly"],
|
|
4797
|
+
["with regard to", "regarding"],
|
|
4798
|
+
["with respect to", "regarding"],
|
|
4799
|
+
["in regards to", "regarding"],
|
|
4800
|
+
["with the exception of", "except"],
|
|
4801
|
+
["in close proximity to", "near"],
|
|
4802
|
+
["take into consideration", "consider"],
|
|
4803
|
+
["give consideration to", "consider"],
|
|
4804
|
+
["make a decision", "decide"],
|
|
4805
|
+
["is able to", "can"],
|
|
4806
|
+
["are able to", "can"],
|
|
4807
|
+
["a large number of", "many"],
|
|
4808
|
+
["a majority of", "most"],
|
|
4809
|
+
["each and every", "each"],
|
|
4810
|
+
["first and foremost", "first"],
|
|
4811
|
+
["last but not least", "finally"],
|
|
4812
|
+
["null and void", "void"],
|
|
4813
|
+
["whether or not", "whether"],
|
|
4814
|
+
["the reason why", "the reason"],
|
|
4815
|
+
["end result", "result"],
|
|
4816
|
+
["future plans", "plans"],
|
|
4817
|
+
["past history", "history"],
|
|
4818
|
+
["basic fundamentals", "fundamentals"],
|
|
4819
|
+
["absolutely essential", "essential"],
|
|
4820
|
+
["it is important to note that", "(often removable)"],
|
|
4821
|
+
["as a matter of fact", "in fact"],
|
|
4822
|
+
["in the process of", "(often removable)"]
|
|
4823
|
+
];
|
|
4824
|
+
function _wordyRegexMcp(phrase) {
|
|
4825
|
+
const tokens = phrase.split(/\s+/).map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
4826
|
+
return new RegExp("\\b" + tokens.join("\\s+") + "\\b", "gi");
|
|
4827
|
+
}
|
|
4828
|
+
function _detectWordyPhrasesMcp(input) {
|
|
4829
|
+
const totalWords = (input.match(/[A-Za-z0-9']+/g) ?? []).length;
|
|
4830
|
+
const matches = [];
|
|
4831
|
+
for (const [phrase, suggestion] of _WORDY_PHRASES_MCP) {
|
|
4832
|
+
const re = _wordyRegexMcp(phrase);
|
|
4833
|
+
const indices = [];
|
|
4834
|
+
let m;
|
|
4835
|
+
while ((m = re.exec(input)) !== null) {
|
|
4836
|
+
indices.push(m.index);
|
|
4837
|
+
if (m.index === re.lastIndex) re.lastIndex++;
|
|
4838
|
+
}
|
|
4839
|
+
if (indices.length > 0) matches.push({ phrase, suggestion, count: indices.length, indices });
|
|
4840
|
+
}
|
|
4841
|
+
matches.sort((a, b) => b.count - a.count || a.phrase.localeCompare(b.phrase));
|
|
4842
|
+
const totalMatches = matches.reduce((s, m) => s + m.count, 0);
|
|
4843
|
+
const density = totalWords > 0 ? Math.round(totalMatches / totalWords * 1e3) / 10 : 0;
|
|
4844
|
+
return { totalWords, totalMatches, density, matches };
|
|
4845
|
+
}
|
|
4846
|
+
server.tool(
|
|
4847
|
+
"detect_wordy_phrases",
|
|
4848
|
+
'Scan text against a curated table of wordy/redundant phrases ("due to the fact that", "in order to", "at this point in time") and flag each occurrence with a suggested concise replacement, an occurrence count, and character offsets. Dictionary-based heuristic: a flagged phrase is a candidate to tighten, not always wrong in context.',
|
|
4849
|
+
{ text: z.string().describe("The text to scan for wordy/redundant phrases") },
|
|
4850
|
+
async ({ text: input }) => {
|
|
4851
|
+
return text(JSON.stringify(_detectWordyPhrasesMcp(input), null, 2));
|
|
4852
|
+
}
|
|
4853
|
+
);
|
|
4854
|
+
var _OXFORD_CONJ_RE_MCP = /(,)?\s+\b(?:and|or)\b\s+/gi;
|
|
4855
|
+
function _checkOxfordCommaConsistencyMcp(input) {
|
|
4856
|
+
const instances = [];
|
|
4857
|
+
_OXFORD_CONJ_RE_MCP.lastIndex = 0;
|
|
4858
|
+
let m;
|
|
4859
|
+
while ((m = _OXFORD_CONJ_RE_MCP.exec(input)) !== null) {
|
|
4860
|
+
const matchStart = m.index;
|
|
4861
|
+
const hasCommaBefore = !!m[1];
|
|
4862
|
+
let clauseStart = -1;
|
|
4863
|
+
for (const ch of [".", "!", "?", "\n"]) {
|
|
4864
|
+
const idx = input.lastIndexOf(ch, matchStart - 1);
|
|
4865
|
+
if (idx > clauseStart) clauseStart = idx;
|
|
4866
|
+
}
|
|
4867
|
+
clauseStart += 1;
|
|
4868
|
+
const clause = input.slice(clauseStart, matchStart);
|
|
4869
|
+
const commaCount = (clause.match(/,/g) ?? []).length;
|
|
4870
|
+
if (commaCount < 1) continue;
|
|
4871
|
+
const snippetStart = Math.max(clauseStart, matchStart - 60);
|
|
4872
|
+
const afterConjEnd = _OXFORD_CONJ_RE_MCP.lastIndex;
|
|
4873
|
+
const tail = input.slice(afterConjEnd);
|
|
4874
|
+
const boundaryOffset = tail.search(/[.!?\n,]/);
|
|
4875
|
+
const snippetEnd = boundaryOffset === -1 ? Math.min(input.length, afterConjEnd + 40) : afterConjEnd + boundaryOffset;
|
|
4876
|
+
const snippet = input.slice(snippetStart, snippetEnd).trim();
|
|
4877
|
+
instances.push({ snippet, hasOxfordComma: hasCommaBefore, index: matchStart });
|
|
4878
|
+
}
|
|
4879
|
+
const withOxfordComma = instances.filter((i) => i.hasOxfordComma).length;
|
|
4880
|
+
const withoutOxfordComma = instances.length - withOxfordComma;
|
|
4881
|
+
const consistent = withOxfordComma === 0 || withoutOxfordComma === 0;
|
|
4882
|
+
return { totalLists: instances.length, withOxfordComma, withoutOxfordComma, consistent, instances };
|
|
4883
|
+
}
|
|
4884
|
+
server.tool(
|
|
4885
|
+
"check_oxford_comma_consistency",
|
|
4886
|
+
"Scan a document for comma-before-and/or usage in three-or-more-item lists and flag inconsistency: some lists using the Oxford (serial) comma while others in the same document don't. A heuristic over punctuation and sentence boundaries, not a full grammar parser.",
|
|
4887
|
+
{ text: z.string().describe("The document to scan for Oxford comma consistency") },
|
|
4888
|
+
async ({ text: input }) => {
|
|
4889
|
+
return text(JSON.stringify(_checkOxfordCommaConsistencyMcp(input), null, 2));
|
|
4890
|
+
}
|
|
4891
|
+
);
|
|
4784
4892
|
function _calculatePercentageChangeMcp(oldValue, newValue) {
|
|
4785
4893
|
if (!Number.isFinite(oldValue)) return { error: "Original value must be a finite number" };
|
|
4786
4894
|
if (!Number.isFinite(newValue)) return { error: "New value must be a finite number" };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utilix-tech/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.76.0",
|
|
4
4
|
"description": "MCP server exposing 198 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",
|