The short answer
Send any string to count_text on the free Document Tools MCP server (https://docs.openkrill.app/mcp) and one response gives you the word count, character count (with and without spaces), Unicode grapheme clusters, UTF-8 byte length, sentence, paragraph and line counts, silent reading time (reading_minutes), Flesch Reading Ease, Flesch-Kincaid Grade Level, and the SMS segment breakdown.
On our 134-character booking confirmation, which contains Café Lumière and one emoji (🎉), count_text returned 29 words, 3 sentences, 139 UTF-8 bytes, reading_minutes: 0.1, Flesch Reading Ease 97.2 (grade 1.9), and 3 UCS-2 SMS segments (135 UTF-16 code units at 67 units per concatenated segment). Replacing that one emoji with a period dropped the message to 1 GSM-7 segment of 133 septets, with 27 characters to spare.
The test string and how 3 tools measured it
We tested this exact restaurant confirmation message on 2026-10-19:
Hi Ana! Your table for 4 at Café Lumière is booked for Friday 7:30 pm 🎉 Reply YES to confirm or call us if plans change. See you soon!
Here is what each tool returned on that input:
| Tool | Time | Words and sentences | Characters and bytes | Readability | SMS encoding and segments |
|---|---|---|---|---|---|
Document Tools (count_text) | 1,039 ms | 29 words, 3 sentences, 1 paragraph | 134 characters (106 without spaces), 134 graphemes, 139 UTF-8 bytes | Flesch Reading Ease 97.2 (very easy), Flesch-Kincaid grade 1.9 | UCS-2, 135 units, 3 segments (67 per segment) |
Twilio @twilio-labs/sms-segments-calculator | 1,997 ms | Not supported | 135 UCS-2 code units (1,080 bits) | Not supported | UCS-2, 135 units, 3 segments |
Python textstat | 2,429 ms | 28 words; sentence count failed without external nltk_data | 134 characters (106 without spaces) | Failed without punkt_tab download | Not supported |
We also fetched WordCounter.net on the same day. Its static HTML page serves 0 words and 0 characters unless you run a browser with client-side JavaScript.
Why 134 characters became 135 UTF-16 units and 3 SMS segments
Three encoding rules stack up on this one message:
- GSM-7 vs UCS-2 switching. Standard SMS uses the 7-bit GSM 03.38 alphabet, which fits 160 septets into one 140-byte SMS frame. As soon as a message contains even one character outside GSM-7 (here
🎉, U+1F389), the carrier re-encodes the entire message as 16-bit UCS-2, where a single-part SMS holds at most 70 UTF-16 code units. - Surrogate pairs above U+FFFF. Our string has 134 user-perceived characters (grapheme clusters), but
🎉sits in the astral plane (U+1F389) and takes a UTF-16 surrogate pair of 2 code units. That brings the UCS-2 unit count from 134 to 135. It also brings the UTF-8 byte count to 139: 131 ASCII bytes, 2 bytes each for é and è, and 4 bytes for🎉. - User Data Header (UDH) overhead on split messages. Once a UCS-2 message goes past 70 units, each segment reserves 6 bytes (3 UTF-16 units) for the concatenation header that tells the handset how to reassemble the text. So each segment carries 67 units instead of 70. Two segments hold 134 units (
67 × 2 = 134), which means unit 135 spills into a 3rd segment.
Dropping the one emoji cuts the cost from 3 segments to 1
A common misconception is that the French accents in Café Lumière also force UCS-2 encoding. They don't. Both lowercase é (U+00E9) and lowercase è (U+00E8) are in the basic GSM 03.38 7-bit character table, at 1 septet each. On 2026-10-20 we replaced 🎉 with a period and ran count_text again:
| Version | Characters | Words and sentences | UTF-8 bytes | SMS encoding | SMS units | Segments |
|---|---|---|---|---|---|---|
With 🎉 emoji | 134 (106 no spaces) | 29 words, 3 sentences | 139 bytes | UCS-2 | 135 UTF-16 units (67 per segment) | 3 segments |
Emoji replaced by . | 133 (106 no spaces) | 28 words, 4 sentences | 135 bytes | GSM-7 | 133 septets (160 per segment) | 1 segment |
To run the same check from any MCP client or script, send this JSON-RPC call to Document Tools (see also the ChatGPT integration guide and the Claude integration guide):
{"method":"tools/call","params":{"name":"count_text",
"arguments":{"text":"Hi Ana! Your table for 4 at Café Lumière is booked for Friday 7:30 pm. Reply YES to confirm or call us if plans change. See you soon!"}}}
Frequently asked questions
Why does a 134-character message take 3 SMS segments instead of 1?
Any character outside the GSM-7 alphabet, such as an emoji, switches the entire SMS to UCS-2 (16-bit) encoding. A single UCS-2 message holds at most 70 UTF-16 code units. A multi-part UCS-2 message holds 67 units per segment, because 6 bytes go to the concatenation header. Our message comes to 135 UTF-16 units (133 characters plus 2 units for the emoji surrogate pair), and 135 divided by 67 rounds up to 3 segments.
Do French accents like é and è force UCS-2 encoding?
Not when they are part of the standard GSM 03.38 7-bit alphabet. Lowercase é and è each take 1 septet in the basic GSM-7 table, so our 133-character booking text for Café Lumière stays in 1 GSM-7 segment once the emoji is removed.
Why did Python textstat count 28 words while Document Tools counted 29?
Document Tools counts runs of non-whitespace separated by whitespace, so it counts the standalone emoji token between 7:30 pm and Reply as 1 word. Python textstat returned 28 words on the same string because it excludes the standalone emoji token from its word count.
What else does the Document Tools MCP server do besides count_text?
The server at https://docs.openkrill.app/mcp provides 4 tools with no API key (up to 60 calls a minute per network): count_text, make_calendar_file (RFC 5545 .ics calendar invites), make_csv_file (RFC 4180 CSV export from JSON rows) and translate_page (bilingual or translated HTML and Markdown documents).
Sources
- Text, readability and SMS segment runs: Document Tools MCP server (
https://docs.openkrill.app/mcp), read on 2026-10-19 and 2026-10-20. - GSM 03.38 character set and SMS concatenation specification: 3GPP TS 23.038 / ETSI TS 123 038 (Alphabets and language-specific information) and 3GPP TS 23.040 (Technical realization of the Short Message Service).
- Twilio segment benchmark:
@twilio-labs/sms-segments-calculator, run via Node.js on 2026-10-19. - Python readability benchmark:
textstaton PyPI, run on 2026-10-19.