An MCP (Model Context Protocol) server that enables LLMs to read and understand locally installed package source code, helping reduce API hallucinations by providing direct access to actual installed packages.
- 🔍 Auto-Detection: Automatically detects Python or Node.js projects
- 📖 Source Code Access: Direct reading of actual installed package source code
- ⚡ High Performance: SQLite cache with 40x faster validity checks
- 🎯 Zero Configuration: Works immediately with standard project structures
- 🚀 Production Ready: 300+ tests, 14 CI stages, comprehensive error handling
- 📊 Summary Mode: Get package counts with 99% token reduction
- 🔎 Regex Filtering: Filter packages by pattern matching
- 📦 Category Filtering: Separate production/development dependencies (Node.js)
- 🏷️ Group Filtering: Pre-defined groups (testing, linting, building, etc.)
- 🎚️ Smart Limits: Default 50 packages to optimize LLM token usage
- 🚫 Type Exclusion: Optionally exclude @types packages
- 📦 Node.js: Full support with dependency categorization
- Package managers: npm, pnpm, yarn, bun
- Production vs development classification
- Scoped packages (@org/package)
- 🐍 Python: Full support for virtual environments
- Package managers: pip, uv (full support), poetry, pipenv (detection)
- Virtual environments: venv, .venv, conda
- Bottles architecture for isolated package operations
- Note: Dependency categorization pending
- 💾 SQLite Cache: High-performance cache with WAL mode for concurrent access
- 📈 Relevance Scoring: Prioritizes direct dependencies (Node.js)
- 🌲 Lazy Loading: File trees loaded on-demand
- ⏱️ Fast Operations: ~150ms scan, ~10ms read, ~5ms cache hits
- 🚀 40x Faster: Validity checks in 0.03ms vs 1.2ms (old JSON cache)
- 🛠️ TypeScript 5.9+: Strict mode with full type safety
- 📦 ES Modules: Modern JavaScript with import maps
- 🧪 Comprehensive Testing: 300+ tests covering all scenarios
- 🔒 Security: Path sanitization, file size limits, read-only access
- 🚀 MCP SDK: Latest Model Context Protocol implementation
- ⚙️ CI/CD: 14-stage pipeline with 4-minute total runtime
LLMs often hallucinate APIs or use outdated syntax from their training data. This tool solves that by letting LLMs read the actual source code of packages installed in your environment, ensuring generated code matches your exact package versions.
npm install -g @descoped/mcp-pkg-localnpx @descoped/mcp-pkg-localCreate .mcp.json in your project root:
{
"mcpServers": {
"pkg-local": {
"command": "npx",
"args": ["@descoped/mcp-pkg-local"],
"env": {
"DEBUG": "mcp-pkg-local:*"
}
}
}
}Or use the CLI:
claude mcp add pkg-local -- npx @descoped/mcp-pkg-localFor local development/testing with the built version:
{
"mcpServers": {
"pkg-local": {
"command": "node",
"args": ["/absolute/path/to/mcp-pkg-local/dist/index.js"],
"env": {
"DEBUG": "mcp-pkg-local:*"
}
}
}
}Create or edit ~/.config/gemini/mcp.json:
{
"mcpServers": {
"pkg-local": {
"command": "npx",
"args": ["@descoped/mcp-pkg-local"]
}
}
}After adding, use /mcp list in Gemini CLI to verify the server is configured.
Create .cursor/mcp.json in your project root:
{
"mcpServers": {
"pkg-local": {
"command": "npx",
"args": ["-y", "@descoped/mcp-pkg-local"],
"cwd": "${workspaceFolder}"
}
}
}Open Cursor Settings → MCP to verify connection (green status).
Add to .continue/config.json:
{
"models": [...],
"mcpServers": {
"pkg-local": {
"command": "npx",
"args": ["@descoped/mcp-pkg-local"],
"cwd": "${workspaceFolder}"
}
}
}Create .windsurf/mcp.json in your project root:
{
"mcpServers": {
"pkg-local": {
"command": "npx",
"args": ["-y", "@descoped/mcp-pkg-local"]
}
}
}macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"pkg-local": {
"command": "npx",
"args": ["-y", "@descoped/mcp-pkg-local"]
}
}
}After adding, restart Claude Desktop completely. You'll see the MCP indicator (🔌) in the conversation input box.
Once configured, the MCP server provides two main tools:
Scan and index all packages in the virtual environment.
Parameters:
forceRefresh(bool) - Force rescan even if index existsfilter(string) - Regex pattern to filter package names (e.g.,^@types/,eslint)limit(number) - Max packages to return (default: 50)summary(bool) - Return only summary countscategory(string) - Filter by production/development/allincludeTypes(bool) - Include @types packagesgroup(string) - Filter by group (testing, building, linting, etc.)
Examples:
// Scan with default settings (returns 50 packages)
scan-packages
// Force refresh the cache
scan-packages --forceRefresh
// Get summary only (token-efficient)
scan-packages --summary
// Returns: { total: 304, languages: { javascript: 304 }, categories: { production: 12, development: 292 } }
// Filter by regex pattern
scan-packages --filter "^react" // All React packages
scan-packages --filter "eslint" // Packages containing 'eslint'
// Filter by category
scan-packages --category production // Production dependencies only
scan-packages --category development // Dev dependencies only
// Filter by predefined groups
scan-packages --group testing // Testing tools (jest, mocha, vitest, etc.)
scan-packages --group building // Build tools (webpack, vite, rollup, etc.)
scan-packages --group linting // Linters (eslint, prettier, etc.)
scan-packages --group typescript // TypeScript-related packages
// Exclude @types packages
scan-packages --includeTypes false
// Limit results
scan-packages --limit 10 // Return only 10 packagesRead source files from a specific package.
Parameters:
packageName(string, required) - Package name to readfilePath(string) - Specific file within packageincludeTree(bool) - Include full file tree (default: false)maxDepth(number) - Max depth for tree traversal (default: 2)pattern(string) - Glob pattern to filter files (e.g.,*.ts,src/**)
Examples:
// Get main files only (default - very efficient)
read-package express
// Returns: mainFiles, fileCount, package.json content
// Read specific file
read-package express lib/router/index.js
// Get full file tree
read-package express --includeTree
// Limit tree depth
read-package express --includeTree --maxDepth 2
// Filter files by pattern
read-package typescript --includeTree --pattern "*.d.ts"
read-package express --includeTree --pattern "lib/**"The tool has been optimized for LLM token consumption:
| Operation | v0.1.0 | v0.2.0 | Reduction |
|---|---|---|---|
| Full scan (all packages) | 20,000 | 2,000 | 90% |
| Summary scan | N/A | 200 | 99% |
| Filtered scan (e.g., testing tools) | 20,000 | 500 | 97.5% |
| Read package (default) | 5,000 | 300 | 94% |
| Read package with tree | 5,000 | 1,000 | 80% |
| Large TypeScript files (AST) | 100,000 | 300 | 99.7% |
- Default Limits: Returns only 50 packages by default instead of all
- Lazy File Trees: Shows only main files unless full tree is requested
- Relative Paths: Uses relative paths to save ~30% on path strings
- Smart Filtering: Multiple ways to get exactly what you need
- Summary Mode: Get counts without package details
- AST Extraction: TypeScript/JavaScript files parsed to 99.7% smaller output
- Simplified API: Only 3 total parameters across both tools (v0.2.0)
- Environment Detection: Automatically detects Python (
.venv/venv) or Node.js (package.json) projects - Package Discovery:
- Python: Scans
site-packagesand reads.dist-infometadata - Node.js: Scans
node_modulesincluding scoped packages
- Python: Scans
- Smart Caching: SQLite database (
.pkg-local-cache/cache.db) for high-performance lookups - Source Reading: Provides file trees and actual source code to LLMs
The project includes a "Bottles" architecture for isolated package management operations:
- Persistent shell process management for stateful command execution
- Activity-based timeout system that resets on stdout progress
- Cross-platform support (Windows PowerShell, Linux bash, macOS bash)
- Command queueing with automatic cleanup on timeout
- Virtual environment activation support
- Cache management for 12+ package managers (npm, pip, poetry, maven, etc.)
- Cross-platform cache path detection and mounting
- 10x CI/CD performance improvement through cache persistence
- Environment variable injection for consistent package operations
- Proper error handling with actionable error messages
- Unified interface for pip and uv (Python package managers)
- Dynamic tool detection replaces hardcoded paths
- Configurable timeouts with activity-based reset behavior
- Support for requirements.txt, pyproject.toml, and lock files
- Clean, isolated environments preventing system pollution
- Node.js 20+ (LTS recommended)
- npm 10+ or pnpm
- Python 3.9+ with virtual environment (for Python support)
- Node.js project with node_modules (for Node.js support)
# Clone the repository
git clone https://github.com/descoped/mcp-pkg-local.git
cd mcp-pkg-local
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Development mode
npm run dev
# Clean build artifacts and cache
npm run clean # Remove everything (dist, node_modules, cache)
npm run clean:cache # Remove only cache filesmcp-pkg-local/
├── src/
│ ├── index.ts # Entry point
│ ├── server.ts # MCP server setup
│ ├── tools/ # MCP tool implementations
│ ├── scanners/ # Language-specific scanners
│ └── utils/ # Utilities
├── tests/ # Test suite
└── dist/ # Compiled output
The project includes comprehensive tests using Vitest with configurable timeouts:
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run in watch mode
npm run test:uiTests use centralized timeout presets that automatically adjust for CI environments:
- Short tests (5s): Unit tests, quick validations
- Medium tests (15s): Integration tests, package operations
- Long tests (30s): End-to-end workflows, complex scenarios
In CI environments, timeouts are automatically multiplied by 1.5x for reliability.
Tests are run sequentially to avoid SQLite locking issues and race conditions.
The following environment variables can be used to customize the behavior:
BOTTLE_CACHE_ROOT- Custom cache directory for all package data (default:.pkg-local-cache)- Example:
export BOTTLE_CACHE_ROOT=/tmp/pkg-cache - Used for: Package cache, SQLite database, bottle volumes
- Example:
TEST_BASE_DIR- Base directory for test temporary files (default:output/test-temp)PRESERVE_TEST_DIRS_ON_FAILURE- Keep test directories on failure for debugging (default:truelocally,falsein CI)USE_SYSTEM_TEMP- Use system temp directory instead of local (default:falselocally,truein CI)
DEBUG=mcp-pkg-local:*- Enable debug loggingNODE_ENV=production- Production mode (disables debug features)
PKG_LOCAL_TIMEOUT_MULTIPLIER- Multiplier for all operation timeouts (default:1.0)- Example:
export PKG_LOCAL_TIMEOUT_MULTIPLIER=2(doubles all timeouts) - Useful for: Slow networks, CI environments, or debugging
- Example:
The system uses activity-based timeouts that reset on stdout progress:
- Quick operations (5s): Version checks, package listings
- Standard operations (30s): Package installations, virtual environment creation
- Extended operations (60s): Large installations (rarely used)
Timeouts automatically reset when commands show progress output (downloads, installations). Error output (stderr) does NOT reset timeouts to prevent hanging on failing commands.
The cache system uses SQLite for optimal performance:
- Location:
${BOTTLE_CACHE_ROOT}/cache.db(or.pkg-local-cache/cache.dbif not set) - Mode: WAL (Write-Ahead Logging) for concurrent access
- TTL: 1-hour default validity
- Refresh: Use
--forceRefreshto force rescan
You can customize the cache location using the BOTTLE_CACHE_ROOT environment variable:
# Absolute path
export BOTTLE_CACHE_ROOT=/tmp/pkg-cache
# Relative path (relative to project root)
export BOTTLE_CACHE_ROOT=build/cache
# In CI/CD environments
export BOTTLE_CACHE_ROOT=${CI_PROJECT_DIR}/.pkg-cacheThis is particularly useful for:
- CI/CD environments where you want persistent cache between builds
- Shared development environments
- Docker containers with mounted cache volumes
- Testing with isolated cache directories
- ✅ Virtual environments (venv, .venv)
- ✅ Package managers: pip, poetry, uv, pipenv (basic detection)
- ✅ Standard pip packages
- ✅ Editable installations (-e)
- ✅ Namespace packages
⚠️ Limited: No dependency categorization yet- 🚧 Conda environments (planned)
- ✅ node_modules directory
- ✅ Package managers: npm, pnpm, yarn, bun (full support)
- ✅ Scoped packages (@org/package)
- ✅ TypeScript packages
- ✅ ESM and CommonJS modules
- ✅ Production vs development categorization
- Python dependency categorization not yet implemented
- Local environments only (no system packages)
- Read-only access (cannot modify packages)
- 10MB file size limit for source files
- Go, Rust, Java support planned for future versions
- Never reads files outside virtual environment or node_modules
- Path sanitization prevents directory traversal
- No code execution, only reading
- Binary files are blocked
Contributions are welcome! Please read our Contributing Guide for details.
- Fork the repository
- Create a feature branch
- Write tests for new features
- Ensure all tests pass
- Submit a pull request
- Python virtual environment support
- Basic package scanning and reading
- MCP server implementation
- Caching system
- Performance optimizations (90% token reduction)
- Advanced filtering (regex, category, groups)
- Lazy file tree loading
- Summary mode for minimal tokens
- Node.js/JavaScript support
- Multi-package manager support
- Bottles architecture for isolated package operations
- Shell-RPC engine with activity-based timeouts
- Volume controller for cache management
- Dynamic tool detection (no hardcoded paths)
- AST extraction for TypeScript/JavaScript (99.7% reduction)
- Simplified API (77% parameter reduction)
- 300+ tests with 14 CI stages
- Production-ready error handling
-
Python dependency categorization (critical)
-
Smart package prioritization
-
Conda environment support
-
Package alias resolution
-
Dependency tree visualization
-
Go modules support
-
Rust/Cargo support
-
Auto-trigger on import detection
-
Package documentation extraction
MIT License - see LICENSE file for details
Built with:
Made with ❤️ for better LLM code generation