String Manipulation Tools for AI Agents via MCP

"How many R's are in strawberry?" This simple question exposes a fundamental limitation of LLMs - they can't count reliably. MCP string tools give your AI agents the ability to perform precise string operations, from character counting to encoding and formatting.

The Strawberry Problem

The "strawberry problem" has become a famous example of LLM limitations. When asked "How many R's are in strawberry?", many LLMs confidently answer "2" - which is wrong. There are 3 R's (at positions 3, 9, and 10).

This happens because LLMs don't actually count characters. They process text as tokens (chunks of characters) and predict what response would be appropriate. Character-level operations like counting require iterating through each character - something LLMs fundamentally cannot do.

The Strawberry Problem Solved
// Without MCP - LLM guesses
User: "How many R's in 'strawberry'?"
LLM: "There are 2 R's in strawberry"  // Wrong!

// With MCP - LLM uses tool
User: "How many R's in 'strawberry'?"
LLM: [calls string/count-char]
Tool: { "count": 3, "positions": [2, 8, 9] }
LLM: "There are 3 R's in strawberry, at positions 3, 9, and 10"  // Correct!
Why Positions Matter: TinyFn returns 0-indexed positions (2, 8, 9). When presenting to users, the agent adds 1 for human-readable positions (3, 9, 10).

Character and Word Counting

TinyFn provides precise counting tools that solve the strawberry problem:

Count Specific Character

MCP Tool Call: Count Character
Tool: string/count-char
Input: {
  "text": "strawberry",
  "char": "r"
}

Response: {
  "count": 3,
  "positions": [2, 8, 9],
  "text": "strawberry",
  "char": "r"
}

Character Count (Length)

MCP Tool Call: String Length
Tool: string/length
Input: {
  "text": "Hello, World!"
}

Response: {
  "length": 13,
  "length_no_spaces": 11,
  "text": "Hello, World!"
}

Word Count

MCP Tool Call: Word Count
Tool: string/word-count
Input: {
  "text": "The quick brown fox jumps over the lazy dog"
}

Response: {
  "words": 9,
  "characters": 43,
  "characters_no_spaces": 35,
  "sentences": 1
}

Formatting and Transformation

AI agents often need to format text for specific purposes - URLs, filenames, display. MCP tools handle these transformations reliably:

Slugify

Convert any text to a URL-friendly slug:

MCP Tool Call: Slugify
Tool: string/slugify
Input: {
  "text": "Hello World! This is a Test",
  "separator": "-"
}

Response: {
  "slug": "hello-world-this-is-a-test",
  "original": "Hello World! This is a Test"
}

Truncate

Truncate text to a specific length with customizable suffix:

MCP Tool Call: Truncate
Tool: string/truncate
Input: {
  "text": "This is a very long piece of text that needs to be shortened",
  "length": 30,
  "suffix": "..."
}

Response: {
  "truncated": "This is a very long piece o...",
  "original_length": 61,
  "was_truncated": true
}

Case Conversion

MCP Tool Calls: Case Conversion
// Camel Case
Tool: string/camel-case
Input: { "text": "hello world example" }
Response: { "result": "helloWorldExample" }

// Pascal Case
Tool: string/pascal-case
Input: { "text": "hello world example" }
Response: { "result": "HelloWorldExample" }

// Snake Case
Tool: string/snake-case
Input: { "text": "Hello World Example" }
Response: { "result": "hello_world_example" }

// Kebab Case
Tool: string/kebab-case
Input: { "text": "Hello World Example" }
Response: { "result": "hello-world-example" }

Encoding and Decoding

LLMs cannot perform encoding operations - they can only simulate them (often incorrectly). MCP tools provide guaranteed correct encoding:

Base64 Encoding

MCP Tool Call: Base64 Encode
Tool: encode/base64
Input: {
  "text": "Hello, World!",
  "action": "encode"
}

Response: {
  "result": "SGVsbG8sIFdvcmxkIQ==",
  "action": "encode"
}

URL Encoding

MCP Tool Call: URL Encode
Tool: encode/url
Input: {
  "text": "hello world & more",
  "action": "encode"
}

Response: {
  "result": "hello%20world%20%26%20more",
  "action": "encode"
}

HTML Entity Encoding

MCP Tool Call: HTML Encode
Tool: encode/html
Input: {
  "text": "",
  "action": "encode"
}

Response: {
  "result": "<script>alert('XSS')</script>",
  "action": "encode"
}

Real Agent Use Cases

