Are you the author? Sign in to claim
A lightweight stdio-based MCP server for local file system operations — read, write, edit, search, exec for AI assistant
Zero-dependency MCP server for local file operations. 13 filesystem tools + 3 meta-tools for progressive discovery — no SDKs, no frameworks, no npm install needed.
MCP Protocol: 2024-11-05 · Transport: stdio + Streamable HTTP · Runtime: Node.js ≥ 22.0.0
local-mcp.mjs — 595 lines, 13 tools, entry point
lib/mcp-core.mjs — 229 lines, stdio + HTTP transport, 9 MCP methods
lib/config.mjs — 31 lines, MCP_WORKSPACE/DATA env config with validation
Total: ~855 lines, zero runtime dependencies.
| Tool | Description | Annotation |
|---|---|---|
read | Read file with line numbers, optional head/tail truncation | readOnlyHint |
search | File search by name (glob) then content (grep) | readOnlyHint |
ls | Compact directory listing with lazy stat | readOnlyHint |
exec | Streaming command execution with stdin support and timeout | destructiveHint |
diff | Diff two files or text strings (Myers O(ND)) | readOnlyHint |
copy | Copy file or directory | destructiveHint |
move | Move or rename file/directory | destructiveHint |
batch | Run multiple ops sequentially; atomic rollback, $prev refs | destructiveHint |
file | Unified: read, write, edit, append, delete, info, mkdir, move | — |
block | Read/replace/insert/delete code blocks by range or function name | — |
bookmark | Persistent path aliases (add/get/list/delete) | — |
grep | Compact file:line:content format with adaptive concurrency | readOnlyHint |
watch | Watch file/directory for changes; max 20 concurrent watchers | — |
| Tool | Description |
|---|---|
search_tools | Search available tools by keyword — saves ~90% tokens vs listing all |
describe_tool | Get full input schema for a specific tool (loaded on demand) |
call_tool | Execute any tool by name with arguments |
Instead of sending all 13 tool schemas (~3,000 tokens) in every request, progressive discovery with these 3 meta-tools reduces it to ~50 tokens — ~90% token savings.
| # | Optimization | Impact |
|---|---|---|
| A | Stream head/tail read | streamHead() avoids reading entire files. 500MB logs: 3s → 5ms, memory: 500MB → few KB |
| B | Lazy stat in ls | Only calls statSync when sort=size. 1000-file dir: 50ms → 2ms |
| C | Adaptive grep concurrency | os.availableParallelism() (max 16, min 4) instead of hardcoded 16 workers |
| D | LRU cache eviction | Map insertion-order LRU — hot small files no longer evicted by cold large files |
| E | Grep byte protection | MAX_GREP_TOTAL_MB=100 + MAX_GREP_FILES=1000 guards prevent OOM |
| F | Progress notification | _meta.progressToken passthrough for MCP 2025 spec (TODO: events for long exec) |
| Area | Detail |
|---|---|
| Read cache | Size-aware eviction (max 50 items, 10 MB) + 5s TTL |
| Myers diff | O(ND) algorithm, used by edit, block, and diff |
| Search scoring | Name-match first (no I/O), then stat only top 50 candidates |
| Output format | grep: file:line:content, ls: compact columns, read: line numbers + truncation hint |
| Protocol | O(1) Map dispatch, sync handler short-circuit |
# Zero install — no dependencies
node local-mcp.mjs
# With configuration
MCP_WORKSPACE=D:/projects node local-mcp.mjs
{
"mcpServers": {
"local-mcp": {
"command": "node",
"args": ["D:/path/to/local-mcp.mjs"],
"env": {
"MCP_WORKSPACE": "D:/projects"
}
}
}
}
node local-mcp.mjs --http
node local-mcp.mjs --http --port 3456
Supports JSON-RPC 2.0 POST, SSE streaming (Accept: text/event-stream), CORS, and GET /tools.
node local-mcp.mjs --help # Show usage + env vars
node local-mcp.mjs --list-tools # Print available tools and exit
node local-mcp.mjs --http # Start HTTP mode
node local-mcp.mjs --http --port 3456
| Variable | Default | Description |
|---|---|---|
MCP_WORKSPACE | process.cwd() | Working directory root (security boundary) |
MCP_DATA | {WORKSPACE}/.mcp-data | Data directory (bookmarks, temp files) |
MCP_DIR | {WORKSPACE} | Default directory for tree/ls commands |
MCP_PORT | 3100 | HTTP server port (when using --http) |
MCP_READONLY | false | Set to true to block all write operations |
MCP_EXCLUDE | — | Comma-separated extra dirs to exclude from search |
MCP_WORKSPACE and subdirectories__proto__/constructor/prototype injection).gitignore and common exclude dirs (node_modules, .git, etc.) respectedZero runtime dependencies. Uses only Node.js built-ins:
| Module | Purpose |
|---|---|
fs | File system + glob (Node 22) |
child_process | Streaming shell execution |
http | HTTP transport (no Express needed) |
path | Path resolution |
os | availableParallelism() for adaptive concurrency |
readline | Streaming line-by-line processing |
availableParallelism()streamHead scope bug — done defined outside Promise callback# Run tests
node --test test/*.test.mjs
# Adding a tool
# 1. Define schema + handler in local-mcp.mjs
# 2. Register with server.tool()
# 3. Add tests
MIT
Run Claude Code as an MCP server so any agent can delegate coding tasks to it
Browser automation using accessibility snapshots instead of screenshots
Google's universal MCP server supporting PostgreSQL, MySQL, MongoDB, Redis, and 10+ databases
Official GitHub integration for repos, issues, PRs, and CI/CD workflows