# Perfonext Build MCP

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/souvikdu/perfonext-build-mcp  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/perfonext-build-mcp

## Description
MCP server for Next.js build stats, chunk attribution, and bundle optimization advice.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "perfonext-build-mcp": {
    "command": "npx",
    "args": ["-y","perfonext-build-mcp"]
  }
}
```

## Documentation & README

# perfonext-build-mcp

> Analyze Next.js build artifacts to find heavy routes, shared chunks, and bundle growth.

[![npm](https://img.shields.io/npm/v/@perfonext/build-mcp)](https://www.npmjs.com/package/@perfonext/build-mcp)
[![npm downloads](https://img.shields.io/npm/dt/@perfonext/build-mcp)](https://www.npmjs.com/package/@perfonext/build-mcp)
[![license](https://img.shields.io/npm/l/@perfonext/build-mcp)](https://www.npmjs.com/package/@perfonext/build-mcp)

`perfonext-build-mcp` is a Model Context Protocol (MCP) server that gives GitHub Copilot, Claude Desktop,
Claude Code, and other MCP clients structured bundle analysis for Next.js performance work. It loads `.next`
build artifacts and turns them into route-size rankings, shared-chunk and duplication findings, and
severity-ranked fix suggestions — evidence agents can reason over instead of inspecting raw `.next` manifests.

## Quick Start

`perfonext-build-mcp` is a standard MCP stdio server, so it works with any MCP-compatible client
(GitHub Copilot in VS Code, Claude Desktop, Claude Code, Cursor, and others). Run it directly with
`npx`:

```bash
npx -y @perfonext/build-mcp
```

Or install globally:

```bash
npm install -g @perfonext/build-mcp
```

The executable command remains `perfonext-build-mcp` after installation.

### VS Code

Add the server to `.vscode/mcp.json` (the workspace MCP configuration file):

```json
{
  "servers": {
    "perfonext-build": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@perfonext/build-mcp"]
    }
  }
}
```

Reload the VS Code window and run **MCP: List Servers** to start it, or accept the trust prompt when it appears.

### Claude Desktop

Add the server to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "perfonext-build": {
      "command": "npx",
      "args": ["-y", "@perfonext/build-mcp"]
    }
  }
}
```

Restart Claude Desktop to pick up the new server.

### Claude Code

Add the server with the CLI:

```bash
claude mcp add perfonext-build -- npx -y @perfonext/build-mcp
```

Or add it directly to `.mcp.json`:

```json
{
  "mcpServers": {
    "perfonext-build": {
      "command": "npx",
      "args": ["-y", "@perfonext/build-mcp"]
    }
  }
}
```

### Other MCP clients

Any client that supports stdio MCP servers can launch the same command/args pair:
`command: npx`, `args: ["-y", "@perfonext/build-mcp"]`. Consult your client's docs for where its MCP
server configuration file lives.

For a locally-built checkout, point `command`/`args` at `node` and the repo's `dist/index.js` instead,
in any of the configurations above.

Then ask your assistant: _"Load the Next.js build in `./.next` and show me the largest routes."_

## Troubleshooting

### `spawn npx ENOENT` / `spawn node ENOENT` on macOS with nvm

If the server fails to start with `spawn npx ENOENT` (or `spawn node ENOENT`), your editor/app was
likely launched from the Dock/Finder and cannot see nvm. GUI apps on macOS do not load shell config
(`.zshrc`/`.bashrc`), so `npx`/`node` installed via nvm are not on `PATH`. This applies to VS Code,
Claude Desktop, and any other GUI MCP client on macOS.

Fix it by giving the MCP config an absolute `npx` path and a `PATH` that includes the same Node bin
directory (`dirname $(which npx)`):

```json
{
  "command": "/Users/YOU/.nvm/versions/node/v<version>/bin/npx",
  "args": ["-y", "@perfonext/build-mcp"],
  "env": {
    "PATH": "/Users/YOU/.nvm/versions/node/v<version>/bin:/usr/bin:/bin"
  }
}
```

Merge the `command`/`args`/`env` fields above into your client's server entry (e.g. under `servers`
for VS Code or `mcpServers` for Claude Desktop/Code).

## What It Does

- loads Next.js build artifacts from a `.next` directory
- ranks the largest user-facing routes by emitted bundle footprint
- identifies the heaviest shared chunks that affect multiple routes
- compares two builds and explains which routes and chunks drove bundle growth, with
  severity-ranked, evidence-backed fix suggestions
- matches chunks across builds even though Next.js fingerprints filenames with content hashes
- traces why a given module or npm package is bundled (import chain entry → module) when an
  optional webpack stats file is collected
- finds npm packages duplicated across chunks and explains what dominates shared chunks
- aggregates all of the above into severity-ranked, evidence-backed optimization suggestions tied to
  concrete Next.js actions
- keeps loaded build snapshots in memory so an MCP client can inspect them without re-reading the same build

## Tools

