codebase-lens
Provides deep analysis of Next.js projects, including route trees with layouts and error boundaries, client/server bundle boundaries, route handler authentication coverage, unused exports, middleware behavior, data fetching configuration, and security audits of next.config and env files.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@codebase-lensWhich API route handlers don't check auth?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
nextjs-lens
An MCP server that gives Claude Code (or any MCP client) deep insight into Next.js projects.
Claude can read a page.tsx file on its own. What it can't easily do is hold the whole app in its head: which layout wraps which page, where 'use client' pulls a subtree into the browser bundle, which route handlers skip auth, or which exports nothing imports. nextjs-lens parses your project with the TypeScript compiler API and answers those questions directly.
Why
We tested the same security audit question on a 90-file Next.js app across different models and configurations:
Config | Correct findings | Hallucinations | Cost |
Haiku alone | ~5 of 27 | 7 false positives | $0.19 |
Haiku + nextjs-lens | ~23 of 27 | 0 | $0.10 |
Opus alone | ~20 of 27 | 2 false positives | $0.47 |
Opus + nextjs-lens | ~24 of 27 | 0 | $0.65 |
Haiku with nextjs-lens outperformed Opus without it — at one-fifth the cost, in a quarter of the time, with zero hallucinations. Without tools, Haiku invented security issues that don't exist (fake CSRF problems, nonexistent password handling). With tools, it reported only what the code actually shows.
Related MCP server: vibealive MCP Server
How it works
Your Next.js project
↓ PROJECT_PATH
nextjs-lens (MCP server over stdio)
├── Next.js tools (AST-based; PROJECT_PATH must be a Next.js app or a monorepo containing one)
├── Generic scanners (files, search, imports, styles)
└── Knowledge resources (official docs + community gotchas)Quick Start
1. Add to your project
Requires Node.js 20.11 or later. Create .mcp.json in your project root:
{
"mcpServers": {
"nextjs-lens": {
"command": "npx",
"args": ["-y", "nextjs-lens"],
"env": {
"PROJECT_PATH": "/absolute/path/to/your/project"
}
}
}
}To run from source instead (for development, or to refresh the bundled Next.js docs):
git clone https://github.com/shanewin/nextjs-lens.git
cd nextjs-lens
npm install
npm run fetch-docs # pull the latest Next.js docs (optional)
npm run buildThen use "command": "node" and "args": ["/absolute/path/to/nextjs-lens/dist/server.js"] in .mcp.json.
In a monorepo, point PROJECT_PATH at the repo root: nextjs-lens analyzes the Next.js app with the most routes. To choose a different app, set "NEXTJS_LENS_APP": "apps/admin" (a path relative to PROJECT_PATH) in env. If no Next.js app is found, the server exits with an error explaining why.
To tune findings for your project (exempt public routes, raise severities, ignore legacy files), add a .nextjs-lens.json file.
This project was previously called codebase-lens. Existing .codebase-lens.json files and the CODEBASE_LENS_APP variable still work.
2. Use it
Open Claude Code in your project. The tools are available automatically. Try:
"Show me the route tree with which layouts and error boundaries apply to each page"
"Where does 'use client' pull server code into the client bundle?"
"Which API route handlers don't check auth?"
"Find exports nothing imports"
"Audit my next.config and middleware for security issues"
Tools Reference
Next.js (loaded when next.config.* exists or next is in package.json)
Every tool parses source with the TypeScript compiler API (ts.createSourceFile), not regex. That means it handles multi-line exports, export const GET = withAuth(...), export { handler as POST }, re-export barrels, and tsconfig path aliases.
Results are compact by default so they fit comfortably in Claude's context on large apps: counts, every finding, and one-line lists. Pass detail: "full" to any Next.js tool for complete per-item data (layout chains, file lists, auth evidence, fetch options).
Whole-app analysis
Tool | What it does |
| App Router segment tree with inheritance resolved: the layout chain, templates, and the loading / error / not-found boundary that actually applies to each page, plus merged route segment config. Flags page+route conflicts, error boundaries without |
| Walks the real import graph from every page and layout to find where |
| Per-method auth coverage for every route handler and Pages API route: auth calls, auth wrappers, credential header checks, shared-secret comparisons, and webhook signature checks. Follows auth helpers in the same file or imported from other modules, and handlers defined in other modules (re-exports, imported functions passed to wrappers). Handlers built with tRPC, GraphQL, or Auth.js are marked delegated rather than unprotected, and routes that are usually public by design (health checks, CSRF tokens, sign-in flows, OG images) are reported as info. Evaluates the middleware/proxy matcher against real routes to separate endpoints protected in the handler, protected only by middleware, and unprotected. |
| Dead exports and unimported files. Follows barrel re-exports and dynamic imports, and ignores the exports Next.js consumes by convention (default exports, |
Focused audits
Tool | What it does |
| Flat list of App Router + Pages Router routes with HTTP methods |
| Every server action (module-level and inline |
| Parsed matcher config, auth logic, and exactly which routes middleware/proxy runs on and which it skips. On Next.js 16, migration advice that accounts for the Edge runtime (proxy only runs on Node.js) |
| Per-route segment config, |
| Statically evaluates next.config (unwrapping plugin wrappers) and flags secrets in |
| Secret-looking |
Generic (always available)
Tool | What it does |
| List files matching extensions with sizes |
| Read any file (100KB limit) |
| Regex search across the codebase |
| Build a dependency graph from any file |
| Find hardcoded colors/spacing escaping the design system |
Project Rules
Add .nextjs-lens.json to PROJECT_PATH (or to the analyzed app's directory) to adapt findings to your project:
{
"authFunctions": ["makeSureLoggedIn", "requireOrgMember"],
"exempt": ["/api/public/*", "/api/search"],
"severity": {
"src/app/api/cron/*": "critical",
"src/app/api/billing/webhook": "critical"
},
"ignore": ["src/lib/legacy/*", "src/components/Unused.tsx"]
}Key | Effect |
| Drops findings whose file or route matches. A finding that lists many routes (such as "route handlers not matched by middleware") loses only the exempt routes. |
| Reports matching findings at |
| Removes matching files from |
| Names of your own auth check functions. |
Patterns match file paths (relative to the app directory) or URL routes:
src/app/api/cron/*or/api/public/*: everything under that prefix*matches within one path segment,**across segmentsA plain path matches itself and anything inside it, so
src/app/api/billing/webhookcovers itsroute.ts
Rules match a finding's file and route fields, never its message text. Results that rules changed include a rules_applied count. Problems in the file (invalid JSON, unknown keys, unsupported severities) are logged to stderr and shown in the lens://status resource.
Policy Checks
Write down which code may import what, and check it in CI. Add nextjs-lens.policy.json to the project root (or the app directory):
{
"version": 1,
"mode": "warn",
"rules": {
"client-bundle": [
{ "name": "database stays on the server", "module": ["@prisma/client", "@acme/db"], "message": "Load data in a server component and pass it down" },
{ "import": "src/server/**" }
],
"forbidden-imports": [
{ "module": "stripe", "allowedIn": ["src/server/billing/**"] },
{ "module": "next/router", "from": "src/app/**", "message": "Use next/navigation in the App Router" }
]
}
}npx nextjs-lens check /path/to/project # readable report
npx nextjs-lens check /path/to/project --json # machine-readable, includes exit_codeFrom a source checkout, npm run check -- /path/to/project does the same (add --silent before check when piping --json).
Rule | Checks |
| Nothing it names reaches the browser through any chain of imports from a |
| Only allowed files import something: importers matching |
Each rule entry needs a target, either module (package names) or import (file globs, matched after resolving path aliases). The other fields are optional:
modulenames match exactly;"pkg/*"matches the package's subpaths, so list both to cover either.exceptlists importer globs the rule never applies to, such as data-loading files next to UI code.severityiserror(default) orwarn, andmessageis shown with each violation.Files inside an
importglob may import each other.forbidden-importsonly:includeTypeOnlyalso checks type-only imports, andincludeTestsalso checks test, story, and mock files.
Globs are relative to the app directory and use the same patterns as project rules.
mode decides the exit code, and it can only be set in the policy file, so protect that file with CODEOWNERS:
Exit code | When |
0 | No error-severity violations outside the baseline, or |
1 |
|
2 | The check could not run: no policy file, an invalid policy or baseline (every problem is listed), or no Next.js app |
The policy file fails closed: an unknown key, a misspelled rule name, or a bad value makes the whole policy invalid instead of quietly skipping that rule.
Baselines
An existing app usually breaks a new policy in a few places already. A baseline records those, so you can switch to enforce right away and fail only on new violations:
npx nextjs-lens check /path/to/project --update-baseline # record every current violation in nextjs-lens.baseline.json
npx nextjs-lens check /path/to/project --prune-baseline # remove violations that have been fixed; never adds new onesCommit nextjs-lens.baseline.json next to the policy file and protect it with CODEOWNERS too, since adding an entry allows a violation. Violations are matched by rule, file, and what they import, not by line number, so unrelated edits don't make known violations look new. A second offending import of the same thing in the same file is still new.
Each report lists new violations in full, known ones in a short list, and baseline entries that no longer occur, so the baseline can shrink as code is fixed. An invalid baseline file stops the check (exit code 2) instead of being ignored; --update-baseline regenerates it. Renaming a rule makes its baselined violations new, since the rule name is part of the match.
Rollout: start in warn mode to see what the policy reports, fix or except what's wrong, record the rest with --update-baseline, then switch to enforce.
Inline exceptions
To allow one specific violation, say why in a comment on the line above the import, or at the end of the import's first line:
// lens-allow client-bundle: only imports an error message constant, no server code
import { INVALID_TOKEN_ERROR } from '@acme/lib/server/turnstile'
import { db } from '@/server/db' // lens-allow "No server code in routes": removed in #1234Name the rule by type (forbidden-imports, client-bundle) or by its name in quotes. Other // comment lines may sit between the exception and the import.
The reason is required. A comment without one doesn't apply, and the report says so.
Every applied exception is listed in the report with its reason, so reviewers see them.
Comments that no longer match a violation are listed as unused, so they don't pile up.
Allowed violations are never written to the baseline. Removing the comment makes the violation fail again.
Use exceptions for decisions about a single import, and except in the policy for whole groups of files.
Pull request annotations (SARIF)
--sarif <file> also writes the violations that count (not baselined, not allowed by an exception) in SARIF, which GitHub code scanning shows on pull requests at the offending line. Run the check against the repository root so the paths line up.
# .github/workflows/nextjs-lens.yml
name: nextjs-lens
on: [pull_request]
permissions:
contents: read
security-events: write
jobs:
policy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 22
- run: npx -y nextjs-lens@0.4 check . --sarif nextjs-lens.sarif
- uses: github/codeql-action/upload-sarif@v3
if: always() && hashFiles('nextjs-lens.sarif') != ''
with:
sarif_file: nextjs-lens.sarifThe check step fails the job in enforce mode; the upload runs either way. Code scanning is free for public repositories; private repositories need GitHub Advanced Security. Without it, the check step's log still shows every violation.
Knowledge Resources
Markdown knowledge files are exposed as MCP resources that Claude can read:
knowledge/nextjs/docs/: selected official Next.js docs pages (routing, Server and Client Components, route handlers, proxy, data security, caching, environment variables, the version 16 upgrade guide), one resource per page, plusdocs/index.mdlisting them.npm run fetch-docsrefreshes them from nextjs.org's Markdown versions; don't edit them by hand.knowledge/nextjs/community.md: security checklist, Next.js 16 changes, gotchas, and patterns the official docs don't cover well. This is where contributors add the most value. PRs welcome.
Architecture
src/
├── cli.ts # The nextjs-lens command: starts the MCP server, or runs `check`
├── server.ts # MCP entry point, app resolution, rules, tool registration
├── core/
│ ├── types.ts # ToolRegistration, ToolCollector interfaces
│ ├── helpers.ts # safePath, walkFiles, file utilities
│ ├── rules.ts # .nextjs-lens.json loading and matching
│ ├── policy.ts # nextjs-lens.policy.json loading and validation
│ ├── check.ts # Runs policy rules and builds the check report
│ ├── checkCli.ts # `nextjs-lens check` arguments and output
│ ├── baseline.ts # nextjs-lens.baseline.json: known violations
│ ├── exceptions.ts # // lens-allow inline exceptions
│ ├── sarif.ts # SARIF output for GitHub code scanning
│ ├── runner.ts # Runs every Next.js tool with timings (snapshot script)
│ └── workspace.ts # Finds the Next.js app (PROJECT_PATH, NEXTJS_LENS_APP, or monorepo workspaces)
├── scanners/ # Generic tools
│ ├── files.ts # File listing, reading, searching
│ ├── imports.ts # Import/dependency tracing
│ └── styles.ts # Design system compliance checking
└── stacks/
├── nextjs.ts # Registers the Next.js tools; config, middleware, and env audits
└── nextjs/
├── ast.ts # Parsing, exports/imports, module resolution (tsconfig paths and extends, workspaces)
├── graph.ts # Shared, cached import graph used by every tool
├── routes.ts # Route tree and route list
├── boundaries.ts # Server/client boundary map
├── auth.ts # Route handler auth and server actions
├── unused.ts # Unused exports
├── fetching.ts # Data fetching and caching
├── forbidden.ts # forbidden-imports policy rule
├── clientBundle.ts # client-bundle policy rule
└── snapshot.ts # Snapshot normalization and diffing
test/ # node --test suites and fixture apps
knowledge/nextjs/ # Docs + community knowledge (MCP resources)
scripts/ # check.mjs (policy check), snapshot.mjs (real-app regression check), fetch-docs.tsDevelopment
npm test # compiles, then runs node --test against the fixture apps in test/fixturestest/fixtures/app (a single Next.js app) and test/fixtures/mono (a workspace monorepo) contain planted issues. The tests assert what each tool must find there and what it must not flag. CI runs the suite on Node 20 and 22.
Fixtures only cover the cases someone thought of, so also check a large real app before a release:
npm run snapshot -- /path/to/a/real/nextjs/app # first run saves a snapshot; later runs print what changed
npm run snapshot -- /path/to/a/real/nextjs/app --update # accept the current resultsThe report lists endpoint auth status flips, added and removed findings, changed counts, and tools that got much slower. It exits with 1 when anything changed. Snapshots are saved in .lens-snapshots/ (gitignored), since they depend on your local checkout.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Zero-config MCP security scanner for AI-generated apps. 25K+ vulnerability patterns.
Hosted code graph over MCP: exact callers, dependencies, and cross-repo blast radius for AI agents.
Enterprise code intelligence for M&A, security audits, and tech debt. Hosted server with 200k free.
Security, SEO and AI-visibility scanner for web apps · free scans and focused checks via MCP.
Related MCP Servers
- -licenseNot gradedqualityNot gradedmaintenanceAutomatically generates typed React hooks for Next.js projects by crawling API routes, GraphQL queries, and components. Analyzes pages to suggest optimal render modes (SSR/CSR/ISR) and produces documentation with performance guidance.-
- AlicenseNot gradedqualityCmaintenanceProvides code analysis for Next.js projects through the Model Context Protocol, enabling IDE and LLM integration to identify unused files, dead code, and redundant API endpoints.9 npm8MIT
- AlicenseNot gradedqualityBmaintenanceEnables MCP-compatible clients to inspect Next.js codebases, analyze App Router and Pages Router structure, discover API routes, and audit build performance through controlled tools.7 npmMIT
- AlicenseAqualityCmaintenanceMCP server that scans Next.js projects and returns a compact summary of routes, API endpoints, schema, and security issues.128 npm1MIT