Repository avatar
Search & Data Extraction
v1.0.9
active

filesystem-context

io.github.j0hanz/filesystem-context

🔍 Read-only MCP server for secure filesystem exploration, searching, and analysis

Documentation

FS Context MCP Server

FS Context MCP Server Logo

A secure, read-only MCP server for filesystem scanning, searching, and analysis with comprehensive security validation.

npm version License Node.js TypeScript MCP SDK

One-Click Install

Install with NPX in VS CodeInstall with NPX in VS Code Insiders

Install in Cursor

Features

  • Directory listing (immediate contents)
  • File search with glob patterns
  • Content search with regex and context lines
  • File reading with head previews (first N lines)
  • Batch reads and metadata lookups in parallel
  • Security: path validation, symlink escape protection, read-only operations

When to Use

TaskTool
Explore project structurels
Find filesfind
Search for code patterns/textgrep
Read source coderead
Batch read multiple filesread_many
Get file metadata (size, dates)stat
Batch get file metadatastat_many
Check available directoriesroots

Quick Start

NPX (recommended)

Allow the current working directory explicitly:

npx -y @j0hanz/fs-context-mcp@latest --allow-cwd

Or pass explicit directories:

npx -y @j0hanz/fs-context-mcp@latest /path/to/project /path/to/docs

If your MCP client supports the Roots protocol, you can omit directory arguments and let the client provide allowed directories. Otherwise, pass explicit directories or use --allow-cwd (if neither is provided, the server defaults to the current working directory).

VS Code (workspace folder)

Add to .vscode/mcp.json:

{
  "servers": {
    "fs-context": {
      "command": "npx",
      "args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
    }
  }
}

Installation

NPX (no install)

npx -y @j0hanz/fs-context-mcp@latest /path/to/dir1 /path/to/dir2

Global installation

npm install -g @j0hanz/fs-context-mcp
fs-context-mcp /path/to/your/project

From source

git clone https://github.com/j0hanz/fs-context-mcp-server.git
cd fs-context-mcp-server
npm install
npm run build
node dist/index.js /path/to/your/project

Directory Access and Resolution

Access is always restricted to explicitly allowed directories.

  1. CLI directories are validated and added first (if provided).
  2. --allow-cwd optionally adds the current working directory.
  3. MCP Roots from the client are used next:
    • If CLI and/or --allow-cwd are provided, only roots inside those baseline directories are accepted.
    • If no baseline is provided, roots become the allowed directories.
  4. If nothing is configured and the client provides no roots, the server defaults to the current working directory and logs a warning.

Notes:

  • Windows drive-relative paths like C:path are rejected. Use C:\path or C:/path.
  • Reserved Windows device names (e.g., CON, NUL) are blocked.

Configuration

All configuration is optional. Sizes in bytes, timeouts in milliseconds.

Environment Variables

VariableDefaultDescription
MAX_FILE_SIZE10MBMax file size for read operations (range: 1MB-100MB)
MAX_SEARCH_SIZE1MBMax file size for content search (range: 100KB-10MB)
DEFAULT_SEARCH_TIMEOUT30000Timeout for search/list operations (range: 100-3600000ms)
FS_CONTEXT_SEARCH_WORKERSmin(cpu cores, 8)Search worker threads (range: 1-16)

See CONFIGURATION.md for examples and CLI usage.

Tools

All tools return both human-readable text and structured JSON. Structured responses include ok, optional error (with code, message, path, suggestion), plus the tool-specific fields documented below.

roots

List all directories that this server can access.

ParameterTypeRequiredDefaultDescription
(none)----

Returns: Allowed directory paths. Structured output includes ok and directories.


ls

List the immediate contents of a directory (non-recursive). Omit path to use the first allowed root. If pattern is provided, listing is recursive up to maxDepth.

ParameterTypeRequiredDefaultDescription
pathstringNofirst rootDirectory path to list (omit to use first root)
includeHiddenbooleanNofalseInclude hidden files and directories
excludePatternsstring[]No[]Glob patterns to exclude
patternstringNo-Glob pattern to include (relative, no ..)
maxDepthnumberNo10Maximum depth when using pattern (0-100)
maxEntriesnumberNo10000Maximum entries to return (1-100000)
timeoutMsnumberNo30000Timeout in milliseconds
sortBystringNonameSort by: name, size, modified, type
includeSymlinkTargetsbooleanNofalseInclude symlink target paths (symlinks are not followed)

Returns: Entries with name, relativePath, type, size, and modified time. Structured output includes ok, path, entries, and totalEntries.


find

Search for files using glob patterns. Omit path to search from the first allowed root. find does not apply a built-in exclude list; scope your pattern to avoid dependency/build directories (e.g., src/**/*.ts).

ParameterTypeRequiredDefaultDescription
pathstringNofirst rootBase directory to search from (omit to use first root)
patternstringYes-Glob pattern (e.g., **/*.ts, src/**/*.js)
maxResultsnumberNo100Maximum matches to return (1-10000)

Returns: Matching paths (relative) with size and modified date. Structured output includes ok, results, totalMatches, and truncated.


read

Read the contents of a text file.

ParameterTypeRequiredDefaultDescription
pathstringYes-File path to read
headnumberNo-Read only first N lines

Notes:

  • Reads are UTF-8 text only; binary files are rejected.
  • Full reads are capped by MAX_FILE_SIZE (default 10MB). When head is set, output stops at the line limit or size budget, whichever comes first.

Returns: File content plus structured metadata (ok, path, content, truncated, totalLines).


read_many

Read multiple files in parallel.

ParameterTypeRequiredDefaultDescription
pathsstring[]Yes-Array of file paths (max 100)
headnumberNo-Read only first N lines of each file

Notes:

  • Reads files as UTF-8 text; binary files are not filtered. Max size per file is capped by MAX_FILE_SIZE (default 10MB).
  • Total read budget across all files is capped at 100MB.
  • No binary detection is performed; use read for single-file safety checks.

Returns: Per-file content or error, plus structured summary (total, succeeded, failed).


stat

Get detailed metadata about a file or directory.

ParameterTypeRequiredDefaultDescription
pathstringYes-Path to file or directory

Returns: name, path, type, size, timestamps (created/modified/accessed), permissions, hidden status, MIME type (for files), and symlink target (if applicable).


stat_many

Get metadata for multiple files/directories in parallel.

ParameterTypeRequiredDefaultDescription
pathsstring[]Yes-Array of paths to query (max 100)

Returns: Array of file info with individual success/error status, plus summary (total, succeeded, failed).


grep

Search for text content within files using regular expressions. Omit path to search from the first allowed root.

ParameterTypeRequiredDefaultDescription
pathstringNofirst rootBase directory to search in (omit to use first root)
patternstringYes-Regex pattern to search for
filePatternstringNo**/*Glob pattern to filter files
excludePatternsstring[]Nobuilt-in exclude listGlob patterns to exclude (overrides built-in list)
caseSensitivebooleanNofalseCase-sensitive search
maxResultsnumberNo100Maximum number of results
maxFileSizenumberNo1MBMaximum file size to scan (default from MAX_SEARCH_SIZE)
maxFilesScannednumberNo20000Maximum files to scan before stopping
timeoutMsnumberNo30000Timeout in milliseconds
skipBinarybooleanNotrueSkip likely-binary files
includeHiddenbooleanNofalseInclude hidden files and directories
includeIgnoredbooleanNofalseInclude ignored dirs (node_modules, dist) and disable built-in excludes
contextLinesnumberNo0Lines of context before/after match (0-10)
wholeWordbooleanNofalseMatch whole words only
isLiteralbooleanNofalseTreat pattern as literal string (escape regex chars)
baseNameMatchbooleanNofalseMatch file patterns without slashes against basenames
caseSensitiveFileMatchbooleanNotrueCase-sensitive filename matching

Returns: Matching lines with file path, line number, content, and optional context. Structured output includes ok, matches, totalMatches, and truncated. Matched line content is trimmed to 200 characters.


Built-in exclude list (used by grep when excludePatterns is not provided and includeIgnored is false) includes common dependency/build/output directories and files: node_modules, dist, build, coverage, .git, .vscode, .idea, .DS_Store, .next, .nuxt, .output, .svelte-kit, .cache, .yarn, jspm_packages, bower_components, out, tmp, .temp, npm-debug.log, yarn-debug.log, yarn-error.log, Thumbs.db. Pass excludePatterns: [] or includeIgnored: true to disable it.

Error Codes

CodeMeaning
E_ACCESS_DENIEDPath outside allowed roots
E_NOT_FOUNDPath does not exist
E_NOT_FILEExpected file, got directory
E_NOT_DIRECTORYExpected directory, got file
E_TOO_LARGEFile exceeds size limits
E_TIMEOUTOperation timed out
E_INVALID_PATTERNInvalid glob/regex pattern
E_INVALID_INPUTInvalid argument(s)
E_PERMISSION_DENIEDOS-level permission denied
E_SYMLINK_NOT_ALLOWEDSymlink escapes allowed roots
E_UNKNOWNUnexpected error

Client Configuration

VS Code

Add to .vscode/mcp.json (recommended) or .vscode/settings.json:

{
  "servers": {
    "fs-context": {
      "command": "npx",
      "args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
    }
  }
}
Claude Desktop

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "fs-context": {
      "command": "npx",
      "args": ["-y", "@j0hanz/fs-context-mcp@latest", "C:\\path\\to\\project"]
    }
  }
}

If your client supports MCP Roots, you can omit the path. Otherwise, pass a path or --allow-cwd.

Cursor

Add to Cursor's MCP configuration:

{
  "mcpServers": {
    "fs-context": {
      "command": "npx",
      "args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
    }
  }
}
Codex

Add to ~/.codex/config.toml:

[mcp_servers.fs-context]
command = "npx"
args = ["-y", "@j0hanz/fs-context-mcp@latest", "/path/to/your/project"]

If your client supports MCP Roots, you can omit the path. Otherwise, pass a path or --allow-cwd.

Windsurf

Add to Windsurf's MCP configuration:

{
  "mcpServers": {
    "fs-context": {
      "command": "npx",
      "args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
    }
  }
}

Security

This server implements multiple layers of security:

ProtectionDescription
Access controlOnly explicitly allowed directories are accessible
Path validationAll paths are validated before any filesystem operation
Symlink protectionSymlinks that resolve outside allowed directories are blocked
Path traversal preventionAttempts to escape via .. are detected and blocked
Read-only operationsNo writes, deletes, or modifications
Safe regexRegex validation with RE2 prevents ReDoS
Size limitsConfigurable limits prevent resource exhaustion

Development

Prerequisites

  • Node.js >= 20.0.0
  • npm

Scripts

CommandDescription
npm run buildCompile TypeScript to JavaScript
npm run devWatch mode with tsx
npm run startRun compiled server
npm run testRun tests (node --test with tsx/esm)
npm run test:watchRun tests in watch mode (node --test --watch)
npm run test:coverageRun tests with coverage (node --test --experimental-test-coverage)
npm run test:nodeRun node-tests (isolated checks)
npm run lintRun ESLint
npm run formatFormat code with Prettier
npm run type-checkTypeScript type checking
npm run inspectorTest with MCP Inspector

Project Structure

src/
  index.ts                 # CLI entry point
  server.ts                # MCP server wiring and roots handling
  tools.ts                 # MCP tool registration + response helpers
  schemas.ts               # Zod input/output schemas
  config.ts                # Shared types and formatting helpers
  instructions.md          # Tool usage instructions (bundled in dist)
  lib/                     # Core logic and filesystem operations
  __tests__/               # node:test + tsx tests
node-tests/                # Additional Node.js checks
docs/                      # Static docs assets
dist/                      # Build output (generated)

Troubleshooting

IssueSolution
"Access denied" errorEnsure the path is within an allowed directory. Use roots to check.
"Path does not exist"Verify the path exists. Use ls to explore available files.
"File too large"Use head or increase MAX_FILE_SIZE.
"Binary file" warningread only supports UTF-8 text and rejects binary files.
No directories availablePass explicit paths, use --allow-cwd, or ensure the client provides Roots.
Symlink blockedSymlinks that resolve outside allowed directories are blocked.
Invalid regex/patternSimplify the regex or set isLiteral=true for exact matches.

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Run format, lint, type-check, build, and tests (npm run format && npm run lint && npm run type-check && npm run build && npm run test)
  4. Commit your changes (git commit -m 'Add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Code Style

  • Use TypeScript with strict mode
  • Follow ESLint configuration
  • Use Prettier for formatting
  • Write tests for new features