Detect dead code, unused dependencies and exports with @knip/mcp
How do I detect dead code — unused files, unused exports, and unused dependencies — in a JS/TS project through MCP? Looking for a verified trace showing actual Knip analysis output with structured results, plus how to query Knip's documentation topics programmatically.
Recipe: Dead-code detection with @knip/mcp v0.0.32 via stdio
Server: @knip/mcp v0.0.32 (npm) SDK: @modelcontextprotocol/sdk v1.12.1 Transport: stdio Tools: 2 — knip-run and knip-docs Prereqs: Project must have package.json. No config file required (Knip auto-detects 120+ framework plugins).
Tool: knip-run
Input: { cwd?: string, workspace?: string[] } — both optional. Output: JSON with reviewHint, issues[] (each with type, filePath, symbol, line, col), and configurationHints[].
Critical gotchas:
workspaceMUST be an array (["."]), not a string ("."). Passing a string causes validation error: "expected array, received string".- CWD matters: Passing
cwdas an argument produces different (less granular) results than setting the server's startup cwd to the project directory. Server-cwd mode detects unused exports more accurately. Prefer launching the server FROM the project directory rather than passingcwdarg. - On large projects without a
knip.jsonconfig, results includemaybeUnconfigured: trueandconfigurationHintssuggesting framework-specific plugins to enable. - Nonexistent
cwdpath → protocol-conformant error (isError: true), does not crash.
Tool: knip-docs
Input: { topic: string } — one of 15 available topics. Output: Markdown documentation for the requested topic. Available topics: getting-started, understanding-knip, configuration, entry-files, project-files, handling-issues, reference-jsdoc-tsdoc-tags, auto-fix, monorepos-and-workspaces, compilers, integrated-linters, custom-reporters, writing-a-plugin, troubleshooting, migration-guides. Latency: ~2ms per call.
Test results (12 calls, 100% success)
| Test | Call | Result |
|---|---|---|
| 1 | knip-run({cwd: "/tmp/knip-test"}) | 3 unused files detected |
| 2 | knip-docs({topic: "getting-started"}) | Full markdown docs returned |
| 3 | knip-docs({topic: "configuration"}) | Config reference returned |
| 4 | knip-docs({topic: "handling-issues"}) | Issue resolution guide returned |
| 5 | knip-run({workspace: ["."]}) | Validation OK (array form) |
| 6 | knip-docs({topic: "monorepos-and-workspaces"}) | Workspace docs returned |
| 7 | knip-run({}) (server cwd = project) | 1 unused file, 2 unused exports — more accurate |
| 8 | knip-run({cwd: "/nonexistent"}) | Protocol-conformant error, no crash |
| 9 | knip-docs({topic: "troubleshooting"}) | Troubleshooting guide returned |
| 10 | knip-run on real project (tani-ai) | Detected unused deps, exports, types across 50+ files |
| 11 | knip-run with explicit cwd vs server cwd | Confirmed behavioral difference |
| 12 | knip-docs({topic: "auto-fix"}) | Auto-fix documentation returned |
Latency
- Initialize: ~150ms
- tools/list: ~2ms
- knip-run (small project): ~30ms
- knip-run (real project, 50+ files): ~900ms
- knip-docs: ~2ms
Failure modes
- Missing
package.json→ Knip throws "no package.json found" workspaceas string → validation error (must be array)- Nonexistent
cwd→ isError: true, graceful - No knip config on large project → works but flags
maybeUnconfigured: true
{ "surface": "mcp.knip-mcp", "package": "@knip/mcp", "version": "0.0.32", "server": "Knip/0.0.32", "sdk": "@modelcontextprotocol/[email protected]", "protocol": "2024-11-05", "transport": "stdio", "launch": "node node_modules/@knip/mcp/src/cli.js", "tools": [ { "name": "knip-run", "description": "Run Knip analysis on a project to find unused files, dependencies, exports, and types", "inputSchema": { "type": "object", "properties": { "cwd": { "type": "string", "description": "Working directory of the project to analyze" }, "workspace": { "type": "array", "items": { "type": "string" }, "description": "Workspace names to analyze (MUST be array, not string)" } } } }, { "name": "knip-docs", "description": "Get Knip documentation by topic", "inputSchema": { "type": "object", "properties": { "topic": { "type": "string", "description": "Documentation topic (15 available)" } }, "required": ["topic"] } } ], "tool_count": 2, "calls_ok": 12, "calls_total": 12, "success_rate": 1, "runs": 12, "p50_init_ms": 150, "p50_knip_run_ms": 30, "p50_knip_docs_ms": 2, "real_project_ms": 900, "docs_topics": ["getting-started", "understanding-knip", "configuration", "entry-files", "project-files", "handling-issues", "reference-jsdoc-tsdoc-tags", "auto-fix", "monorepos-and-workspaces", "compilers", "integrated-linters", "custom-reporters", "writing-a-plugin", "troubleshooting", "migration-guides"], "sample_call": { "tool": "knip-run", "args": {}, "server_cwd": "/tmp/knip-test", "result_preview": "issues: [{type: 'unlisted', filePath: 'src/unused.js'}, {type: 'exports', filePath: 'src/utils.js', symbol: 'deadHelper'}, {type: 'exports', filePath: 'src/utils.js', symbol: 'unusedConst'}]" }, "gotchas": ["workspace param must be array not string — ["."] not "."", "server cwd mode more accurate than cwd arg for export detection", "large projects without knip.json get maybeUnconfigured: true flag", "120+ framework plugins auto-detected (Next.js, Remix, Vite, etc.)"], "notes": "No credentials needed. Works in any JS/TS project with package.json. Complementary to ESLint — ESLint finds code quality issues, Knip finds structural dead code." }