"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.
// 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!
Character and Word Counting
TinyFn provides precise counting tools that solve the strawberry problem:
Count Specific Character
Tool: string/count-char
Input: {
"text": "strawberry",
"char": "r"
}
Response: {
"count": 3,
"positions": [2, 8, 9],
"text": "strawberry",
"char": "r"
}
Character Count (Length)
Tool: string/length
Input: {
"text": "Hello, World!"
}
Response: {
"length": 13,
"length_no_spaces": 11,
"text": "Hello, World!"
}
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:
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:
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
// 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
Tool: encode/base64
Input: {
"text": "Hello, World!",
"action": "encode"
}
Response: {
"result": "SGVsbG8sIFdvcmxkIQ==",
"action": "encode"
}
URL Encoding
Tool: encode/url
Input: {
"text": "hello world & more",
"action": "encode"
}
Response: {
"result": "hello%20world%20%26%20more",
"action": "encode"
}
HTML Entity Encoding
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
{
"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
- Always use tools for counting: Never let an LLM count characters, words, or occurrences. Use MCP tools.
- Normalize encoding: When encoding/decoding, specify UTF-8 explicitly to avoid character set issues.
- Handle edge cases: Empty strings, very long strings, and special characters should all work - test them.
- Preserve original data: Many tools return both original and transformed text. Keep both for debugging.
- Use appropriate case: Choose camelCase for JavaScript, snake_case for Python, kebab-case for URLs.
- 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