mcp-texttools 1.0.4 → 1.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 +3 -79
- package/index.js +140 -1
- package/package.json +16 -3
package/README.md
CHANGED
|
@@ -1,84 +1,8 @@
|
|
|
1
|
-
# mcp-texttools
|
|
2
1
|
|
|
3
|
-
MCP server with 10 text transformation tools for AI assistants (Claude, Cursor, etc).
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx mcp-texttools
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
### Claude Desktop
|
|
12
|
-
|
|
13
|
-
Add to `claude_desktop_config.json`:
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"mcpServers": {
|
|
18
|
-
"texttools": {
|
|
19
|
-
"command": "npx",
|
|
20
|
-
"args": ["-y", "mcp-texttools"]
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Cursor
|
|
27
|
-
|
|
28
|
-
Add to `.cursor/mcp.json`:
|
|
29
|
-
|
|
30
|
-
```json
|
|
31
|
-
{
|
|
32
|
-
"mcpServers": {
|
|
33
|
-
"texttools": {
|
|
34
|
-
"command": "npx",
|
|
35
|
-
"args": ["-y", "mcp-texttools"]
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Tools
|
|
42
|
-
|
|
43
|
-
| Tool | Description |
|
|
44
|
-
|------|-------------|
|
|
45
|
-
| `case_convert` | Convert between camelCase, snake_case, kebab-case, PascalCase, CONSTANT_CASE, Title Case, dot.case |
|
|
46
|
-
| `slugify` | Convert text to URL-friendly slug |
|
|
47
|
-
| `word_count` | Count words, characters, sentences, paragraphs + reading time |
|
|
48
|
-
| `lorem_ipsum` | Generate placeholder text (words, sentences, or paragraphs) |
|
|
49
|
-
| `truncate` | Smart truncation at word/sentence/character boundaries |
|
|
50
|
-
| `regex_replace` | Find & replace with regex (supports capture groups) |
|
|
51
|
-
| `markdown_strip` | Strip markdown formatting to plain text |
|
|
52
|
-
| `text_reverse` | Reverse by characters, words, or lines |
|
|
53
|
-
| `line_sort` | Sort lines (alpha, numeric, length, random) + dedup |
|
|
54
|
-
| `text_diff` | Compare two texts line by line |
|
|
55
|
-
|
|
56
|
-
## Examples
|
|
57
|
-
|
|
58
|
-
**Convert case:**
|
|
59
|
-
- Input: `"myVariableName"` → snake → `my_variable_name`
|
|
60
|
-
- Input: `"my-api-endpoint"` → pascal → `MyApiEndpoint`
|
|
61
|
-
|
|
62
|
-
**Slugify:**
|
|
63
|
-
- Input: `"Hello World! This is a Test"` → `hello-world-this-is-a-test`
|
|
64
|
-
|
|
65
|
-
**Word count:**
|
|
66
|
-
- Returns words, characters, sentences, paragraphs, reading time
|
|
67
|
-
|
|
68
|
-
## Part of the MCP Dev Tools Suite
|
|
69
|
-
|
|
70
|
-
- [mcp-devutils](https://www.npmjs.com/package/mcp-devutils) — UUID, hash, base64, timestamps, JWT decode, and more
|
|
71
|
-
- [mcp-apitools](https://www.npmjs.com/package/mcp-apitools) — HTTP status, MIME types, JWT create, mock data, CORS headers
|
|
72
|
-
- **mcp-texttools** — Text transformation and analysis (this package)
|
|
73
|
-
- [mcp-mathtools](https://www.npmjs.com/package/mcp-mathtools) — 12 math & statistics tools: arithmetic, statistics, unit conversion, financial calculations
|
|
74
|
-
- [mcp-datetime](https://www.npmjs.com/package/mcp-datetime) — 10 date & time tools: timezone conversion, date math, cron explanation, business days
|
|
75
|
-
- [mcp-quick-calc](https://www.npmjs.com/package/mcp-quick-calc) — 5 calculator tools: currency conversion, percentages, compound interest, unit conversion, loan payments
|
|
76
|
-
- **[mcp-all-tools](https://www.npmjs.com/package/mcp-all-tools)** — All 54+ tools in a single MCP server
|
|
77
2
|
|
|
78
3
|
## Support
|
|
79
4
|
|
|
80
|
-
If
|
|
81
|
-
|
|
82
|
-
## License
|
|
5
|
+
If this tool saves you time, consider supporting development:
|
|
83
6
|
|
|
84
|
-
|
|
7
|
+
- [Buy me a coffee](https://buymeacoffee.com/gl89tu25lp)
|
|
8
|
+
- [Tip via Stripe ($3)](https://buy.stripe.com/dRm8wP8R295Z9VyeN59Zm00)
|
package/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
5
|
|
|
6
6
|
const server = new Server(
|
|
7
|
-
{ name: "mcp-texttools", version: "1.
|
|
7
|
+
{ name: "mcp-texttools", version: "1.1.0" },
|
|
8
8
|
{ capabilities: { tools: {} } }
|
|
9
9
|
);
|
|
10
10
|
|
|
@@ -152,6 +152,69 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
152
152
|
},
|
|
153
153
|
required: ["text1", "text2"]
|
|
154
154
|
}
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "extract_emails",
|
|
158
|
+
description: "Extract all email addresses from text, with optional deduplication",
|
|
159
|
+
inputSchema: {
|
|
160
|
+
type: "object",
|
|
161
|
+
properties: {
|
|
162
|
+
text: { type: "string", description: "Text to extract emails from" },
|
|
163
|
+
unique: { type: "boolean", description: "Return only unique emails (default: true)" }
|
|
164
|
+
},
|
|
165
|
+
required: ["text"]
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "extract_urls",
|
|
170
|
+
description: "Extract all URLs (http/https) from text, with optional deduplication",
|
|
171
|
+
inputSchema: {
|
|
172
|
+
type: "object",
|
|
173
|
+
properties: {
|
|
174
|
+
text: { type: "string", description: "Text to extract URLs from" },
|
|
175
|
+
unique: { type: "boolean", description: "Return only unique URLs (default: true)" }
|
|
176
|
+
},
|
|
177
|
+
required: ["text"]
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
name: "text_pad",
|
|
182
|
+
description: "Pad text to a fixed width — left, right, or center aligned",
|
|
183
|
+
inputSchema: {
|
|
184
|
+
type: "object",
|
|
185
|
+
properties: {
|
|
186
|
+
text: { type: "string", description: "Text to pad" },
|
|
187
|
+
width: { type: "number", description: "Target width in characters" },
|
|
188
|
+
align: { type: "string", enum: ["left", "right", "center"], description: "Alignment (default: right)" },
|
|
189
|
+
char: { type: "string", description: "Padding character (default: space)" }
|
|
190
|
+
},
|
|
191
|
+
required: ["text", "width"]
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: "text_wrap",
|
|
196
|
+
description: "Wrap text to a specified line width, breaking at word boundaries",
|
|
197
|
+
inputSchema: {
|
|
198
|
+
type: "object",
|
|
199
|
+
properties: {
|
|
200
|
+
text: { type: "string", description: "Text to wrap" },
|
|
201
|
+
width: { type: "number", description: "Maximum line width (default: 80)" }
|
|
202
|
+
},
|
|
203
|
+
required: ["text"]
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
name: "string_repeat",
|
|
208
|
+
description: "Repeat a string N times with an optional separator",
|
|
209
|
+
inputSchema: {
|
|
210
|
+
type: "object",
|
|
211
|
+
properties: {
|
|
212
|
+
text: { type: "string", description: "Text to repeat" },
|
|
213
|
+
count: { type: "number", description: "Number of repetitions (1-1000, default: 2)" },
|
|
214
|
+
separator: { type: "string", description: "Separator between repetitions (default: empty)" }
|
|
215
|
+
},
|
|
216
|
+
required: ["text"]
|
|
217
|
+
}
|
|
155
218
|
}
|
|
156
219
|
]
|
|
157
220
|
};
|
|
@@ -447,6 +510,82 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
447
510
|
return { content: [{ type: "text", text: output.join("\n") + summary }] };
|
|
448
511
|
}
|
|
449
512
|
|
|
513
|
+
case "extract_emails": {
|
|
514
|
+
const { text, unique = true } = args;
|
|
515
|
+
const emailRegex = /[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/g;
|
|
516
|
+
let emails = text.match(emailRegex) || [];
|
|
517
|
+
if (unique) emails = [...new Set(emails.map(e => e.toLowerCase()))];
|
|
518
|
+
if (emails.length === 0) {
|
|
519
|
+
return { content: [{ type: "text", text: "No email addresses found." }] };
|
|
520
|
+
}
|
|
521
|
+
return { content: [{ type: "text", text: `Found ${emails.length} email(s):\n\n${emails.join("\n")}` }] };
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
case "extract_urls": {
|
|
525
|
+
const { text, unique = true } = args;
|
|
526
|
+
const urlRegex = /https?:\/\/[^\s<>\"')\]]+/g;
|
|
527
|
+
let urls = text.match(urlRegex) || [];
|
|
528
|
+
if (unique) urls = [...new Set(urls)];
|
|
529
|
+
if (urls.length === 0) {
|
|
530
|
+
return { content: [{ type: "text", text: "No URLs found." }] };
|
|
531
|
+
}
|
|
532
|
+
return { content: [{ type: "text", text: `Found ${urls.length} URL(s):\n\n${urls.join("\n")}` }] };
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
case "text_pad": {
|
|
536
|
+
const { text, width, align = "right", char = " " } = args;
|
|
537
|
+
const padChar = char.charAt(0) || " ";
|
|
538
|
+
const lines = text.split("\n");
|
|
539
|
+
const padded = lines.map(line => {
|
|
540
|
+
if (line.length >= width) return line;
|
|
541
|
+
const diff = width - line.length;
|
|
542
|
+
switch (align) {
|
|
543
|
+
case "left":
|
|
544
|
+
return line + padChar.repeat(diff);
|
|
545
|
+
case "center": {
|
|
546
|
+
const left = Math.floor(diff / 2);
|
|
547
|
+
const right = diff - left;
|
|
548
|
+
return padChar.repeat(left) + line + padChar.repeat(right);
|
|
549
|
+
}
|
|
550
|
+
case "right":
|
|
551
|
+
default:
|
|
552
|
+
return padChar.repeat(diff) + line;
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
return { content: [{ type: "text", text: padded.join("\n") }] };
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
case "text_wrap": {
|
|
559
|
+
const { text, width = 80 } = args;
|
|
560
|
+
const paragraphs = text.split("\n");
|
|
561
|
+
const wrapped = paragraphs.map(para => {
|
|
562
|
+
if (para.trim() === "") return "";
|
|
563
|
+
const words = para.split(/\s+/);
|
|
564
|
+
const lines = [];
|
|
565
|
+
let current = "";
|
|
566
|
+
for (const word of words) {
|
|
567
|
+
if (current.length === 0) {
|
|
568
|
+
current = word;
|
|
569
|
+
} else if (current.length + 1 + word.length <= width) {
|
|
570
|
+
current += " " + word;
|
|
571
|
+
} else {
|
|
572
|
+
lines.push(current);
|
|
573
|
+
current = word;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (current) lines.push(current);
|
|
577
|
+
return lines.join("\n");
|
|
578
|
+
});
|
|
579
|
+
return { content: [{ type: "text", text: wrapped.join("\n") }] };
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
case "string_repeat": {
|
|
583
|
+
const { text, count = 2, separator = "" } = args;
|
|
584
|
+
const n = Math.max(1, Math.min(1000, count));
|
|
585
|
+
const result = Array(n).fill(text).join(separator);
|
|
586
|
+
return { content: [{ type: "text", text: result }] };
|
|
587
|
+
}
|
|
588
|
+
|
|
450
589
|
default:
|
|
451
590
|
throw new Error(`Unknown tool: ${name}`);
|
|
452
591
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-texttools",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "MCP server with
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "MCP server with 15 text transformation tools \u2014 case conversion, slug, word count, lorem ipsum, truncate, regex replace, markdown strip, reverse, line sort, text diff, extract emails, extract URLs, text pad, text wrap, string repeat",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"bin": {
|
|
@@ -24,7 +24,12 @@
|
|
|
24
24
|
"claude",
|
|
25
25
|
"cursor",
|
|
26
26
|
"ai-tools",
|
|
27
|
-
"string-utils"
|
|
27
|
+
"string-utils",
|
|
28
|
+
"extract-email",
|
|
29
|
+
"extract-url",
|
|
30
|
+
"text-wrap",
|
|
31
|
+
"string-repeat",
|
|
32
|
+
"text-padding"
|
|
28
33
|
],
|
|
29
34
|
"author": "Hong Teoh",
|
|
30
35
|
"license": "MIT",
|
|
@@ -34,5 +39,13 @@
|
|
|
34
39
|
},
|
|
35
40
|
"dependencies": {
|
|
36
41
|
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/hlteoh37/mcp-texttools.git"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/hlteoh37/mcp-texttools#readme",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/hlteoh37/mcp-texttools/issues"
|
|
37
50
|
}
|
|
38
51
|
}
|