mcp-texttools 1.0.5 → 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.
Files changed (2) hide show
  1. package/index.js +140 -1
  2. package/package.json +8 -3
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.0.0" },
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.5",
4
- "description": "MCP server with 10 text transformation tools \u2014 case conversion, slug, word count, lorem ipsum, truncate, regex replace, markdown strip, character count, reverse, line sort",
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",