mcp-server-serp-title-width
Measures Chinese, Japanese, and Korean page titles against Google search result rendering, using Google SERP title font and column dimensions to flag titles that are safe, long, near the desktop truncation limit, or cut.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-server-serp-title-widthcheck if this Chinese title will be cut off in Google: 台北最佳咖啡廳推薦"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-server-serp-title-width
Check whether Chinese, Japanese and Korean page titles fit in Google search results, measured by rendered pixel width instead of character count. Ships as an MCP server (for AI agents) and a CLI (for builds and CI).
Documentation and background: adsandcode.com/en/open-source/serp-title-width
The problem
Site auditors and SEO plugins usually judge title length by counting characters, with limits around 60. That rule of thumb comes from Latin text. In the font Google uses for result titles, a CJK ideograph, a kana or a Hangul syllable is 22px wide, roughly twice an average Latin letter. Sixty of them come to 1320px, about twice the 652px desktop result column. A character-count check passes CJK titles that Google will cut in half.
Google says only that the title link is truncated as needed; its documentation gives no length in characters or pixels:
"the title link is truncated in Google Search results as needed" (Google Search Central, "Influencing your title links in search results")
So the width has to be measured.
Related MCP server: geo-tool-check
The model
Measured on 2026-09-18 on google.com with the zh-TW (Traditional Chinese, Taiwan) interface, Chrome on Windows, by reading the computed style of a result title and measuring glyph advances with a canvas in the same page.
Item | Value |
Result title font | Arial 22px, line-height 28px |
Desktop result column | 652px, the same at 1366px and 1920px viewport widths |
Desktop truncation | done by Google's server (text cut, |
Mobile | two lines, 343px per line |
Full-width character | 22.0px (1em). Full width means East Asian Width W or F (UAX #11): ideographs, kana, Hangul, full-width punctuation, most emoji |
Printable ASCII (U+0020-U+007E) | Arial's own advance widths, all 95 characters: for example |
Other half-width characters | 12.2px (estimate, not measured) |
Zero-width characters | 0px: U+200B-U+200D, U+2060, U+FEFF, variation selectors, emoji skin-tone modifiers |
Emoji sequences | each grapheme cluster counts once: a family emoji, a flag or a letter with combining accents is one character |
Thresholds:
Tier | Width | Result | Why |
| up to 572px (26 full-width characters) | pass | Conservative line. Leaves room for narrow screens and for differences between your |
| over 572px | warning | Over the conservative line, below the edge zone |
| over 630px | fail | Near the measured single-line limit on desktop |
| over 648px | fail | Wider than the desktop column: desktop results truncate it |
A digit costs about 0.56 of a full-width character, so "2026" takes the space of 2.2 ideographs. Capital letters are much wider than digits: an all-caps product name can push a title over the line that a character count, or a model that treats every Latin letter alike, says it fits.
The ASCII widths come from the font file (Arial Version 7.01 on Windows), in
font units, measured with scripts/measure-arial.py and cross-checked three
ways: Pillow at 2048px, the font's advance-width table read with fontTools,
and measureText() on a Chrome canvas set to 22px arial. All 95 agree to
within 0.0001px.
Re-measuring
If Google changes the title font size, every number above is wrong. Open a google.com results page in the interface language you care about and run this in the browser console:
(() => { const h = document.querySelector('a h3'), s = getComputedStyle(h);
const c = document.createElement('canvas').getContext('2d');
c.font = s.fontSize + ' ' + s.fontFamily;
return { font: s.fontSize + ' ' + s.fontFamily,
col: h.closest('div[data-hveid],div').getBoundingClientRect().width,
cjk: c.measureText('貓').width, digit: c.measureText('0').width }; })()If cjk is no longer 22, update EM and the thresholds in src/width.ts.
If the font changes, regenerate the ASCII table with
python scripts/measure-arial.py path/to/font.ttf. Do not measure with
Pillow at 22px directly: hinting rounds each advance to a whole pixel
(W becomes 21), while browsers use the unhinted widths.
Install
Requires Node.js 18 or later. No API keys, no network access.
MCP server
{
"mcpServers": {
"serp-title-width": { "command": "npx", "args": ["-y", "mcp-server-serp-title-width"] }
}
}CLI
npx -y -p mcp-server-serp-title-width serp-title-width ./publicor install it once with npm install -g mcp-server-serp-title-width and run
serp-title-width.
CLI usage
serp-title-width <file|dir> ... check <title> in .html/.htm files (directories are recursive)
serp-title-width --titles "t1" "t2" ... check title strings
serp-title-width ... --json machine-readable output
serp-title-width --selftest run the ruler's positive and negative controls (use alone)Example:
$ serp-title-width --titles "家常料理食譜站|滷肉飯做法・便當菜色・120道快速晚餐" \
"旗艦手機開箱|SAMSUNG GALAXY S26 ULTRA VS GOOGLE PIXEL" "京都三天兩夜行程"
Checked 3 title(s). Safe <= 572px / edge > 630px / cut > 648px (Arial 22px, measured 2026-09-18).
------------------------------------------------------------------------------
[FAIL] (input 2)
旗艦手機開箱|SAMSUNG GALAXY S26 ULTRA VS GOOGLE PIXEL
688.3px / 31.3 full-width characters / cut
[FAIL] Cut: 688px (31.3 full-width characters), 40px over the 648px line. Desktop results will truncate it.
[warn] Keyword zone (text before the first ?:、,) is 688px, wider than the 343px first line on mobile, so the line breaks inside it.
[warn] (input 1)
家常料理食譜站|滷肉飯做法・便當菜色・120道快速晚餐
564.7px / 25.7 full-width characters / safe
[warn] Keyword zone (text before the first ?:、,) is 565px, wider than the 343px first line on mobile, so the line breaks inside it.
[ok] (input 3)
京都三天兩夜行程
176.0px / 8.0 full-width characters / safe
------------------------------------------------------------------------------
Passed 2 / must fix 1The second title is 47 characters, under a typical 60-character limit, and 688px wide. When scanning files, only titles with a finding are listed, each with its path under the folder you gave. Check a whole site at once so boilerplate tails across pages are detected.
What is read from disk:
A directory is searched recursively for
.htmland.htmfiles.node_modulesand anything starting with.(such as.git) are skipped, and symbolic links to folders are not followed.A file named explicitly is read whatever its extension, so
serp-title-width page.php.txtworks.A scan stops with exit code 2 after 20,000 HTML files, which usually means the path is not a site's build output.
Only the
<title>in the document head counts. Titles inside comments,<svg>,<math>,<script>,<style>,<template>and<noscript>, or after the head has ended, are ignored.
Exit codes
Code | Meaning |
0 | Every title passes (warnings allowed) |
1 | At least one title must be fixed |
2 | The ruler failed its own controls, or bad input: unknown option, path not found, path or subfolder not readable, more than 20,000 HTML files, no |
The selftest runs before every verdict. If the ruler cannot show that it still flags known-bad titles and passes known-good ones, it gives no verdict.
MCP tools
Tool | Input | What it does |
|
| Measures each title and checks the whole set together |
|
| Reads the head |
Each result has px, full_width_units (px / 22), tier, fails and warns
(each finding is {rule, message}), plus boilerplate_tails for the set and a
verdict of pass or fix. The server runs the selftest at startup and
refuses to start if it fails.
Rules
Rule | Level | Condition | Reason |
| fail | wider than 648px | Wider than the desktop column |
| fail | wider than 630px | Near the measured desktop single-line limit |
| warn | wider than 572px | Over the conservative safe line |
| warn within 572px, fail over 572px | more than 2 of | In the sample behind this model, where Google cut a long zh-TW title, the cut fell on one of these marks. Small sample: treat as a heuristic. A title within the safe line is rarely shortened, so there it only warns |
| fail | more than 1 full-width | Editorial rule: one title, one question. Not from Google's documentation |
| fail | the phrase after the last | Google's title link documentation names boilerplate titles as a problem. Text after a colon is not counted: the same documentation suggests putting the site name at the start or end of each title, separated by a hyphen, colon or pipe, so |
| warn | text before the first | On mobile the first line breaks inside the main keyword |
| fail | title is empty or whitespace | |
| fail | the same run of 2-4 CJK ideographs appears 3 or more times | Google's title link documentation advises against keyword stuffing. Runs are split greedily, so this catches literal repeats such as |
Limitations
Measured for one setting. google.com, zh-TW interface, Chrome on Windows, 2026-09-18. Other interface languages, browsers or operating systems can use different fonts and widths.
Japanese and Korean were not measured separately. Kana and Hangul use the same full-width assumption (East Asian Width W), which matches how they are normally set, but nobody measured google.co.jp or google.co.kr for this model. Treat results for those languages as estimates.
Kerning is not modelled. Widths are added one character at a time. Chrome also adjusts the space between some letter pairs, which makes text slightly narrower: the all-caps example above is 688.3px here and 686.7px in Chrome's canvas with its default kerning. Results err on the long side.
Half-width characters outside ASCII are estimated at 12.2px. Their real Arial widths vary:
éand–are 12.24px,“7.33px,‘4.89px,Æand™22px.Ambiguous-width characters (East Asian Width A, for example
①※…) are counted as half width. Depending on the fallback font they can render wider.Google may display something else. It builds title links from several sources besides
<title>, including headings,og:title, anchor text andWebSitestructured data (which carries the site name), may replace a title it considers boilerplate or inaccurate, and may omit a site name that repeats the one already shown. Text that is not in your<title>can therefore appear in the result. A passing title is not a guarantee of what is shown.Emoji are not measured. Each emoji grapheme cluster counts as one full-width character when its first code point is full width or it carries the emoji presentation selector U+FE0F. Other emoji (such as flags, which Windows shows as two letters) count by their first code point.
HTML reading is simple. The head
<title>is found with patterns, not a full HTML parser.& < > " ' and numeric references are decoded; other named references are measured as written.
Port and parity
This is a TypeScript port of a Python implementation of the same model, which is not published. The port changes four things on purpose:
Cause | Change |
| All 95 printable ASCII characters use Arial's own widths. The first reference had 14 values, with |
| Zero-width characters count 0 and each grapheme cluster counts once |
| A phrase after |
| More than 2 separators only warn within the 572px safe line |
The shipped code can be switched back to the reference's behaviour, so
scripts/parity.mjs --ref <title_check.py> checks two things: the code in
that mode matches the reference exactly, and every difference in normal mode
has one of the four causes above. Results against the current reference:
287 mixed titles (Traditional Chinese, Japanese kana, Korean Hangul, Latin, digits, full-width punctuation, emoji, whitespace edge cases): in the reference's mode, pixel widths, boilerplate tails and the ordered list of failed and warned rules are identical. In normal mode 27 verdicts differ, all with a named cause:
colon-tail21,separator-tier4,zero-width3 (one title can have more than one). Against the first reference,ascii-widthalso changes 4 verdicts, including the all-caps example above.Every code point from U+0020 to U+FFFF (63,456, surrogates excluded): in the reference's mode, the widths differ only where the two sides use different Unicode data. Against Python 3.10 (Unicode 13.0), 1,613 code points differ: 1,392 are unassigned (CPython before 3.12 reports East Asian Width F for unassigned code points), 143 were assigned after Unicode 13.0, and 78 changed from N to W in later Unicode (U+2630-U+2637, U+268A-U+268F, U+4DC0-U+4DFF). Against Python 3.12 (Unicode 15.0), 85 differ: the same 78 plus 7 newer assignments. This package follows the newer data from
get-east-asian-width. In normal mode, 21 more differ, all zero-width characters.
License
MIT.
Maintainer
Built and maintained by Ads & Code.
Available Tools
2 toolscheck_title_filesA
Read the first element from local .html/.htm files and run the same pixel-width checks as measure_titles across all of them. Each path may be a file (read whatever its extension) or a directory; directories are searched recursively for .html and .htm files, skipping node_modules and names that start with '.', and stop with an error after 20000 files. Only the title in the document head counts; titles in comments, , and similar are ignored. Reads only, never writes. Character references & < > " ' and numeric references are decoded before measuring. Model: Google search results on google.com with the zh-TW (Traditional Chinese, Taiwan) interface, Chrome on Windows, title font Arial 22px, desktop result column 652px, mobile first line 343px, measured 2026-09-18. Full-width characters (East Asian Width W or F: CJK ideographs, kana, Hangul, full-width punctuation, most emoji) count 22px; printable ASCII uses Arial's own advance widths at 22px; other half-width characters count 12.2px; zero-width characters count 0 and each grapheme cluster (such as an emoji ZWJ sequence) counts once. Kerning is not modelled. Tiers: safe <= 572px, long > 572px (warning), edge > 630px (must fix), cut > 648px (must fix). Japanese and Korean use the same full-width assumption but were not separately measured. Google may rewrite title links, so a passing title is not a guarantee of what is displayed. Fails: tier edge or cut; more than 2 separators (、 or ,) in a title over 572px; more than 1 full-width question mark (?); a trailing phrase after the last 、 or , shared by more than 2 titles in the same call (boilerplate; a site name after a colon is not counted, as Google suggests that pattern); empty title; the same 2-4 ideograph run 3 or more times (keyword stuffing). Warnings: tier long; more than 2 separators in a title within 572px; text before the first ?:、,wider than the 343px mobile first line.
| Name | Required | Description | Default |
|---|---|---|---|
| paths | Yes | Absolute paths to HTML files or directories on this machine, e.g. a static site's build output. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so thoroughly: it states that the tool is read-only, never writes, recursively searches directories, skips node_modules and dot-prefixed names, errors after 20000 files, decodes character references, and details the exact measurement model, tiers, failure conditions, and warnings.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but front-loaded with purpose, path handling, and the most important behavioral rules. The measurement model and fail/warning criteria are dense yet relevant; the single-paragraph structure makes it harder to scan than a headed breakdown would.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must explain what the checks produce. It does this by defining the tier thresholds and enumerating failure and warning conditions, along with caveats about Google rewriting titles and Japanese/Korean not being separately measured.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is a 3, but the description adds meaningful path semantics beyond the schema: each path may be a file or directory, file extensions are read as given, directories are searched recursively, and certain directories are skipped.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: reading the first <title> element from local .html/.htm files and running pixel-width checks. It explicitly distinguishes the tool from its sibling by saying it runs the same checks as measure_titles across all of the given files.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes clear that this is the batch/local-file counterpart to measure_titles and explains directory recursion, skipping rules, and the 20000-file limit. It does not explicitly state when to prefer measure_titles over this tool, so it falls short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
measure_titlesA
Measure page titles by rendered pixel width in Google search results, not by character count, and check them for truncation and title-link problems. Pass every title of a site in one call so boilerplate tails shared across titles are detected. Returns per title: px, full_width_units (px / 22), tier (safe/long/edge/cut), fails, warns; plus boilerplate_tails for the whole set and verdict 'fix' if any title fails. Model: Google search results on google.com with the zh-TW (Traditional Chinese, Taiwan) interface, Chrome on Windows, title font Arial 22px, desktop result column 652px, mobile first line 343px, measured 2026-09-18. Full-width characters (East Asian Width W or F: CJK ideographs, kana, Hangul, full-width punctuation, most emoji) count 22px; printable ASCII uses Arial's own advance widths at 22px; other half-width characters count 12.2px; zero-width characters count 0 and each grapheme cluster (such as an emoji ZWJ sequence) counts once. Kerning is not modelled. Tiers: safe <= 572px, long > 572px (warning), edge > 630px (must fix), cut > 648px (must fix). Japanese and Korean use the same full-width assumption but were not separately measured. Google may rewrite title links, so a passing title is not a guarantee of what is displayed. Fails: tier edge or cut; more than 2 separators (、 or ,) in a title over 572px; more than 1 full-width question mark (?); a trailing phrase after the last 、 or , shared by more than 2 titles in the same call (boilerplate; a site name after a colon is not counted, as Google suggests that pattern); empty title; the same 2-4 ideograph run 3 or more times (keyword stuffing). Warnings: tier long; more than 2 separators in a title within 572px; text before the first ?:、,wider than the 343px mobile first line.
| Name | Required | Description | Default |
|---|---|---|---|
| titles | Yes | Title strings exactly as they appear in <title>, already decoded ("&" not "&"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so thoroughly: it explains the measurement model, pixel assumptions, tier thresholds, failure and warning conditions, and important caveats such as unmodeled kerning and Google's possible title rewriting. This is unusually complete for an unannotated tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long and dense, but it is front-loaded with the core purpose and organized into outputs, model assumptions, tiers, fails, and warnings. Most sentences provide substantive rules or caveats rather than filler, though the length may challenge quick scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a single parameter, no annotations, and no output schema, the description supplies everything an agent needs: purpose, expected input batching, returned fields, measurement assumptions, thresholds, and detailed fail/warn criteria. It is complete for correct invocation and interpretation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the single titles parameter is already well documented in the schema. The description adds meaningful batch semantics by requiring all titles of a site in one call for boilerplate detection, which is valuable context beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: measuring page titles by rendered pixel width and checking truncation and title-link problems. It is very clear about what the tool does, though it does not explicitly compare itself to the sibling check_title_files tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear usage instruction to pass every title of a site in one call so that shared boilerplate tails can be detected. It does not state when not to use the tool or explicitly name check_title_files as an alternative, so it falls short of full alternative guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
check_title_files - First observed
measure_titles
TDQS
Scored across 2 tools
The two tools are cleanly separated by input source: measure_titles takes title strings directly, while check_title_files takes file/directory paths and extracts titles itself. There is no realistic scenario where an agent would struggle to pick between them.
Both names follow a verb_noun snake_case pattern (measure_titles, check_title_files). The verbs differ slightly (measure vs check) for what is essentially the same underlying check, but the nouns make the distinction clear.
Two tools is thin in absolute terms but appropriate for this narrow, single-purpose server (pixel-width title auditing). Each tool covers a distinct input mode and neither feels redundant.
The surface covers the two main ways an agent would obtain titles: raw strings and local HTML files, with directory recursion and entity decoding handled. Minor gaps exist (no URL fetching or batch input from a file of plain titles), but agents can work around these by passing strings directly.
Maintenance
Related MCP Connectors
Technical SEO and AI-readiness audits for any page, plus a check that your fix worked.
31Turn the AI you already pay for into an SEO agent: measured topics, SERP briefs, rule-checked drafts
Audit pages for SEO and AI search: scores, fixes, AI crawler access, llms.txt. Pay per use.
Website checker for AI coding agents. Measures your site in a real browser, with evidence.
Related MCP Servers
- AlicenseBqualityCmaintenanceProvides technical SEO tools for AI agents, including structured data generation, meta tag creation, robots.txt validation, and SERP previews, all offline with no API key or account.1820 PyPIMIT
- AlicenseNot gradedqualityAmaintenanceProvides agents with tools to score a page's AI readiness, check which AI crawlers robots.txt blocks, and assess passage citability—all performed locally.27 npm2MIT
- AlicenseAqualityBmaintenanceFree SEO + GEO (AI-search-citation) analysis for AI assistants: full SEO audits, AI-crawler-access checks (GPTBot/ClaudeBot/PerplexityBot), Core Web Vitals, structured data, security headers, mobile, and images. No signup, no API key, nothing sent to any server - runs entirely on the user's machine.1367 npm1MIT
- AlicenseAqualityCmaintenanceEnables local validation of supplied HTML for SEO metadata and JSON-LD structured data, checking titles, meta descriptions, H1s, image alt attributes, and JSON syntax errors.280 npmMIT