webnav-mcp
Navigates CSS stylesheets through the CSS language server, offering hover, go-to-definition, references and diagnostics for .css files, plus a cross-file index that tracks where CSS custom properties (--name) and #id/.class selectors are defined and used across CSS, HTML and JS.
Routes JS/TS files (.js/.mjs/.cjs/.jsx/.ts/.mts/.cts/.tsx) to TypeScript 7's native language server (tsc --lsp --stdio) to provide hover, definition, references, diagnostics, workspace symbol search, symbol info and file outlines for the navigated project.
webnav-mcp
⚠️ Deprecated — do not use this package. Use
webnav-ts-mcpfrom the npm registry instead (claude mcp add webnav -- npx webnav-ts-mcp). It is a TypeScript port with the same tools and environment variables, needs only Node.js (no Python oruv), and is the only version that will receive updates.
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. It's the front-end counterpart to
codenav-mcp.
Quick start
You need uv (or pipx) and Node.js ≥ 18:
uvx webnav-mcpRegister it with your MCP host. For Claude Code, from the project root:
claude mcp add webnav -- uvx webnav-mcpOr add it to a project .mcp.json (Claude Code) or .cursor/mcp.json (Cursor):
{
"mcpServers": {
"webnav": {
"command": "uvx",
"args": ["webnav-mcp"]
}
}
}In Cursor, also set "env": {"WEBNAV_MCP_WORKSPACE": "${workspaceFolder}"},
because Cursor may start MCP servers with your home directory as the working
directory.
Related MCP server: ts-language-mcp
Language servers
Requests are routed to three Node language servers by file extension:
Extension | Backend |
| TypeScript 7 native LSP: |
|
|
|
|
Resolution order for tsc / HTML / CSS binaries: navigated project's
node_modules/.bin/ → webnav's own package-local install (see Development) →
PATH → npx --yes (JS/TS: npx -p typescript@7 tsc --lsp --stdio). webnav
does not use typescript-language-server — TypeScript 7 no longer ships
classic tsserver.js.
To skip downloads, install in the project (or under this package for standalone):
npm install --save-dev typescript@^7 vscode-langservers-extractedTools
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 left out unless |
| 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 (a Python scanner, not the language servers):
Tool | Answers |
| Where is |
| Where is |
search_symbol, symbol_info and outline 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. A missing parameter gets a short hint back instead of a validation
error.
Positions are 1-indexed. column is a UTF-16 character offset (a leading
tab counts as one character).
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). These aren't opened, are hidden from |
| nothing | Comma-separated workspace-relative stylesheets (files or directories) that are a public API, e.g. a design-token file consumed by other projects. |
Requirements
Python ≥ 3.11
Node.js ≥ 18 (for TypeScript 7's
tscshim and the HTML/CSS servers)Installed automatically:
mcp,mcp-nav-shared
Related
Design notes (index heuristics, dynamic selectors, positioning): docs/agent-tooling.md.
Development
Source: github.com/illescasDaniel/webnav-mcp. From a
checkout: uv sync --group dev, then npm ci in this directory (owns
typescript@^7 + vscode-langservers-extracted for standalone launch), then
uv run webnav-mcp.
License
MIT. See LICENSE.
Available Tools
10 toolscss_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 (seeWEBNAV_MCP_ROOTS; a single unnamed root by default), since each may define its own values.queryis accepted as an alias forname.
Inputs: name, query. Returns: result
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.
Inputs: line (required), column (required), file_path (required). Returns: result
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, custom properties declared
but never used, and CSS selectors (#id/.class) with no HTML/JS
reference in that root (files under WEBNAV_MCP_PUBLIC are exempt from
the last two).
Inputs: file_path (required). Returns: result
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.
Inputs: line (required), column (required), file_path (required). Returns: result
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.
Inputs: file_path (required), detailed. Returns: result
referencesA
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.
Inputs: line (required), column (required), file_path (required), include_declaration. Returns: result
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.
Inputs: kind, name, path, fuzzy, +1 more. Returns: result
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.
Inputs: name, query. Returns: result
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.
Inputs: name, query, file_path, include_references. Returns: result
workspaceA
Which directory is webnav navigating, and why? Use when results look like they come from the wrong checkout/worktree.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 10 tools
Most tools have clearly distinct purposes: hover/definition/references are standard position-based LSP queries, css_var and selector target distinct cross-file resource types, and workspace is a unique diagnostic. The only real overlap is search_symbol vs symbol_info (both accept a name), but the descriptions explicitly frame symbol_info as the one-call summary wrapper, which should steer selection correctly.
All names are lowercase and use snake_case for multi-word names (search_symbol, symbol_info, css_var), with single-word names for the rest, so there is no case or delimiter mixing. However, there is no unifying verb_noun pattern—several tools are bare nouns (hover, definition, references, diagnostics, outline)—so it is consistent in style but not in grammatical shape.
Ten tools is a well-scoped set for a code-navigation server: four core LSP-style primitives, three navigation helpers (outline, search_symbol, symbol_info), two cross-file CSS/HTML index lookups, and one workspace diagnostic. Each tool maps to a distinct workflow and none feel padded.
The surface covers navigation (definition, references, hover, outline, symbol search), diagnostics, and cross-file CSS/HTML lookups well, with clear coverage of the stated JS/TS/CSS/HTML domain. Minor gaps remain—no rename, call hierarchy, implementation lookup, or general textual/file search—but these are outside the apparent navigation-focused scope and agents can work around them.
Maintenance
Related MCP Connectors
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Coding agents in multi-service codebases routinely rebuild existing helpers, trust stale type definitions, and modify API contracts without knowing who consumes them. Carrick solves this by indexing your entire TypeScript ecosystem across service and repository boundaries. By integrating deeply with the TypeScript compiler, Carrick traces every route, type, and cross-service call while recording function behaviour so agents search by intent rather than name. Delivered via MCP for AI agents and LSP for IDEs, Carrick ensures models see existing endpoints and utilities before generating new code. The scanner is source-available and runs from your CLI or CI pipeline.
Give your AI agent a persistent map of your project's structure, dependencies, and bugs.
Codebase intelligence for AI agents — dead code, blast radius, ownership.
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,620 npmMIT
- AlicenseAqualityBmaintenanceEnables AI coding agents to interact with TypeScript projects through compiler-level code intelligence, providing tools for navigation, type information, diagnostics, refactoring, and semantic search.29179 npm4Apache 2.0
- AlicenseAqualityBmaintenanceEnables AI agents to navigate JS/TS, HTML, and CSS code — symbol info, outlines, callers, implementations, definitions, references, hover, and diagnostics — through bundled Node language servers. It also builds a cross-file index answering where CSS custom properties and #id/.class selectors are defined and used across stylesheets, markup, and scripts.1214 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to navigate and refactor a codebase through an AST index, offering project overviews, symbol and usage search, module dependency exploration, and LSP-backed operations such as rename, go-to-definition, diagnostics, and extract-method. Supports TypeScript/JavaScript and C# with automatic reindexing and watch mode.MIT