Squint
The server’s provided schema exposes only the ping tool.
Confirm the server is alive.
Get the server’s
nameandversion.Optionally send a
message, which is echoed back in the response.
Note: the README documents additional tools (inspect_element, detect_visual_bugs, extract_tokens) for visual inspection and design-token extraction, but they are not present in the provided schema.
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., "@Squintopen http://localhost:5173 and tell me which element is visually broken"
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.
Squint
Squint is an MCP server that examines a rendered web page by crossing what the browser reports (DOM/CSS) with what is actually painted (pixels), and reports the visual problems it finds without needing a baseline.
It is built for coding agents that have just produced UI and need to know whether the page actually looks right: which element is broken, and what the evidence is.
Install
Requires uv. uv installs Python 3.12 for you if it is missing. Two steps:
uvx --from squint-mcp playwright install chromium # the browser Squint drives
uvx squint-mcp # the serverThe first step goes through squint-mcp so the Chromium downloaded is the one its Playwright expects; uv warns that playwright comes from a dependency, which is expected. On Linux, add --with-deps to also install the system libraries Chromium needs.
The server speaks MCP over stdio, so started by hand it just waits for a client. Register it in your MCP client instead:
{
"mcpServers": {
"squint": {
"command": "uvx",
"args": ["squint-mcp"]
}
}
}In Claude Code: claude mcp add squint -- uvx squint-mcp.
Then call ping to confirm the connection.
Related MCP server: UI Analyzer MCP Server
Tools
The server exposes four tools:
Tool | Input | Output |
|
| server |
|
| one element's computed styles, box model, sampled colours, |
|
| Findings ordered by severity, |
|
| the design tokens the page uses, in eight Families, each token with how many elements use it, and |
detect_visual_bugs runs five Checks: text-clipped (text cut off by its own box), low-contrast-real (text whose contrast against the background sampled from the pixels is below WCAG 2.2 SC 1.4.3, so it is right over images and gradients), offscreen-overflow (the element that makes the page scroll horizontally), overlap (text that another element is painted over, with how much of it is hidden and which element covers it) and font-fallback (a web font the page declares that did not load, with how many elements render their text in a fallback font). See docs/SPEC.md for the v0.1 specification and CHANGELOG.md for what each release contains.
extract_tokens reads the values a rendered page is styled with. scope is a CSS selector that reaches into open shadow roots: the reading is narrowed to its matches and every element under them. It returns eight Families: colors (by role: text, background, border), typography.families, typography.sizes, typography.weights, typography.lineHeights, spacing in px (by role: margin, padding, gap), radii and shadows. A token counts its uses: one use is one element that paints a box, is visible and is not under an opacity of 0, having that value in that role, and a value on several sides, corners or axes of one element is one use. Type values and text shadows count only on elements whose own text is painted, where the text is. A border side counts in the border role only when it has a width and its style is not outset, inset, groove or ridge: those are painted in shades of their colour, or by the theme of a form control such as a default <button>, never in the colour itself. Values nearly equal are one token, whose value is the most used and whose variants list each with its own count:
colours of one alpha whose ΔE2000 is below 2, the just noticeable difference of CSS Color Module Level 4 (section 20.2 for the formula, section 14.2.1 for the value; reading it as one token is Squint's);
font sizes, line heights, spacings and px radii less than 1px apart, a Squint default with no norm behind it: a Capture has one image pixel per CSS pixel, and the whole steps of a scale stay apart.
Each Family returns at most 20 tokens, the most used, and its total counts every token it found.
Pages behind a login
Every call opens its page with no cookies, so a page behind a login is examined as its login screen. To examine it logged in, log in once and save the session to a file in Playwright's storage state format:
uvx --from squint-mcp playwright codegen --save-storage=/home/me/admin-state.json https://example.com/adminLog in in the window that opens, then close it: the file holds the cookies and localStorage of the session. Pass its absolute path as storageState to inspect_element, detect_visual_bugs or extract_tokens. Each call loads it into a fresh context and never writes it, so calls stay isolated from one another.
The file holds the secrets of the session: anyone who has it is logged in. Keep it out of the repository; do not commit it.
sessionStorageis not carried. A page that keeps its session there opens logged out.When the session expires, the calls examine the login screen again, with no error: save the file anew.
The calls see the first screen after the login. A state reached only by clicking, such as a dialog or an editor with no URL of its own, is out of reach.
Development
Run from a checkout:
git clone https://github.com/sh4wty1/squint-mcp.git
cd squint-mcp
uv sync
uv run playwright install chromium # the tests drive a real Chromium
uv run squint-mcpTo point an MCP client at the checkout, use "command": "uv" with "args": ["run", "--directory", "/path/to/squint-mcp", "squint-mcp"].
One command each:
uv run pyright # typecheck (strict)
uv run ruff check # lint
uv run ruff format --check # format check
uv run pytest # testsTests drive the server through an in-memory MCP client, the same surface a real client uses. See CONTRIBUTING.md.
Documentation
CONTEXT.md: domain glossary (Capture, Check, Finding, Profile, Audit)docs/SPEC.md: v0.1 specificationdocs/adr/: architecture decision records
License
Available Tools
1 toolpingARead-only
Confirm the server is alive.
Returns the server name and version, and echoes `message` when given.
| Name | Required | Description | Default |
|---|---|---|---|
| message | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| message | Yes | |
| version | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, so the agent knows this is a safe, purely local read. The description reinforces that nothing is mutated, and the mention of the echo behavior adds modest context, but it doesn't discuss auth, rate limits, or failure modes beyond what the annotations and output schema already imply.
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?
Two short sentences, the purpose first and the return/echo behavior second. Nothing is padded and no sentence is wasted.
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?
For a one-parameter, zero-required liveness tool with an output schema documenting the return payload and annotations covering the safety profile, the description supplies everything an agent needs: what it checks, when it is useful, and how the input is handled.
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 description coverage is 0%, so the description must compensate for the single `message` parameter — and it does, explaining that the value is echoed back when supplied, which clarifies it is an optional round-trip probe rather than a filter or identifier. It stops short of noting the null default explicitly.
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?
States a specific verb and object ('confirm the server is alive') plus the observable effect ('returns the server name and version'). An agent immediately understands this is a liveness/health probe, and there are no siblings to disambiguate against.
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 name and description jointly signal the use case: verifying server availability before or after other operations. There are no alternatives to name and no explicit when-not condition, but for a single sibling-less health-check tool the context is unambiguous.
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.
1 tool update
v0.1.0- First observed
ping
TDQS
Scored across 1 tool
With only a single tool there is no possibility of overlap or misselection, so the lone tool is trivially unambiguous. However, there is no meaningful set to disambiguate among, so it does not demonstrate strong design.
The single name 'ping' is clear and conventional for a health-check, but with only one tool there is no pattern to establish consistency and no verb_noun structure to evaluate.
A server exposing only one trivial liveness tool is far too thin for any real purpose. The count is essentially a minimal stub rather than a scoped toolset.
The surface offers only a ping with no domain operations at all, leaving no create/read/update/delete or lifecycle coverage. Any actual task would be a dead end.
Maintenance
Related MCP Connectors
Website checker for AI coding agents. Measures your site in a real browser, with evidence.
Read-only web QA agent: scans a site in a real browser and returns evidence-backed findings
Playwright selector risk checks with healing suggestions and receipts.
Browser-backed QA with evidence and fix-ready reports for coding agents.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables AI assistants to inspect, debug, and test web pages using Playwright. Provides comprehensive DOM inspection, visibility debugging, layout validation, and element finding capabilities in real browser environments.3466 npm5MIT
- AlicenseNot gradedqualityDmaintenanceAnalyzes website UIs using Playwright and provides precise CSS/HTML fix instructions for AI coding assistants like GitHub Copilot and Cursor.4MIT
- AlicenseAqualityBmaintenanceEnables AI coding agents to see, measure, and verify web pages through a real Chrome browser, including screenshots, responsive layout and accessibility audits, pixel diffing against baselines, secure logins, and deployed-fix verification.271MIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to run an evidence-backed visual QA loop for browser interfaces, including inspecting a running app, retrieving findings with screenshots, and rechecking only the captures affected by a fix.MIT