sens

sens

Provides MCP tools for Claude Code to query a project's codebase via a compact index, reducing token usage and context bloat by enabling symbol lookup, usage tracking, and dead-code detection.

Category
Visit Server

README

<p align="center"> <img src="docs/banner.svg" alt="Sens — a project index for Claude Code" width="860"> </p>

<p align="center"> <a href="https://www.npmjs.com/package/sens-mcp"><img alt="npm version" src="https://img.shields.io/npm/v/sens-mcp?style=flat-square&color=cb3837&logo=npm"></a> <a href="#license"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-1a7f47?style=flat-square"></a> <img alt="Built for Claude Code" src="https://img.shields.io/badge/built_for-Claude_Code-4f7cff?style=flat-square"> <img alt="MCP server" src="https://img.shields.io/badge/MCP-server-7a5cff?style=flat-square"> <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white"> <img alt="Status" src="https://img.shields.io/badge/status-early_development-e0a33d?style=flat-square"> </p>

<p align="center"> <b>Let the model <i>query</i> your codebase instead of reading it all.</b><br> Fewer tokens, cleaner context, and a heads-up when code already exists or is dead. </p>


Why Sens?

If you use Claude Code on a subscription, your pain isn't a per-token bill — it's the usage limit and the context window filling up. Every time the agent opens 20 files just to orient itself, it burns your quota and bloats the context (which then compacts and quietly loses memory).

Sens keeps a compact index of your project and serves it to Claude over MCP, so the model asks focused questions instead of reading everything:

"where is login?" · "who uses it?" · "does something like this already exist?" · "what's dead code here?"

One engine, two payoffs:

  • 🪙 Fewer tokens / cleaner context → your subscription lasts longer and long sessions stay sharp.
  • 🧹 Cleaner code → reuse what already exists instead of duplicating, and surface dead code.

[!NOTE] Sens is not a "write-less" rules engine (that's what ponytail does well). Sens is the missing piece underneath: the project knowledge that makes "reuse what exists" actually work. They're complementary.

Contents

Quick start

Add Sens as an MCP server. In your project's .mcp.json (or Claude Code's MCP config):

{
  "mcpServers": {
    "sens": {
      "command": "npx",
      "args": ["-y", "sens-mcp", "mcp"]
    }
  }
}

Or register it once for every project:

claude mcp add sens -s user -- npx -y sens-mcp mcp

That's it. Claude Code launches Sens on demand — no per-project install, no manual server to run. Then just ask Claude naturally: "use sens to map this project", "any dead code? check with sens".

What Claude gets (MCP tools)

Tool What it does Replaces
project_map A one-screen map of the repo with each file's exports Reading many files to orient
find_symbol Where a symbol is defined (file:line + signature) grep
who_uses Every place a symbol is used grep + reads
file_outline A file's signatures, without its bodies Reading the whole file
already_exists Whether something matching keywords already exists Duplicating by accident
dead_code Unused symbols / exports (candidates) —
file_dependencies What a file imports and what imports it (import graph) Grepping for imports across the project

Working rules

Sens's MCP server also hands Claude a short set of working rules it follows when writing or changing code — reuse what exists instead of duplicating, keep code minimal but maintainable, and leave nothing orphaned — each tied to the tool that lets it verify the rule (already_exists/find_symbol before writing, dead_code before finishing, who_uses before a rename). They load automatically over MCP; run sens rules to read them, or sens rules --write to drop a SENS_RULES.md you can reference from your CLAUDE.md / AGENTS.md.

Slash commands

Sens also registers prompts, so it shows up in Claude Code's / menu:

Command Does
/sens map Compact project map
/sens dead-code List dead-code candidates
/sens find <name> Locate a symbol
/sens exists <keywords> Check for existing code before writing
/sens rules Load the working rules and follow them
/sens dashboard Open the web dashboard (graph)

CLI

You can also drive Sens yourself:

npx sens-mcp index          # build/update the index (cached by file mtime)
npx sens-mcp map [subdir]   # compact project map
npx sens-mcp find <name>    # where a symbol is defined
npx sens-mcp who <name>     # where a symbol is used
npx sens-mcp outline <file> # a file's signatures, no bodies
npx sens-mcp exists <kw...> # does something like this already exist?
npx sens-mcp dead-code      # unused symbols (candidates)
npx sens-mcp deps <file>    # what a file imports and what imports it
npx sens-mcp report         # self-contained HTML report → .sens/report.html
npx sens-mcp dashboard      # interactive web dashboard
npx sens-mcp rules          # print the coding rules (--write to save SENS_RULES.md)
npx sens-mcp usage          # which Sens tools the model has actually called