| Tool                    | Description                                                                                                        |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `load_build_stats`      | Parse a Next.js `.next` directory and load the build snapshot into memory                                          |
| `get_largest_routes`    | Rank the heaviest user-facing routes by total emitted chunk bytes                                                  |
| `get_shared_chunks`     | Rank shared chunks by size and show which routes depend on them                                                    |
| `compare_builds`        | Compare a baseline and current build snapshot to show which routes and chunks grew or shrank                       |
| `explain_growth`        | Severity-rank which routes and chunks drove bundle growth between two builds, with evidence-backed fix suggestions |
| `how_to_collect_stats`  | Return the recipe (manual) or an action plan (automatic) to generate `.next/stats.json`                            |
| `load_webpack_stats`    | Parse `.next/stats.json` and link it to a loaded build; required before `trace_import`                             |
| `trace_import`          | Explain why a module or npm package is bundled by walking its import chain to the entry                            |
| `find_duplicates`       | Rank npm packages whose code is emitted into more than one chunk, by wasted bytes                                  |
| `explain_shared_chunks` | Show which packages and app code dominate the shared chunks loaded by many routes                                  |
| `suggest_optimizations` | Aggregate route, chunk, and webpack-stats evidence into severity-ranked, evidence-backed fix suggestions           |

The output stays machine-readable and includes raw byte counts so your MCP client can explain regressions, prioritise fixes, and suggest concrete dependency or import-level follow-up.

Every `suggest_optimizations` finding is sized in `emittedBytes` — actual on-disk chunk bytes — so suggestions of different kinds rank on one scale. Unminified webpack module sizes appear only where they are named as such (`moduleSizeBytes`, `shareOfChunkModuleBytes`).

Because Next.js content-hashes emitted filenames (`framework-<hash>.js`, and CSS files named purely by hash), `compare_builds` and `explain_growth` match chunks across builds by a hash-normalized identity. This prevents a rehashed-but-unchanged chunk from being misreported as removed-and-recreated, while still flagging genuinely new chunks.

## Inputs

The core tools read build artifacts developers already have after running `next build`:

- `.next/build-manifest.json`
- `.next/prerender-manifest.json` when present
- `.next/app-build-manifest.json` when present
- `.next/app-path-routes-manifest.json` when present — maps App Router manifest keys (`/gallery/page`) to the real paths (`/gallery`) the prerender manifest is keyed by, so route `type`, `isPrerendered`, and `prerenderBlockedReason` are read from the build rather than guessed from the path
- optional captured `next build` output text to derive build duration

Import-level attribution (`trace_import`, `find_duplicates`, `explain_shared_chunks`) and the
stats-enriched suggestions from `suggest_optimizations` additionally need a webpack module-stats file
at `.next/stats.json`. A stock `next build` does not emit one; `how_to_collect_stats` returns the
recipe to generate it. The manifest tools above never read it, so they work with or without it.

### Deep bundle attribution (optional)

The manifest tools work with zero setup. To answer "why is this package bundled?", collect a webpack
stats file first:

1. Call `how_to_collect_stats({ method: 'manual' | 'automatic' })` and apply the returned steps — it
   adds `webpack-stats-plugin` and `cross-env`, gates a `next.config` hook behind `ANALYZE=true && !isServer`,
   and rebuilds with `cross-env ANALYZE=true next build --webpack`. Turbopack builds will not produce `.next/stats.json`.
2. Call `load_build_stats({ buildDir })` to get a `buildId`.
3. Call `load_webpack_stats({ buildId })` to parse the generated `.next/stats.json`.
4. Call `trace_import({ buildId, moduleName })` to see the import chain that pulls a module in.
5. Call `find_duplicates({ buildId })` to find packages bundled into more than one chunk, and
   `explain_shared_chunks({ buildId })` to see what dominates the chunks loaded by many routes.
6. Call `suggest_optimizations({ buildId })` for severity-ranked, evidence-backed recommendations.
   It works on manifests alone and is enriched with dedupe, shared-chunk, and package-import
   findings once stats are loaded. Code-split advice is tailored for Next.js framework routes
   (`/404`, `/500`, `/_error`, `/_app`, `/_document`) — these are flagged to be slimmed down by
   trimming imports rather than split with `next/dynamic`, which does not apply to them.

If the app builds with Turbopack there is no webpack module graph, so `how_to_collect_stats` says so
and points back to the manifest-only tools. The attribution tools degrade gracefully with a
breadcrumb when no stats file is loaded — it is never an error.

## Example Prompts

- "Load the Next.js build in `./.next` and show me the largest routes."
- "Which shared chunks are affecting the most routes in this build?"
- "Summarize the build footprint and tell me which routes ship the most JavaScript."
- "Compare my baseline and current `.next` builds and show me which routes or shared chunks grew the most."
- "Explain what grew between my baseline and current `.next` builds and what I should fix first."
- "Set up webpack stats collection so I can see why a package is bundled."
- "Why is `axios` in my bundle? Trace its import chain."
- "Which npm packages are duplicated across chunks and how many bytes are wasted?"
- "What's dominating my shared chunks?"
- "Suggest the highest-impact bundle optimizations for this build."

## Related Perfonext Tools

- [perfonext-profiler-mcp](https://github.com/souvikdu/perfonext-profiler-mcp) — CPU profiling (V8/Chrome) for Next.js servers
- [perfonext-render-mcp](https://github.com/souvikdu/perfonext-render-mcp) — React render analysis for Next.js apps

## Development

```bash
npm install
npm run build
npm test
```

Sample fixtures for local validation live under `tests/fixtures/`.

## License

MIT

