webnav-ts-mcp
An MCP server that provides AI agents JS/TS/HTML/CSS code navigation and analysis, plus safe type-checked editing across files.
Find type/documentation info at any position (
hover) and jump to definitions (definition).Find all usages of a symbol across the workspace (
references, with optional declaration inclusion).Locate the correct project checkout/worktree (
workspace).Search JS/TS symbols by name with kind/path filters and fuzzy matching (
search_symbol).Get a one-call summary of a JS/TS symbol: header, hover, definition, grouped references (
symbol_info).See who calls a function/method via call hierarchy (
callers).See who implements or extends an interface, class, or method (
implementations).Get an indented source-order outline of a JS/TS file (
outline).Retrieve language-server diagnostics for a file, including unreferenced CSS selectors and undefined CSS variables (
diagnostics).Cross-reference CSS custom properties (
css_var) and#id/.classselectors (selector) across CSS, HTML, and JS.CSS/HTML token lookups fall back to a cross-file index that single-file language servers cannot provide.
Indexes and navigates CSS across the workspace: locates where custom properties (--name) and #id/.class selectors are defined and used across stylesheets, HTML and JS, and surfaces CSS diagnostics including unreferenced-selector and undefined-variable warnings (with an option to mark public stylesheets as an external API).
Provides name-based and position-based navigation of JS/TS source via the TypeScript 7 native language server: symbol info (header, hover, definition, references), file outlines, call hierarchy (callers), interface/class/method implementations, ranked workspace symbol search, hover/definition/references and diagnostics.
webnav-ts-mcp
An MCP server that gives AI agents JS/TS/HTML/CSS navigation, plus a
cross-file index of CSS custom properties and #id/.class selectors that
single-file language servers can't provide, and write tools that type-check an
edit before it is written. It needs only Node.js and installs with a web
project's own package manager.
Quick start
You need Node.js ≥ 20:
npx webnav-ts-mcpRegister it with your MCP host. For Claude Code, from the project root:
claude mcp add webnav -- npx webnav-ts-mcpOr add it to a project .mcp.json (Claude Code) or .cursor/mcp.json (Cursor):
{
"mcpServers": {
"webnav": {
"command": "npx",
"args": ["webnav-ts-mcp"]
}
}
}In Cursor, also set "env": {"WEBNAV_MCP_WORKSPACE": "${workspaceFolder}"},
because Cursor may start MCP servers with your home directory as the working
directory.
To pin it per project instead of resolving through npx each time:
npm install --save-dev webnav-ts-mcpRelated MCP server: ts-language-mcp
Language servers
Requests are routed to three Node language servers by file extension:
Extension | Backend |
| TypeScript 7 native LSP: |
|
|
|
|
They are ordinary npm dependencies, so nothing is downloaded at runtime. A TypeScript ≥ 7 in the navigated project wins; otherwise the copy installed with webnav-ts-mcp is used. (An app on an older TypeScript still works, at the cost of the extra install size: see Costs.)
Tools
For JS/TS, start with the name-based tools:
Tool | Answers |
| What is this? Header, hover, definition and references in one call |
| What's in this file? (source order; locals and imports left out unless |
| Who calls this function/method? (call hierarchy) |
| Who implements/extends this interface, class or method? |
| JS/TS workspace symbol search (ranked, capped; optional |
| Which directory is being navigated, and why |
Then use the position tools once you have a path:line:col:
Tool | Answers |
| Type and docs at a position |
| Go to definition (CSS/HTML tokens answer from the index below) |
| All usages (CSS/HTML tokens answer from the index below) |
| Language-server diagnostics; CSS/HTML also get unreferenced-selector and undefined-variable warnings |
Cross-file CSS/HTML index:
Tool | Answers |
| Where is |
| Where is |
search_symbol, symbol_info, outline, callers and implementations are
JS/TS only. Use css_var and selector for markup and stylesheets.
name and query are accepted as aliases of each other on the name-based tools.
Positions are 1-indexed; column is a UTF-16 character offset (a leading
tab counts as one character).
Write tools: change code with a type check before every write
The navigation tools above are read-only. These change code, and share one rule: the edit is shown to the language servers as an in-memory overlay first, the edited files and the script files importing them are re-checked, and the response says which diagnostics the edit would add or fix. Nothing is written until that is on the table.
Tool | Does |
| Type-checked text edit of a JS/TS/HTML/CSS file: |
|
|
| JS/TS: rename through the TypeScript language server (imports, aliases, overriding members; |
| With |
| Apply the language server's own fixes (missing imports, misspellings, ...) one by one, re-checking after each; or a source action: |
| After editing with any tool (your own included): which diagnostics the working tree gained or lost since a git revision (default |
| Write a previewed edit by id; revert an applied one |
One rule for every write tool: it writes when the edit adds no more than
max_new_errors (default 0) errors in the edited files and their importers and
the result parses. Otherwise nothing is written and you get the diagnostics plus
an id for apply_edit. apply=false always previews. Hints and warnings are
shown but not counted. Syntax errors (TypeScript's 1xxx codes, any CSS error)
block a write even with max_new_errors=null.
Safety rules, enforced in code:
Only
.js/.mjs/.cjs/.jsx/.ts/.mts/.cts/.tsx/.html/.cssfiles inside the workspace are edited (movealso carries any file, such as an image a stylesheet uses);node_modules,dist,.gitand the other skipped folders, generated output (WEBNAV_MCP_EXCLUDE) and symlinks are refused.A preview remembers the exact bytes of every file;
apply_editrefuses if any file changed since. Files are replaced atomically (temp file + rename), and a failure part-way restores the ones already written.Every applied edit is undoable (
undo_edit) unless a file was changed after it.Line endings and a leading BOM are preserved.
Edits touching more than 40 files need
allow_large=true.WEBNAV_MCP_READ_ONLY=1turns every write into a refusal (previews still work).
Scope: the importers that get re-checked are found by relative import/export ... from/require()/import() specifiers (./a, ./a.js for a.ts, ./dir
for dir/index.ts); a file reached only through a path alias is checked with its
own edit alone. move's HTML/CSS rewrite understands relative and root-absolute
(/src/main.ts) references; bundler config, path aliases and string paths are
listed as mentions, not rewritten. HTML/CSS edits are checked by their language
servers (syntax and CSS lint), not against the cross-file index.
Environment
Variable | Default | Purpose |
| unset: follows the client's MCP roots when they name a worktree of the same git repository, else | Pins the project root (never overridden). See the |
| the whole workspace as one root, labelled | Comma-separated |
| nothing | Comma-separated workspace-relative paths of generated script output (e.g. the JS a TS build emits). Not opened, hidden from |
| unset |
|
| nothing | Comma-separated workspace-relative stylesheets (files or directories) that are a public API, e.g. a design-token file consumed by other projects. |
Layout
src/
cli.ts stdio entry point (exits when the host closes stdin)
server.ts registers the tools on the MCP SDK
webnav.ts the tools as plain async functions returning text; owns all state
webIndex.ts CSS var / selector index
langCommand.ts how to launch tsc / html / css language servers
glob.ts just enough glob for jsconfig `include`
shared/ lspClient, format, resolve, workspace, notices, errors,
params, exclude
write/ the write tools: edits (plans, diffs), transaction (guard,
journal, undo), simulate + diagnosticsDelta (the type check),
finish (preview/apply), one module per tool, webTokens
(CSS var/id/class finder), jsImports (import rewriting)
tests/ vitest; fixtures/sample-app is the shared fixtureDevelopment
npm install
npm run check # biome + tsc + vitest (pretest builds dist/)
npm run upload # check + publish to npm (--build-only / --dry-run / --otp CODE after `--`); needs `npm login`
npm run test-package # install the published version in a throwaway project and drive it over MCP stdio
node bin/launch.mjs # checkout launcher: installs + builds when needed, then starts the serverSource: github.com/illescasDaniel/webnav-ts-mcp.
Design notes
webnav is glue: it spawns three Node language servers and formats their answers,
plus a regex-grade index.
Tests: vitest (unit tests for the index/format code and the pure parts of the
write tools, real language servers against the fixture and temporary projects,
MCP protocol over an in-memory transport incl. worktree selection via client roots
with a real git worktree, LSP client failure modes, and the built executable).
Things worth knowing
The MCP SDK's stdio server does not treat stdin EOF as a close. With a language server child alive, the process kept running after the host went away (found by installing the tarball and launching via
npx).cli.tsnow handlesstdinend/close;tests/cli.test.tsfails without it.Columns are UTF-16 offsets, which is what LSP uses and what JS strings already are, so no conversion is needed.
Regex index limit:
\wis ASCII in JS. The index regexes use(?<![\w-])to avoid matchingdata-id=, so a non-ASCII letter directly beforeid=/class=/style=still counts as a match. Vanishingly rare in real markup.Inherited-member lookup needs a different approach. TypeScript 7's language server advertises no type hierarchy (checked against its
initializecapabilities), so a member declared on a base class can't be found that way. webnav reads theextends/implementsclauses from the source and resolves each base withtextDocument/definition, breadth-first across files (generic bases, qualified names and mixin calls handled;.d.ts/node_modulesbases aren't followed).callersandimplementationsare offered because the server advertisescallHierarchyProviderandimplementationProvider.Type-checking an edit without writing it relies on documents the client opens with
didOpen/didChangeshadowing the disk (LspClient.withOverlay). tsc's native server resolves imports of a file that exists only as an overlay, but needs its directory to exist and remembers a failed resolution, so the overlay opens new files first and creates (then removes) empty directories.A file with no
import/exportis a global script to TypeScript. Moving the last export out of a module turns it into one, and every top-level name in it becomes visible everywhere; the type check can then miss references that should have broken.Symbol ranges from
documentSymbolare tight: no doc comment, noexport constkeyword, one symbol per declarator.edit_symbolandmovewiden them (extentOf) and refuse declarators that share a statement.The server's unused-import hints identify what a deletion orphaned: hints after the edit minus hints before it, so imports that were already unused stay.
Costs
Install size: a fresh app installing this next to its own TypeScript 5: 177 MB
node_modules(vscode-langservers-extracted66 MB, TypeScript 7 ~50 MB with its native binary). An app already on TypeScript ≥ 7 shares that copy.Not verified: Windows, macOS, Node 20/24. Only Linux + Node 22.
License
MIT. See LICENSE.
Available Tools
12 toolscallersA
Who calls this function? Example: callers(name="renderSidebar").
Narrower than references, since it leaves out imports and type-only usages and only lists actual call sites, each with the calling function and its call-site lines. name resolves the same way as symbol_info (dotted Class.method accepted, inherited members included; pass file_path to disambiguate a common name). query is accepted as an alias for name. JS/TS only.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| query | No | ||
| file_path | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the return content (calling function plus call-site lines), the symbol-resolution rules, and the JS/TS-only limitation. It does not cover failure modes (e.g. unresolved names) or whether results are paginated, but for a read-only query tool the disclosure is strong.
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?
Front-loaded with the core question and an example before any elaboration, and every subsequent sentence adds a distinct fact (scope vs references, resolution rules, alias, language limit). It is dense but not padded, though the mid-paragraph resolution detail is slightly heavy for a first read.
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?
With no annotations and no output schema, the description supplies the return shape, the scoping semantics, the alias, and the language constraint, which is enough to call it correctly. Minor gaps remain around result limits and behavior when a symbol cannot be resolved.
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 0%, so the description must compensate and largely does: it explains that `name` accepts dotted `Class.method` with inherited members, that `file_path` disambiguates a common name, and that `query` is an alias for `name`. Only the exact error/empty behavior of an unresolved `name` is left unexplained.
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 opens with a direct question-and-verb statement ('Who calls this function?') plus a concrete invocation example, and explicitly distinguishes itself from the sibling `references` tool by scope. An agent can tell instantly what resource it operates on and how it differs from the nearest alternative.
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 names the alternative (`references`) and the exact condition that separates them: callers omits imports and type-only usages and lists only actual call sites. It also states the language restriction ('JS/TS only'), which is a hard when-not-to-use boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
css_varA
Where is this --custom-property defined and used? Example: css_var(name="--bg").
The CSS/HTML language servers only see one file at a time, so var(--x) usages can't be cross-referenced across files that way. This scans .css files and HTML <style>/style="…" blocks/attributes instead. name may be given with or without the leading --. Definitions (value + enclosing context, e.g. @media (prefers-color-scheme: dark) › :root) and usages (grouped by file with line numbers) are reported separately per configured root (see WEBNAV_MCP_ROOTS; a single unnamed root by default), since each may define its own values. query is accepted as an alias for name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| query | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations the description carries the full burden and does well: it discloses the scan scope (`.css` files plus HTML style blocks/attributes), that definitions and usages are reported separately per configured root, and references the `WEBNAV_MCP_ROOTS` config with a single unnamed root default. It stops short of noting scanning cost, limits, or ignored files.
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 core question is front-loaded with an inline example (`css_var(name="--bg")`), and the remaining sentences each add distinct detail (cross-file rationale, scan scope, output grouping, roots, alias). It is dense and slightly long but no sentence is redundant.
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 describe returns, and it does: definitions include value plus enclosing context (e.g. `@media (...) › :root`) and usages are grouped by file with line numbers, per root. For a 2-param, no-annotation tool this is nearly complete, missing only error/empty-result behavior.
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 0%, so the description must compensate, and it does: it states `name` may be supplied with or without the leading `--`, and that `query` is an accepted alias for `name`. Both parameters are addressed, though neither is marked optional despite required count being zero.
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 opening question states a specific resource (a `--custom-property`) and the exact action (finding where it is defined and used). It also draws an explicit boundary against sibling language-server tools like `references`/`definition` by noting those only see one file at a time, so an agent can route correctly without opening a schema.
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 clearly implies when to use this over the file-scoped language servers: cross-file `var(--x)` lookups across `.css` files and HTML `<style>`/`style=` blocks. There is no explicit 'do not use when' clause, but the alternative and its limitation are spelled out, which is strong routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
definitionA
Go to the definition of the symbol at a position.
line and column are 1-indexed. column is a UTF-16 character offset on the line (not a visual/display column): a leading tab counts as one character. On a --custom-property/#id/.class token in a .css/.html file (or a name inside an HTML id="..."/class="..." value), answers from the cross-file index (see css_var/selector) instead of the single-file language server: for definition, just the definition(s) in the file's own root (each WEBNAV_MCP_ROOTS root is separate); for references, that root's definitions and usages.
| Name | Required | Description | Default |
|---|---|---|---|
| line | Yes | ||
| column | Yes | ||
| file_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses the 1-indexed, UTF-16 offset convention, tab handling, and that CSS tokens are answered from a cross-file index scoped per WEBNAV_MCP_ROOTS root. It does not describe the return shape or a 'no definition found' behavior, keeping it short of a 5.
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?
Front-loaded with the core action, then supporting detail. The CSS parenthetical is long and dense but every clause adds real semantic value, so little 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 3-param positional tool with no annotations and no output schema, the description covers position semantics and the CSS special case well, but omits what is returned (a definition location list) and what happens on failure. Adequate but with clear gaps.
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 0%, so the description must compensate, and it does for the two non-obvious parameters: line/column are 1-indexed with column being a UTF-16 character offset where a tab is one character. Only file_path's meaning is left implicit, which is acceptable given its obviousness.
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 resource ('Go to the definition of the symbol at a position') that an agent can distinguish from siblings like references, hover, and symbol_info. It even clarifies the difference from references in the CSS special case, so the purpose is unambiguous.
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 gives rich context for the CSS/custom-property case, but it never explicitly says when to choose this over siblings like hover, symbol_info, or implementations. Usage is implied by the tool name rather than stated as guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagnosticsA
Get the relevant language server's diagnostics (errors/warnings) for a single file.
For .css/.html files, this also includes index-derived warnings the single-file language server can't see: var(--x) used with no matching declaration anywhere in the same indexed root, and CSS selectors (#id/.class) with no HTML/JS reference in that root.
| Name | Required | Description | Default |
|---|---|---|---|
| file_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose one genuinely non-obvious trait — that CSS/HTML results include index-derived warnings the single-file language server cannot see — but says nothing about read-only nature, latency/freshness, whether the file must be open, or the shape of results.
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 paragraphs, front-loaded with the core purpose, and the second paragraph is dense with information that is not available anywhere else in the definition. No filler sentences.
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, low-complexity query tool this is nearly sufficient, and the tricky CSS/HTML case is covered. Since no output schema exists, the description could have said more about the returned diagnostics, and the absence of annotations leaves the read-only/safety profile unstated.
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% for the single required parameter, so the description has to compensate. 'For a single file' usefully implies file_path takes one path (no globs or multi-file input), but path format (absolute vs relative vs URI) is left unstated.
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 resource ('Get the relevant language server's diagnostics (errors/warnings)') plus an explicit scope ('for a single file'), which is enough to separate it from the workspace-level sibling without opening either schema. The CSS/HTML addendum further pins down what 'diagnostics' means for those file types.
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 'single file' scoping implies the contrast with the `workspace` sibling, and the CSS/HTML clause frames when the extra index-derived warnings appear, but usage is only implied. There is no explicit statement of when to prefer this over `workspace`, nor any exclusion or precondition (e.g., file must be open/indexed).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
hoverB
Get type/documentation info for the symbol at a position.
line and column are 1-indexed. column is a UTF-16 character offset on the line (not a visual/display column): a leading tab counts as one character.
| Name | Required | Description | Default |
|---|---|---|---|
| line | Yes | ||
| column | Yes | ||
| file_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses coordinate behavior (1-indexed lines, UTF-16 offsets on columns, tab handling), which is real behavioral context rather than restated name. However, it says nothing about what is returned when no symbol exists, whether results are plain text or markdown, or any auth/latency characteristics.
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 sentences with zero filler, and the core purpose is front-loaded ahead of the coordinate caveats. Every clause, including the tab note, earns its place by preventing an off-by-one or encoding error.
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 three-parameter read tool with no output schema and no annotations, the description should do more: it never describes the shape of the returned hover content (type signature vs. docstring vs. both) or `file_path` semantics. The coordinate explanation is a genuine strength, but the picture is only minimum-viable.
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, and it does explain the two tricky parameters (`line`, `column`) with indexing and encoding rules. It says nothing about `file_path`, leaving open whether it is absolute or relative, and nothing about valid ranges.
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 gives a specific verb and resource: "Get type/documentation info for the symbol at a position." This clearly separates it from a location-returning sibling like `definition`, but it never names or contrasts with the closest siblings (`symbol_info`, `definition`), so an agent must infer the boundary itself.
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?
There is no explicit when-to-use or when-not-to-use guidance, and no alternative is named despite a crowded sibling set (`definition`, `symbol_info`, `references`, `implementations`). Usage is only implied by the tool name and the phrase "at a position."
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
implementationsA
Who implements or extends this? Example: implementations(name="Shape").
For an interface or class, lists the classes that implement or extend it (transitively); for an interface or abstract method (Shape.area), lists the methods that implement it. Backed by the language server's textDocument/implementation, so it follows the type checker, not naming. name resolves like symbol_info (pass file_path to disambiguate); query is accepted as an alias. JS/TS only.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| query | No | ||
| file_path | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden and does well: it discloses the underlying mechanism (LSP textDocument/implementation), that results are transitive, that it follows type-checker semantics, and that it is JS/TS only. It does not mention result limits or truncation, but the operational profile is otherwise clear.
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?
Front-loads the purpose as a question, then an example, then the precise semantics. Slightly redundant (the question and the following sentence cover similar ground) but every sentence carries information.
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?
No output schema or annotations exist, yet the description conveys what the return contains (implementing/extending classes or methods), the language restriction, and the resolution behavior for arguments. Adequate for an agent to call it correctly, with only minor gaps around result limits.
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 0%, so the description must compensate, and it does: `name` resolves like symbol_info, `file_path` disambiguates, and `query` is an accepted alias. All three parameters are given meaning beyond the bare schema, though it never states which is required.
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 precise verb+resource: lists classes that implement/extend an interface or class, or methods implementing an abstract method, and gives a concrete invocation example. It is clearly distinguishable from siblings like references, callers, and definition.
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?
Explains the context in which it applies (interfaces, classes, abstract methods) and notes it follows the type checker rather than naming, which implicitly separates it from text-search siblings. It stops short of explicitly naming when to prefer references/callers instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
outlineA
What's in this file? Example: outline(file_path="src/app.ts").
Indented outline (functions, classes, interfaces, with :start-end line spans) of a JS/TS file in source order, so you can navigate without reading it in full. Locals, callbacks and object-literal keys inside functions and variables are left out; pass detailed=true to include them. Follow up with hover/definition/references at a listed line, or symbol_info by name.
| Name | Required | Description | Default |
|---|---|---|---|
| detailed | No | ||
| file_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses the scope (JS/TS files only), ordering (source order), and exactly what is excluded (locals, callbacks, object-literal keys) unless detailed=true. It does not mention error handling for non-JS/TS or missing files, and read-only status is only implied.
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?
Front-loads purpose with a question, then the definition, exclusions, flag, and follow-up path, in that order. The inline example earns its place by showing exact call syntax; phrasing is dense but not padded.
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?
No output schema exists, so the description accurately describes the return shape (indented outline with :start-end spans) and the effect of detailed on that output. Combined with explicit follow-up tools, an agent has everything needed to call it and use the result.
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% for 2 params, so the description must compensate. It explains detailed=true and its concrete effect, and the inline example demonstrates file_path usage; file_path's own semantics (path to the file to outline) are conveyed only implicitly.
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?
Names a specific verb+resource: an indented outline (functions, classes, interfaces with line spans) of a JS/TS file. It distinguishes itself from siblings like symbol_info and search_symbol by describing a whole-file structural view rather than a named-symbol lookup.
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?
Gives clear context for use ('so you can navigate without reading it in full') and routes to follow-ups (hover/definition/references at a listed line, or symbol_info by name). It does not state an explicit when-not-to-use case, but the alternative-tool routing is concrete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
referencesB
Find all usages of the symbol at a position across the workspace.
line and column are 1-indexed. column is a UTF-16 character offset on the line (not a visual/display column): a leading tab counts as one character. On a --custom-property/#id/.class token in a .css/.html file (or a name inside an HTML id="..."/class="..." value), answers from the cross-file index (see css_var/selector) instead of the single-file language server, limited to the file's own root (each WEBNAV_MCP_ROOTS root is separate) unless it has no hits there.
| Name | Required | Description | Default |
|---|---|---|---|
| line | Yes | ||
| column | Yes | ||
| file_path | Yes | ||
| include_declaration | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It adds genuine behavioral detail: the cross-file index path for CSS custom-properties/id/class tokens and the per-root scoping limit with a same-root fallback. But it omits general behavioral facts such as read-only nature, whether declarations are included by default, or result/ordering behavior, so it is only partially complete.
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 core action is front-loaded in the first sentence, and the dense second paragraph is devoted to non-obvious positional and routing details rather than filler. It is somewhat information-packed but each clause earns its place.
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 position-based query tool with no annotations and no output schema, the description covers the risky part (coordinate semantics and special-case routing) but leaves the include_declaration flag unexplained even though it directly affects the result set. Adequate but with a clear visible gap.
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 0%, so the description must compensate. It does this well for line/column (1-indexed, UTF-16 offset, tab counts as one character), which is high-value semantics absent from the schema. However include_declaration and file_path receive no explanation, leaving two of four parameters undocumented.
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 concrete verb+resource+scope: "Find all usages of the symbol at a position across the workspace." An agent can distinguish this from definition or hover. It does not, however, contrast itself against close siblings like callers or implementations, which also report usage-like relationships.
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 implies usage (find usages when you have a position) but never states explicit when-to-use/when-not versus callers, implementations, or definition. It does give one routing rule — CSS/HTML tokens resolve via the cross-file index rather than the single-file language server — but general selection guidance is absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_symbolA
Search JS/TS files for a symbol by name (function, class, const, etc.).
JS/TS-only: the HTML/CSS language servers don't implement useful workspace-wide symbol search (webnav does not reimplement it). Prefer symbol_info for a one-call summary. Returned positions point at the identifier name and use the same character-offset column convention as the other tools. Results include a SymbolKind label and are capped. name is accepted as an alias for query. Narrow broad queries with kind (SymbolKind labels, comma-separated: class, function,method, interface, ...) and path (workspace-relative prefix such as src/, or a glob such as src/**/*.ts). Production code ranks before tests. Loose fuzzy hits whose names don't contain the query are summarised as a count when real matches exist; pass fuzzy=true to list them too.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | ||
| name | No | ||
| path | No | ||
| fuzzy | No | ||
| query | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose non-obvious traits: results are capped, production code ranks before tests, fuzzy non-containing hits are collapsed to a count unless `fuzzy=true`, and positions use the shared character-offset column convention. It stops short of stating the cap size or the read-only/safety profile, so it is strong but not exhaustive.
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?
Dense but front-loaded: purpose and language scope come first, then alternatives, then parameter behavior. Every sentence carries information, though the middle is packed with several distinct concerns in a row.
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 5 undocumented parameters, no annotations, and no output schema, the description supplies enough for correct invocation and even describes the return shape (identifier positions, SymbolKind label, caps). The absence of an explicit cap value or safety statement is the only real gap.
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, and it largely does: `name` is documented as an alias for `query`, `kind` takes comma-separated SymbolKind labels with examples, `path` accepts a workspace-relative prefix or glob, and `fuzzy` controls listing of loose hits. Only the exact cap/semantics of an unbounded `query` remain unspecified.
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 resource ('Search JS/TS files for a symbol by name') and enumerates the symbol kinds it matches. It clearly delimits itself from the sibling symbol_info, which an agent would otherwise confuse with this search 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?
Explicitly says 'Prefer `symbol_info` for a one-call summary', declares the JS/TS-only restriction and why (HTML/CSS language servers lack workspace-wide search), and tells the agent how to narrow queries with `kind` and `path`. When-to-use, when-not-to-use, and the alternative are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
selectorA
Who uses this #id or .class? Example: selector(name=".card-title").
Looks up the selector across the whole workspace.
Cross-references CSS rule definitions, HTML id=/class= attributes, and JS usages (getElementById, classList.add/remove/toggle/contains, querySelector/querySelectorAll, className assignment, and any JS string literal exactly equal to the bare name, e.g. an id passed to a project's own helper like onClick("btn-save", …), labeled "string literal"). Hits in generated output (WEBNAV_MCP_EXCLUDE) are labeled [generated]; edit their source instead. This is something the single-file CSS/HTML language servers can't do. name must include the leading # or .. Grouped by file with line numbers, separately per configured root (see WEBNAV_MCP_ROOTS). A JS hit built from string concatenation (e.g. getElementById("view-" + x)) is reported against only its static prefix and labeled "dynamic partial match"; a query whose name starts with such a prefix (e.g. #view-components against a stored #view-) also surfaces that hit, labeled "dynamic partial match via ''", instead of being silently dropped or guessed. query is accepted as an alias for name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| query | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden and does so well: it enumerates exactly what is scanned, how special cases are labeled ('[generated]', 'string literal', 'dynamic partial match'), and how env vars (WEBNAV_MCP_EXCLUDE, WEBNAV_MCP_ROOTS) affect coverage. It never explicitly states the operation is read-only or describes result ordering beyond 'grouped by file', leaving a small gap for a no-annotation 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?
Front-loaded with the one-line answer and example before the detail, and every sentence is information-dense rather than filler. The two trailing sentences on dynamic partial matching are heavy relative to their importance, but they describe genuine edge-case behavior an agent would otherwise misread.
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 tool with no annotations and no output schema, the description is nearly self-sufficient: it explains what is searched, how hits are labeled, and how they are grouped. The one thing left open is the concrete response shape (field names/structure of the returned hits), which it only describes prose-wise.
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 0%, so the description must compensate, and it does: it mandates the leading '#' or '.', gives a worked example, and explains that 'query' is an alias for 'name'. It does not clarify that one of the two must actually be supplied (required count is 0), so the requiredness question remains ambiguous.
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 opening sentence states a specific verb and resource ('Who uses this #id or .class?') and immediately clarifies scope by listing what it cross-references (CSS rules, HTML id/class attrs, JS usages). It also explicitly carves itself out from the sibling single-file CSS/HTML language servers, so an agent can tell it apart without opening a schema.
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 clear context: workspace-wide lookup that the single-file CSS/HTML language servers cannot perform, which implies when to reach for it. However, it never names its actual siblings (references, css_var, search_symbol) or states an explicit when-not condition, so the guidance stops short of full routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
symbol_infoA
What is X and where is it used? Example: symbol_info(name="renderSidebar").
One-call summary for a JS/TS name: header, hover text, definition, and references grouped by file, the usual first lookup instead of chaining search_symbol → hover → definition → references by hand. Pass file_path to disambiguate; query is accepted as an alias for name. For CSS/HTML cross-file lookups use css_var / selector instead.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| query | No | ||
| file_path | No | ||
| include_references | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the composite nature of the call (it fuses hover, definition, and references into one response and groups references by file), which is genuinely useful behavioral context. It stops short of saying whether the lookup is strictly read-only, how ambiguity or zero-match cases are handled, or whether results are truncated.
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?
Three sentences, front-loaded with the core purpose and a concrete call example before the routing advice. The "What is X and where is it used?" framing and the example are mildly redundant with the following sentence, but nothing is wasted overall.
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 appropriately enumerates the return contents (header, hover, definition, references grouped by file), and it covers the sibling routing an agent needs. It is only slightly thin on ambiguity behavior and the undocumented include_references flag.
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 four bare parameters. It explains that query is an alias for name and that file_path disambiguates a match, but it never mentions include_references (or its default true) or the expected string form of name beyond the example, so half the parameters remain undocumented.
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 gives a specific verb-and-resource framing ("One-call summary for a JS/TS name") and enumerates exactly what is returned: header, hover text, definition, and references grouped by file. It explicitly contrasts itself with the sibling chain search_symbol → hover → definition → references and with css_var/selector, so an agent can place it without opening any schema.
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 states when to use it ("the usual first lookup") and what it replaces, and gives explicit when-not guidance by routing CSS/HTML cross-file lookups to css_var / selector. It also names the disambiguation condition for file_path, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
workspaceA
Which directory is webnav navigating, and why? Use when results look like they come from the wrong checkout/worktree.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose the conceptual output (which directory, plus a reason), which is useful, but says nothing about safety, determinism, or whether it inspects git worktrees versus plain directories. Zero-parameter and clearly read-only by nature, yet that is inferred rather than stated.
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 with no filler, and the 'which directory' framing is front-loaded ahead of the usage trigger. The rhetorical-question style is slightly indirect for a tool definition, which keeps it from a 5.
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 zero-param read tool with no output schema, the description should clarify the shape of the answer. It gestures at 'which directory ... and why' but never specifies what 'why' means (git worktree, symlink resolution, config), leaving the agent to discover the return semantics by calling it.
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?
The tool takes zero parameters and schema description coverage is reported at 100%, so there is nothing for the description to compensate for. Baseline 4 applies for a parameterless tool.
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 gets at the resource (the directory webnav is operating in) and hints at an explanatory payload ('and why'), but it is phrased as a rhetorical question rather than a statement of a verb+resource. The noun-only name 'workspace' does not disambiguate against code-navigation siblings like outline or diagnostics. An agent can infer it reports the active workspace root, but only with effort.
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 concrete trigger: 'Use when results look like they come from the wrong checkout/worktree.' That is a clear when-to-use condition tied to a real failure mode of the sibling navigation tools. It names no alternative (e.g., diagnostics) and gives no when-not-to-use, so it falls short of a 5.
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.
12 tool updates
v0.1.1- First observed
callers - First observed
css_var - First observed
definition - First observed
diagnostics - First observed
hover - First observed
implementations - First observed
outline - First observed
references - First observed
search_symbol - First observed
selector - First observed
symbol_info - First observed
workspace
TDQS
Scored across 12 tools
Most tools map to distinct navigation operations, and descriptions explicitly delineate boundaries (e.g. callers is 'narrower than references', symbol_info is a one-call bundle). The main risk is overlap between symbol_info and the chained search_symbol/hover/definition/references set, plus references vs callers vs implementations, but the descriptions steer selection clearly.
Names are uniformly lowercase, mostly bare LSP-style nouns (hover, definition, references, diagnostics, outline) with a few snake_case compound names (search_symbol, symbol_info, css_var). The style is predictable and readable despite not being a strict single verb_noun pattern.
Twelve tools is well within the ideal 3-15 range and each tool earns its place (a distinct LSP capability or a deliberate cross-file index feature). No obvious redundancy or padding.
Covers the core navigation lifecycle: diagnostics, hover, definition, references, outline, symbol search, callers, implementations, plus CSS custom-property and selector cross-referencing. Missing rename/refactor, code actions, and workspace symbol search for non-JS/TS languages (a limitation the descriptions acknowledge), which are minor workaroundable gaps.
Maintenance
Related MCP Connectors
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Codebase intelligence for AI agents — dead code, blast radius, ownership.
Code intelligence platform for AI agents. 20 tools for architecture, security & impact analysis.
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes type-aware code navigation and fast file search to AI agents via language servers, enabling definitions, references, symbols, and file lookup without reading entire codebases.1,908 npmMIT
- AlicenseAqualityDmaintenanceEnables AI coding agents to interact with TypeScript projects through compiler-level code intelligence, providing tools for navigation, type information, diagnostics, refactoring, and semantic search.29332 npm4Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables LLM agents to efficiently understand and navigate a codebase by providing semantic search over symbols and a reference graph, replacing expensive grep/glob calls with structured tools like definition lookup, caller/callee queries, and change-impact analysis.3MIT
- FlicenseNot gradedqualityAmaintenanceProvides efficient code navigation and graph-based analysis for AI agents, enabling symbol resolution, callers, implementations, and type schemas with minimal token usage.-