Skip to main content
Glama

webnav-mcp

⚠️ Deprecated — do not use this package. Use webnav-ts-mcp from 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 or uv), 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-mcp

Register it with your MCP host. For Claude Code, from the project root:

claude mcp add webnav -- uvx webnav-mcp

Or 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

.js / .mjs / .cjs / .jsx / .ts / .mts / .cts / .tsx

TypeScript 7 native LSP: tsc --lsp --stdio (JS via allowJs / jsconfig.json)

.html

vscode-html-language-server

.css

vscode-css-language-server

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-extracted

Tools

For JS/TS, start with the name-based tools:

Tool

Answers

symbol_info

What is this? Header, hover, definition and references in one call

outline

What's in this file? (source order; locals left out unless detailed=true)

search_symbol

JS/TS workspace symbol search (ranked, capped; optional kind= / path= filters; fuzzy-only hits summarised unless fuzzy=true)

workspace

Which directory is being navigated, and why

Then use the position tools once you have a path:line:col:

Tool

Answers

hover

Type and docs at a position

definition

Go to definition (CSS/HTML tokens answer from the index below)

references

All usages (CSS/HTML tokens answer from the index below)

diagnostics

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

css_var

Where is --name defined and used?

selector

Where is #id or .class defined and used (CSS, HTML, JS)?

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

WEBNAV_MCP_WORKSPACE

unset: follows the client's MCP roots when they name a worktree of the same git repository, else CLAUDE_PROJECT_DIR, else the working directory

Pins the project root (never overridden). See the workspace tool

WEBNAV_MCP_ROOTS

the whole workspace as one root, labelled web

Comma-separated label=relative/path pairs to index separately, e.g. app=src,prototypes=design when two trees define their own values

WEBNAV_MCP_EXCLUDE

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 search_symbol, and are rejected by the position tools. The CSS/selector index still reads them

WEBNAV_MCP_PUBLIC

nothing

Comma-separated workspace-relative stylesheets (files or directories) that are a public API, e.g. a design-token file consumed by other projects. diagnostics stops reporting their custom properties as "declared but never used" and their selectors as "never referenced"; undefined var() usages are still reported

Requirements

  • Python ≥ 3.11

  • Node.js ≥ 18 (for TypeScript 7's tsc shim and the HTML/CSS servers)

  • Installed automatically: mcp, mcp-nav-shared

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 tools
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.

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

    A3.9/5.0

    Scored across 10 tools

    Disambiguation4/5

    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.

    Naming Consistency4/5

    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.

    Tool Count5/5

    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.

    Completeness4/5

    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

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Exposes 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 npm
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables AI coding agents to interact with TypeScript projects through compiler-level code intelligence, providing tools for navigation, type information, diagnostics, refactoring, and semantic search.
      29
      179 npm
      4
      Apache 2.0
    • A
      license
      A
      quality
      B
      maintenance
      Enables 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.
      12
      14 npm
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables 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