Content Management Agent

An AI agent managing blog posts needs string tools for:

  • Slug generation: Convert titles to URL slugs
  • Meta descriptions: Truncate content to 155 characters
  • Word count: Validate minimum article length
  • Reading time: Calculate estimated reading time

Data Processing Agent

An agent processing user data needs:

  • Case normalization: Standardize naming conventions
  • Encoding: Safely encode data for URLs or HTML
  • Validation: Check string patterns and lengths

Code Generation Agent

An agent generating code needs:

  • Variable naming: Convert descriptions to camelCase
  • File naming: Create kebab-case filenames
  • Constant naming: Generate SCREAMING_SNAKE_CASE

Implementation Examples

Claude Desktop with TinyFn MCP

mcp.json Configuration
{
  "mcpServers": {
    "tinyfn-string": {
      "url": "https://api.tinyfn.io/mcp/string/",
      "headers": {
        "X-API-Key": "your-api-key"
      }
    }
  }
}

Python Agent Example

import requests

class StringAgent:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://api.tinyfn.io/v1"

    def count_character(self, text, char):
        """Count occurrences of a character in text"""
        response = requests.post(
            f"{self.base_url}/text/count-char",
            headers={
                "X-API-Key": self.api_key,
                "Content-Type": "application/json"
            },
            json={"text": text, "char": char}
        )
        return response.json()

    def create_slug(self, text):
        """Create URL slug from text"""
        response = requests.post(
            f"{self.base_url}/text/slugify",
            headers={
                "X-API-Key": self.api_key,
                "Content-Type": "application/json"
            },
            json={"text": text}
        )
        return response.json()["slug"]

    def truncate_for_meta(self, text, max_length=155):
        """Truncate text for meta description"""
        response = requests.post(
            f"{self.base_url}/text/truncate",
            headers={
                "X-API-Key": self.api_key,
                "Content-Type": "application/json"
            },
            json={
                "text": text,
                "length": max_length,
                "suffix": "..."
            }
        )
        return response.json()["truncated"]

# Usage
agent = StringAgent("your-api-key")

# Solve the strawberry problem
result = agent.count_character("strawberry", "r")
print(f"Count: {result['count']}, Positions: {result['positions']}")
# Output: Count: 3, Positions: [2, 8, 9]

# Create a blog post slug
slug = agent.create_slug("10 Tips for Better AI Agents!")
print(f"Slug: {slug}")
# Output: 10-tips-for-better-ai-agents

JavaScript Agent Example

class StringAgent {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.tinyfn.io/v1';
  }

  async countCharacter(text, char) {
    const response = await fetch(`${this.baseUrl}/text/count-char`, {
      method: 'POST',
      headers: {
        'X-API-Key': this.apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ text, char })
    });
    return response.json();
  }

  async encodeBase64(text) {
    const response = await fetch(`${this.baseUrl}/encode/base64`, {
      method: 'POST',
      headers: {
        'X-API-Key': this.apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ text, action: 'encode' })
    });
    return (await response.json()).result;
  }

  async decodeBase64(encoded) {
    const response = await fetch(`${this.baseUrl}/encode/base64`, {
      method: 'POST',
      headers: {
        'X-API-Key': this.apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ text: encoded, action: 'decode' })
    });
    return (await response.json()).result;
  }
}

// Usage
const agent = new StringAgent('your-api-key');

// Solve strawberry problem
const result = await agent.countCharacter('strawberry', 'r');
console.log(`There are ${result.count} R's`);  // There are 3 R's

// Encode for API
const encoded = await agent.encodeBase64('secret data');
console.log(encoded);  // c2VjcmV0IGRhdGE=

Best Practices

  1. Always use tools for counting: Never let an LLM count characters, words, or occurrences. Use MCP tools.
  2. Normalize encoding: When encoding/decoding, specify UTF-8 explicitly to avoid character set issues.
  3. Handle edge cases: Empty strings, very long strings, and special characters should all work - test them.
  4. Preserve original data: Many tools return both original and transformed text. Keep both for debugging.
  5. Use appropriate case: Choose camelCase for JavaScript, snake_case for Python, kebab-case for URLs.
  6. Truncate thoughtfully: When truncating, use "..." and try to break at word boundaries when possible.

Solve the Strawberry Problem

Give your AI agents reliable string tools. Get your free TinyFn API key today.

Get Free API Key

Ready to try TinyFn?

Get your free API key and start building in minutes.

Get Free API Key