FS Context MCP Server
A secure, read-only MCP server that enables filesystem scanning, searching with glob patterns and regex, file reading, and batch operations with comprehensive path validation and security protections.
README
FS Context MCP Server
<img src="docs/logo.png" alt="FS Context MCP Server Logo" width="125">
A secure, read-only MCP server for filesystem scanning, searching, and analysis with comprehensive security validation.
One-Click Install
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
| Task | Tool |
|---|---|
| Explore project structure | ls |
| Find files | find |
| Search for code patterns/text | grep |
| Read source code | read |
| Batch read multiple files | read_many |
| Get file metadata (size, dates) | stat |
| Batch get file metadata | stat_many |
| Check available directories | roots |
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.
- CLI directories are validated and added first (if provided).
--allow-cwdoptionally adds the current working directory.- MCP Roots from the client are used next:
- If CLI and/or
--allow-cwdare provided, only roots inside those baseline directories are accepted. - If no baseline is provided, roots become the allowed directories.
- If CLI and/or
- 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:pathare rejected. UseC:\pathorC:/path. - Reserved Windows device names (e.g.,
CON,NUL) are blocked.
Configuration
All configuration is optional. Sizes in bytes, timeouts in milliseconds.
Environment Variables
| Variable | Default | Description |
|---|---|---|
MAX_FILE_SIZE |
10MB | Max file size for read operations (range: 1MB-100MB) |
MAX_SEARCH_SIZE |
1MB | Max file size for content search (range: 100KB-10MB) |
DEFAULT_SEARCH_TIMEOUT |
30000 | Timeout for search/list operations (range: 100-3600000ms) |
FS_CONTEXT_SEARCH_WORKERS |
min(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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| (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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | No | first root |
Directory path to list (omit to use first root) |
includeHidden |
boolean | No | false |
Include hidden files and directories |
excludePatterns |
string[] | No | [] |
Glob patterns to exclude |
pattern |
string | No | - | Glob pattern to include (relative, no ..) |
maxDepth |
number | No | 10 |
Maximum depth when using pattern (0-100) |
maxEntries |
number | No | 10000 |
Maximum entries to return (1-100000) |
timeoutMs |
number | No | 30000 |
Timeout in milliseconds |
sortBy |
string | No | name |
Sort by: name, size, modified, type |
includeSymlinkTargets |
boolean | No | false |
Include 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).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | No | first root |
Base directory to search from (omit to use first root) |
pattern |
string | Yes | - | Glob pattern (e.g., **/*.ts, src/**/*.js) |
maxResults |
number | No | 100 |
Maximum 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | Yes | - | File path to read |
head |
number | No | - | 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). Whenheadis 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
paths |
string[] | Yes | - | Array of file paths (max 100) |
head |
number | No | - | 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
readfor 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | Yes | - | 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
paths |
string[] | 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
path |
string | No | first root |
Base directory to search in (omit to use first root) |
pattern |
string | Yes | - | Regex pattern to search for |
filePattern |
string | No | **/* |
Glob pattern to filter files |
excludePatterns |
string[] | No | built-in exclude list | Glob patterns to exclude (overrides built-in list) |
caseSensitive |
boolean | No | false |
Case-sensitive search |
maxResults |
number | No | 100 |
Maximum number of results |
maxFileSize |
number | No | 1MB | Maximum file size to scan (default from MAX_SEARCH_SIZE) |
maxFilesScanned |
number | No | 20000 |
Maximum files to scan before stopping |
timeoutMs |
number | No | 30000 |
Timeout in milliseconds |
skipBinary |
boolean | No | true |
Skip likely-binary files |
includeHidden |
boolean | No | false |
Include hidden files and directories |
includeIgnored |
boolean | No | false |
Include ignored dirs (node_modules, dist) and disable built-in excludes |
contextLines |
number | No | 0 |
Lines of context before/after match (0-10) |
wholeWord |
boolean | No | false |
Match whole words only |
isLiteral |
boolean | No | false |
Treat pattern as literal string (escape regex chars) |
baseNameMatch |
boolean | No | false |
Match file patterns without slashes against basenames |
caseSensitiveFileMatch |
boolean | No | true |
Case-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
| Code | Meaning |
|---|---|
E_ACCESS_DENIED |
Path outside allowed roots |
E_NOT_FOUND |
Path does not exist |
E_NOT_FILE |
Expected file, got directory |
E_NOT_DIRECTORY |
Expected directory, got file |
E_TOO_LARGE |
File exceeds size limits |
E_TIMEOUT |
Operation timed out |
E_INVALID_PATTERN |
Invalid glob/regex pattern |
E_INVALID_INPUT |
Invalid argument(s) |
E_PERMISSION_DENIED |
OS-level permission denied |
E_SYMLINK_NOT_ALLOWED |
Symlink escapes allowed roots |
E_UNKNOWN |
Unexpected error |
Client Configuration
<details> <summary><b>VS Code</b></summary>
Add to .vscode/mcp.json (recommended) or .vscode/settings.json:
{
"servers": {
"fs-context": {
"command": "npx",
"args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
}
}
}
</details>
<details> <summary><b>Claude Desktop</b></summary>
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.
</details>
<details> <summary><b>Cursor</b></summary>
Add to Cursor's MCP configuration:
{
"mcpServers": {
"fs-context": {
"command": "npx",
"args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
}
}
}
</details>
<details> <summary><b>Codex</b></summary>
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.
</details>
<details> <summary><b>Windsurf</b></summary>
Add to Windsurf's MCP configuration:
{
"mcpServers": {
"fs-context": {
"command": "npx",
"args": ["-y", "@j0hanz/fs-context-mcp@latest", "${workspaceFolder}"]
}
}
}
</details>
Security
This server implements multiple layers of security:
| Protection | Description |
|---|---|
| Access control | Only explicitly allowed directories are accessible |
| Path validation | All paths are validated before any filesystem operation |
| Symlink protection | Symlinks that resolve outside allowed directories are blocked |
| Path traversal prevention | Attempts to escape via .. are detected and blocked |
| Read-only operations | No writes, deletes, or modifications |
| Safe regex | Regex validation with RE2 prevents ReDoS |
| Size limits | Configurable limits prevent resource exhaustion |
Development
Prerequisites
- Node.js >= 20.0.0
- npm
Scripts
| Command | Description |
|---|---|
npm run build |
Compile TypeScript to JavaScript |
npm run dev |
Watch mode with tsx |
npm run start |
Run compiled server |
npm run test |
Run tests (node --test with tsx/esm) |
npm run test:watch |
Run tests in watch mode (node --test --watch) |
npm run test:coverage |
Run tests with coverage (node --test --experimental-test-coverage) |
npm run test:node |
Run node-tests (isolated checks) |
npm run lint |
Run ESLint |
npm run format |
Format code with Prettier |
npm run type-check |
TypeScript type checking |
npm run inspector |
Test 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
| Issue | Solution |
|---|---|
| "Access denied" error | Ensure 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" warning | read only supports UTF-8 text and rejects binary files. |
| No directories available | Pass explicit paths, use --allow-cwd, or ensure the client provides Roots. |
| Symlink blocked | Symlinks that resolve outside allowed directories are blocked. |
| Invalid regex/pattern | Simplify the regex or set isLiteral=true for exact matches. |
Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run format, lint, type-check, build, and tests (
npm run format && npm run lint && npm run type-check && npm run build && npm run test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code Style
- Use TypeScript with strict mode
- Follow ESLint configuration
- Use Prettier for formatting
- Write tests for new features
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。