Installed globally (npm i -g sens-mcp) the command is just sens <command>.

Dashboard

sens dashboard starts a local web UI (default http://localhost:4319):

  • an interactive graph of your project — files as nodes, imports as edges (drag, click a node to see its symbols);
  • live stats and a clickable dead-code list;
  • a symbol search;
  • a one-click Connect to Claude Code (writes .mcp.json) and a Rebuild index button.
npx sens-mcp dashboard --root . --port 4319   # --no-open to skip opening the browser

<p align="center"><i>Nodes are files; blue = has exports, gray = internal, red = has dead code.</i></p>

Does it actually help?

A reproducible benchmark suite (bench/run.ts) measures this on Sens's own repo and fixtures — run it yourself with npm run bench. No estimates, no anecdotes: every number below comes straight from that script.

Metric Result How it's measured
Size to orient in a project ~97% fewer characters project_map output vs. concatenating every file in src/
Re-index when nothing changed ~100\u2013125\u00d7 faster (varies by run/hardware) median cold build (force: true) vs. median cached read, 5 runs each
Duplication caught before writing already_exists("subtract two numbers") surfaces the existing subtract
Dead code false positives 0 out of 8 labeled symbols against fixtures with known used / dead / object-shorthand-referenced symbols

Re-run npm run bench on your own machine or project to reproduce (or challenge) these numbers. Re-index speed varies with CPU and disk, so treat it as a range, not a fixed multiplier.

How it works

Pluggable per-language parsers behind one language-agnostic index. Sens walks your source (respecting .gitignore), extracts top-level symbols with compact signatures, resolves references, and caches the result in .sens/index.json — only rebuilt when file mtimes change; a schema version invalidates stale caches across upgrades.

Languages:

  • JavaScript / TypeScript (.ts .tsx .js .jsx .mts .cts) via ts-morph — cross-file references are resolved semantically (it follows your imports).
  • Python, Go, Rust, Java, C#, C, C++, PHP, Ruby, Kotlin via tree-sitter — functions, classes/structs, methods, constants, and an import graph per file.

Everything lands in one language-agnostic index, so a mixed repo (e.g. a TS frontend + a Python or Go backend) is indexed as a single project. For the tree-sitter languages, cross-file references are resolved by name — the best a syntax-only parser can do without whole-program type inference — so who_uses / dead-code are slightly more approximate than for JS/TS: they over-count rather than miss, which keeps dead-code candidates conservative. Adding a language is a small self-contained parser (src/indexer/languages/); more are on the roadmap.

Configuration

Optional sens.config.json at your project root:

{
  "ignore": ["**/generated/**"],
  "entryPoints": ["src/public-api.ts"]
}
  • ignore — extra globs to skip (on top of .gitignore, node_modules, dist).
  • entryPoints — files whose exports are your public API, so they're never flagged as dead. **/index.* files are treated as entry points by default.

Dead code — read this

Dead-code results are candidates, not certainties. Sens can't see:

  • dynamic usage (string-based access, reflection);
  • framework "magic" (e.g. Vue/Nuxt auto-imported components — SFC support is on the roadmap);
  • a public API meant for external consumers (use entryPoints).

Test files count as usage sources but are never themselves reported as dead. Verify before deleting.

Roadmap

  • [ ] Enforcement hook (warn/block when an edit introduces dead code or a duplicate)
  • [ ] Semantic already_exists (embeddings) + near-duplicate detection
  • [ ] More languages via tree-sitter; Vue/Svelte SFCs
  • [ ] Dashboard: symbol-level graph, live file watching
  • [x] A reproducible benchmark suite (npm run bench)

Contributing

Issues and PRs welcome. To develop locally:

npm install
npm run build      # bundle to dist/
npm test           # vitest
npm run typecheck

npm link makes sens a global command pointing at your local build.

License

MIT — do what you want, just keep the copyright notice. See the note below on why.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured