DEV Community

Hiroki Nomura
Hiroki Nomura

Posted on Fully Autonomous

I scored the tool descriptions of Chrome DevTools MCP and Playwright MCP. Both rarely say when to use a tool

I scored the tool descriptions of two browser-automation MCP servers: Google's Chrome DevTools MCP and Microsoft's Playwright MCP. They averaged 45.1 and 41.9 out of 100. In Chrome DevTools MCP, 24 of 30 tools never say when to use them; in Playwright MCP, 23 of 25. And 27 and 21 tools respectively don't say what they return.

The scoring was done with Forecall, a static linter for MCP tool descriptions that I build. This post shows the results, what separates the low-scoring descriptions from the high-scoring ones, what happened when I added three sentences to one of them, and what real models then did with both versions.

An agent picks a tool from its name, description and input schema, and nothing else

An AI agent reads the list of tools an MCP server returns (the result of tools/list) and decides which tool to call with which arguments. All it has to go on are three things: the tool's name, its description and its input schema.

If the description only restates the name, the name and the schema are all the model has, and nothing tells it what a call returns until it makes one. Whether that is enough can only be measured with real models; I did that later in this post.

How I scored them: get tools/list, then score six parts out of 100

On October 7, 2026, I started these two versions locally and saved their tools/list results as JSON. No tools were called.

Server Package and version Tools
Chrome DevTools MCP chrome-devtools-mcp@1.10.1 30
Playwright MCP @playwright/mcp@0.0.83 25

I scored the JSON with Forecall's CLI (npx forecall lint). It scores each tool on six parts:

Part Points What it looks for
Purpose 20 What the tool does, beyond restating its name
When to use 20 When to use it, and how to choose between similar tools
Arguments 25 Each argument described, with its type and whether it's required
Return value 15 What comes back, in an output schema or the description
Constraints and side effects 10 Preconditions and side effects
Examples 10 An example of a call

The scoring is rule-based and reads only the text of the descriptions and schemas. It doesn't measure whether a real model picks the right tool; I come back to that limit at the end. (I re-scored both servers on October 10 with the current rules, v2, and got the same numbers.)

Results: both average in the 40s, and they're weak in the same places

Chrome DevTools MCP Playwright MCP
Average score 45.1 41.9
No "when to use" 24 / 30 23 / 25
No "what it returns" 27 / 30 21 / 25
Description restates the name 6 14
Pairs with near-identical descriptions 0 0

In both, most of the lost points come from "when to use" and "return value". Both describe their arguments well, and neither has a pair of tools with near-identical descriptions; their tool names are clearly distinct.

Where they differ is how many descriptions only restate the name: 14 of Playwright MCP's 25 tools get that finding.

The low scorers end with one sentence that restates the name

The lowest scores were 31 in Chrome DevTools MCP (drag, hover, upload_file) and 33 in Playwright MCP (browser_handle_dialog, browser_navigate, browser_type and others). Their descriptions:

Tool Description
drag Drag an element onto another element
hover Hover over the provided element
browser_handle_dialog Handle a dialog
browser_navigate Navigate to a URL

They don't say when to call the tool, what's needed before calling it, or what comes back. browser_handle_dialog, for example, only makes sense while a dialog is open, but nothing in its description says so. That is what the linter measures: text that is missing. It doesn't show that a model will choose wrong, and for one-step choices, the test further down found that it doesn't.

The high scorers say when to use the tool, with an example

The same servers also have tools that score well. Chrome DevTools MCP's best is fill_form, at 72:

Fill out multiple form elements (inputs, selects, checkboxes, radios) at once. ALWAYS prefer this tool over multiple individual 'fill' or 'click' calls when interacting with forms. It is significantly faster, more reliable, and reduces turn count. Example: Fill username, password, and check "Remember Me" in one call.

It says how to choose between it and fill or click, and gives a concrete example. The only thing missing is the return value.

Playwright MCP's best is browser_find, at 66. In one paragraph it explains what it searches for, what it returns, and why that's cheaper than taking a full snapshot.

Three sentences took drag's score from 31 to 74

I rewrote drag's description using only facts from its schema. I added three things: when to use it (and how it differs from upload_file), what to do before calling it, and what it returns.

Drag one element and drop it onto another inside the page. Use it for drag-and-drop UIs such as sortable lists, kanban boards and sliders; to send files from the computer, use upload_file instead. Take a snapshot first and pass the uids of both elements as from_uid and to_uid. Returns a snapshot of the page after the drop when includeSnapshot is true.
Enter fullscreen mode Exit fullscreen mode
Part Original Rewritten
Purpose 6 17
When to use 0 20
Arguments 18 18
Return value 0 7
Constraints and side effects 7 7
Examples 0 5
Total 31 74

That's 43 points. The sentence on when to use it did the most: "when to use" went from 0 to the full 20.

The rewrite also produced a new finding: the tool may be destructive but has no destructiveHint. It reacted to the word "drop". drag doesn't destroy anything on the page, so this finding is wrong. Setting destructiveHint: false in the tool's annotations makes it go away (the score stays at 74), and it also tells clients that the tool isn't destructive.

A higher score, though, is not the same as better picks. The next section checks that.

Then I tested real models: the short text was enough, and my rewrite made two models worse

A Chrome DevTools MCP maintainer asked for a concrete case where an agent is confused by the short descriptions. So I tried to produce one. A stand-in server returned chrome-devtools-mcp 1.10.1's tools/list, either as it is or with drag, hover and upload_file rewritten, and models got eight one-step tasks whose right tool is one of those three: a kanban card, a hover menu, a tooltip, an "Add photos" button, an avatar area that takes a dropped image, and so on.

  • With the descriptions as they are, no model picked a wrong tool: Claude Code with Fable 5.1, Sonnet 5.5 and Haiku 4.5 (24 of 24), Codex CLI with gpt-6-astra (11 of 11), and one-turn API calls to Claude Opus 5.5, Claude Sonnet 5.5, gpt-6-astra and gpt-6.1-sol (32 of 32). The only wrong picks, click instead of hover from two smaller Codex models, came from a task whose text was ambiguous.
  • My rewrites made two models worse. gpt-5.6-luna read "Use it for drag-and-drop UIs" against the avatar area that "accepts a dropped image", and called drag instead of upload_file in 2 of 4 runs (0 of 4 with the original). gpt-6-astra said it couldn't identify the tool for the "Add photos" task in 4 of 10 runs with my upload_file text (0 of 4 with the original).

So for a one-step choice, the one-line description plus the schema (from_uid/to_uid, filePaths) was enough, and the text that scores 74 cost accuracy on two models. The full table is in the issue thread. What the descriptions still don't say, what a call returns and that uids come from the latest snapshot, may matter in longer runs, which this test didn't cover.

A later, larger run with Forecall's own evaluation points the same way. Across all 30 Chrome DevTools MCP tools (8 requests per tool), Claude Sonnet 5.5 and GPT-6.1 Sol picked the right tool 99% and 98% of the time. And when a request didn't include a page number, they mostly called list_pages first (77–87% of such requests), which is the right move.

Try it on your own server

Get your server's tools/list and score it:

npx forecall dump -o tools.json -- <command that starts your server>
npx forecall lint tools.json
Enter fullscreen mode Exit fullscreen mode

Both run on your machine, and the results aren't sent anywhere. Add --fail-under 60 to fail a CI job when the average drops below 60. To try it in the browser instead, paste the same JSON at forecall.dev; no sign-up needed. For a public server that needs no sign-in, you can paste its URL there instead of JSON. Both servers' full results are at forecall.dev/en/servers/chrome-devtools and forecall.dev/en/servers/playwright.

One caveat. The score comes from reading the text alone, so a tool like browser_close, short but obvious from its name, scores low even when models use it correctly. Treat the score as a guide to where there's room to write more. Whether real models pick the right tools has to be measured another way, and as the test above shows, a higher score doesn't mean better picks.

Use the score to find gaps, then test any rewrite with real models

Google's and Microsoft's browser-automation servers describe their arguments carefully, but rarely say when to use a tool or what it returns. The linter finds those gaps quickly. It doesn't tell you that a model will choose wrong: for these three tools, the models I tested chose right with the one-line text, and my longer text made two of them worse.

For your own server, start with the lowest-scoring tools and fill in what's missing, such as what a call returns. Then check the new text with the models your users run before you ship it. Words like "drop", or a list of example UIs, can pull a model toward the wrong tool.

Update: I suggested rewrites upstream in microsoft/playwright-mcp#1788 and ChromeDevTools/chrome-devtools-mcp#3026. A Playwright maintainer closed that one, asking for a reproducible trajectory against a frontier model rather than a score. In #3026, after the test above, I withdrew the claim that the short descriptions confuse models.

I'm the author of Forecall. The linter is open source: github.com/forecall/forecall-cli.

Top comments (0)