MCP Server that enables LLMs to interact with the local filesystem. Provides tools for navigation, search, file management, and analysis — all scoped to allowed directories. Filesystem MCP exposes a rich set of tools for reading, writing, searching, and inspecting files and directories. All operations are strictly bounded to the directories you provide at startup, preventing access to any path out
Add this skill
npx mdskills install j0hanz/filesystem-context-mcp-serverComprehensive filesystem MCP server with extensive tool set, excellent documentation, and strong security model
1# Filesystem MCP23   45[](https://insiders.vscode.dev/redirect/mcp/install?name=filesystem-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D) [](https://insiders.vscode.dev/redirect/mcp/install?name=filesystem-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D&quality=insiders)67[](https://cursor.com/deeplink/mcp-install?name=filesystem-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovZmlsZXN5c3RlbS1tY3BAbGF0ZXN0Il19)89MCP Server that enables LLMs to interact with the local filesystem. Provides tools for navigation, search, file management, and analysis — all scoped to allowed directories.1011## Overview1213Filesystem MCP exposes a rich set of tools for reading, writing, searching, and inspecting files and directories. All operations are strictly bounded to the directories you provide at startup, preventing access to any path outside those roots.1415## Key Features1617- **Navigation**: List directory contents (`ls`), render trees (`tree`), and query workspace roots (`roots`).18- **File I/O**: Read single or multiple files (`read`, `read_many`); write, edit, move, and delete (`write`, `edit`, `mv`, `rm`).19- **Search**: Find files by glob pattern (`find`) or search content with full regex support (`grep`).20- **Analysis**: Metadata and token estimates (`stat`, `stat_many`), SHA-256 hashing (`calculate_hash`), and unified diffs (`diff_files`).21- **Patch & Replace**: Apply unified patches (`apply_patch`) and bulk search-and-replace across files (`search_and_replace`).22- **Tasks**: Long-running tools support background task execution with progress notifications and cancellation.23- **Large Output Handling**: Oversized results are externalized to ephemeral resource URIs instead of truncating inline.24- **Security**: Strict path validation, safe regex via RE2, `.gitignore`-aware operations, and atomic writes.2526## Requirements2728- **Node.js** `>= 24`2930## Quick Start3132```json33{34 "mcpServers": {35 "filesystem-mcp": {36 "command": "npx",37 "args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/allowed/dir"]38 }39 }40}41```4243Run directly:4445```bash46npx -y @j0hanz/filesystem-mcp@latest /path/to/allowed/dir47```4849## Client Configuration5051<details>52<summary><b>Install in VS Code</b></summary>5354[](https://insiders.vscode.dev/redirect/mcp/install?name=filesystem-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D)5556Or add manually to `.vscode/mcp.json`:5758```json59{60 "servers": {61 "filesystem-mcp": {62 "command": "npx",63 "args": ["-y", "@j0hanz/filesystem-mcp@latest", "${workspaceFolder}"]64 }65 }66}67```6869CLI:7071```bash72code --add-mcp '{"name":"filesystem-mcp","command":"npx","args":["-y","@j0hanz/filesystem-mcp@latest","${workspaceFolder}"]}'73```7475</details>7677<details>78<summary><b>Install in VS Code Insiders</b></summary>7980[](https://insiders.vscode.dev/redirect/mcp/install?name=filesystem-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40j0hanz%2Ffilesystem-mcp%40latest%22%5D%7D&quality=insiders)8182CLI:8384```bash85code-insiders --add-mcp '{"name":"filesystem-mcp","command":"npx","args":["-y","@j0hanz/filesystem-mcp@latest","${workspaceFolder}"]}'86```8788</details>8990<details>91<summary><b>Install in Cursor</b></summary>9293[](https://cursor.com/deeplink/mcp-install?name=filesystem-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBqMGhhbnovZmlsZXN5c3RlbS1tY3BAbGF0ZXN0Il19)9495Or add to `~/.cursor/mcp.json`:9697```json98{99 "mcpServers": {100 "filesystem-mcp": {101 "command": "npx",102 "args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/dir"]103 }104 }105}106```107108</details>109110<details>111<summary><b>Install in Claude Desktop</b></summary>112113Add to `claude_desktop_config.json`:114115```json116{117 "mcpServers": {118 "filesystem-mcp": {119 "command": "npx",120 "args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/dir"]121 }122 }123}124```125126</details>127128<details>129<summary><b>Install in Claude Code</b></summary>130131```bash132claude mcp add filesystem-mcp -- npx -y @j0hanz/filesystem-mcp@latest /path/to/dir133```134135</details>136137<details>138<summary><b>Install in Windsurf</b></summary>139140```json141{142 "mcpServers": {143 "filesystem-mcp": {144 "command": "npx",145 "args": ["-y", "@j0hanz/filesystem-mcp@latest", "/path/to/dir"]146 }147 }148}149```150151</details>152153<details>154<summary><b>Install in Codex</b></summary>155156```toml157[mcp_servers.filesystem-mcp]158command = "npx"159args = ["-y", "@j0hanz/filesystem-mcp@latest", "${workspaceFolder}"]160```161162</details>163164<details>165<summary><b>Docker</b></summary>166167```bash168docker run -i --rm \169 -v /path/to/your/project:/projects/workspace:ro \170 ghcr.io/j0hanz/filesystem-mcp:latest \171 /projects/workspace172```173174MCP config:175176```json177{178 "mcpServers": {179 "filesystem-mcp": {180 "command": "docker",181 "args": [182 "run",183 "-i",184 "--rm",185 "-v",186 "/path/to/project:/projects/workspace:ro",187 "ghcr.io/j0hanz/filesystem-mcp:latest",188 "/projects/workspace"189 ]190 }191 }192}193```194195</details>196197## MCP Surface198199### Tools200201| Tool | Description |202| :------------------- | :--------------------------------------------------- |203| `roots` | List workspace roots the server can access |204| `ls` | List directory contents (non-recursive) |205| `find` | Find files by glob pattern |206| `tree` | Render a bounded directory tree |207| `read` | Read text content of a file |208| `read_many` | Read multiple files in one request |209| `stat` | Get file or directory metadata |210| `stat_many` | Get metadata for multiple paths |211| `grep` | Search file content by literal or RE2 regex |212| `calculate_hash` | Compute SHA-256 hash of a file or directory |213| `diff_files` | Generate a unified diff between two files |214| `mkdir` | Create a directory (recursive) |215| `write` | Write content to a file (create or overwrite) |216| `edit` | Edit a file via sequential string replacements |217| `mv` | Move or rename a file or directory |218| `rm` | Delete a file or directory |219| `apply_patch` | Apply a unified diff patch to a file |220| `search_and_replace` | Search and replace text across files matching a glob |221222---223224#### `roots` — List workspace roots225226Enumerate the directories the server is allowed to access. Call this first in any session.227228No input parameters.229230---231232#### `ls` — List directory contents233234List immediate directory contents (non-recursive). Returns name, type, size, and modified date per entry.235236| Parameter | Type | Required | Default | Description |237| :---------------------- | :--------------------------------- | :------: | :------ | :-------------------------------------------------------- |238| `path` | string | No | root | Base directory |239| `includeHidden` | boolean | No | `false` | Include hidden items (`.`) |240| `includeIgnored` | boolean | No | `false` | Include `node_modules`, `.git`, etc. |241| `pattern` | string | No | — | Glob filter enabling recursive traversal (e.g. `**/*.ts`) |242| `sortBy` | `name`\|`size`\|`modified`\|`type` | No | `name` | Sort field |243| `maxDepth` | integer | No | — | Max recursion depth when `pattern` is set (1–50) |244| `maxEntries` | integer | No | — | Truncation limit (1–20,000) |245| `includeSymlinkTargets` | boolean | No | `false` | Resolve and include symlink targets |246247---248249#### `find` — Find files by glob250251Locate files matching a glob pattern. Returns relative paths and metadata.252253| Parameter | Type | Required | Default | Description |254| :--------------- | :--------------------------------- | :------: | :------ | :-------------------------------------------------- |255| `pattern` | string | Yes | — | Glob pattern (e.g. `**/*.ts`, `src/*.js`) |256| `path` | string | No | root | Search root |257| `maxResults` | integer | No | `100` | Max results (1–10,000) |258| `maxDepth` | integer | No | — | Max directory depth to scan (0–100) |259| `sortBy` | `name`\|`size`\|`modified`\|`path` | No | `path` | Sort field |260| `includeHidden` | boolean | No | `false` | Include hidden files |261| `includeIgnored` | boolean | No | `false` | Include ignored directories (disables `.gitignore`) |262263> [!TIP]264> Supports background task execution with progress reporting.265266---267268#### `tree` — Render directory tree269270Returns both an ASCII tree (text) and a structured JSON tree.271272| Parameter | Type | Required | Default | Description |273| :--------------- | :------ | :------: | :------ | :-------------------------------------------------- |274| `path` | string | No | root | Base directory |275| `maxDepth` | integer | No | `5` | Max depth (0–50); `0` = root node only, no children |276| `maxEntries` | integer | No | `1000` | Max entries (1–20,000) |277| `includeHidden` | boolean | No | `false` | Include hidden items |278| `includeIgnored` | boolean | No | `false` | Include ignored items (disables `.gitignore`) |279280---281282#### `read` — Read file content283284Read text content of a single file with optional line-range or head preview.285286| Parameter | Type | Required | Default | Description |287| :---------- | :------ | :------: | :------ | :---------------------------------------------------------------------------- |288| `path` | string | Yes | — | Absolute path to file |289| `head` | integer | No | — | Read first N lines (1–100,000); mutually exclusive with `startLine`/`endLine` |290| `startLine` | integer | No | — | Start line (1-based, inclusive) |291| `endLine` | integer | No | — | End line (1-based, inclusive); requires `startLine` |292293Large files return a `resourceUri`; call `resources/read` on that URI for full content.294295---296297#### `read_many` — Read multiple files298299Batch-read up to 100 files in a single request.300301| Parameter | Type | Required | Default | Description |302| :---------- | :------- | :------: | :------ | :--------------------------------------- |303| `paths` | string[] | Yes | — | File paths (1–100 items) |304| `head` | integer | No | — | Read first N lines of each file |305| `startLine` | integer | No | — | Start line per file |306| `endLine` | integer | No | — | End line per file (requires `startLine`) |307308Per-file `truncationReason` can be `head`, `range`, or `externalized`. Total read budget is capped internally.309310---311312#### `stat` — Get file/directory metadata313314Returns name, type, size, created/modified/accessed timestamps, permissions, MIME type, and a token estimate (`size ÷ 4`).315316| Parameter | Type | Required | Default | Description |317| :-------- | :----- | :------: | :------ | :------------ |318| `path` | string | Yes | — | Absolute path |319320---321322#### `stat_many` — Get metadata for multiple paths323324Batch version of `stat`.325326| Parameter | Type | Required | Default | Description |327| :-------- | :------- | :------: | :------ | :------------------ |328| `paths` | string[] | Yes | — | Paths (1–100 items) |329330---331332#### `grep` — Search file content333334Search for text within files using literal match or RE2 regex. Returns matching lines with optional context.335336| Parameter | Type | Required | Default | Description |337| :--------------- | :------ | :------: | :------ | :------------------------------------------------------------------ |338| `pattern` | string | Yes | — | Text to search (literal by default, RE2 regex when `isRegex: true`) |339| `path` | string | No | root | Search root (file or directory) |340| `isRegex` | boolean | No | `false` | Treat `pattern` as RE2 regex |341| `caseSensitive` | boolean | No | `false` | Case-sensitive matching |342| `wholeWord` | boolean | No | `false` | Match whole words only |343| `contextLines` | integer | No | `0` | Lines of context before/after each match (0–50) |344| `maxResults` | integer | No | `500` | Max match rows returned (0–10,000) |345| `filePattern` | string | No | `**/*` | Glob to restrict candidate files (e.g. `**/*.ts`) |346| `includeHidden` | boolean | No | `false` | Include hidden files |347| `includeIgnored` | boolean | No | `false` | Include ignored directories |348349> [!NOTE]350> RE2 does not support lookahead, lookbehind, or backreferences. Results exceeding 50 inline matches are externalized via `resourceUri`.351352---353354#### `calculate_hash` — SHA-256 hash355356Compute a SHA-256 hash. For directories, produces a deterministic composite hash of all contained files (lexicographically sorted, `.gitignore`-aware).357358| Parameter | Type | Required | Default | Description |359| :-------- | :----- | :------: | :------ | :--------------------- |360| `path` | string | Yes | — | File or directory path |361362---363364#### `diff_files` — Generate unified diff365366Create a unified diff between two files. Check `isIdentical` in the response — if `true`, the files match and no patch is needed.367368| Parameter | Type | Required | Default | Description |369| :----------------- | :------ | :------: | :------ | :--------------------------------- |370| `original` | string | Yes | — | Original file path |371| `modified` | string | Yes | — | Modified file path |372| `context` | integer | No | — | Lines of context in the diff |373| `ignoreWhitespace` | boolean | No | `false` | Ignore leading/trailing whitespace |374| `stripTrailingCr` | boolean | No | `false` | Strip trailing carriage returns |375376Large diffs are externalized to a `resourceUri`.377378---379380#### `mkdir` — Create directory381382Create a directory and all missing parent directories (recursive).383384| Parameter | Type | Required | Default | Description |385| :-------- | :----- | :------: | :------ | :----------------------- |386| `path` | string | Yes | — | Directory path to create |387388---389390#### `write` — Write file391392Create or overwrite a file. Parent directories are created automatically.393394| Parameter | Type | Required | Default | Description |395| :-------- | :----- | :------: | :------ | :--------------- |396| `path` | string | Yes | — | File path |397| `content` | string | Yes | — | Content to write |398399> [!CAUTION]400> Overwrites existing file content without confirmation.401402---403404#### `edit` — Edit file405406Apply sequential literal string replacements to an existing file. Replaces the **first** occurrence of each `oldText`.407408| Parameter | Type | Required | Default | Description |409| :-------- | :--------------------- | :------: | :------ | :------------------------------------- |410| `path` | string | Yes | — | File to edit |411| `edits` | `{oldText, newText}[]` | Yes | — | Ordered list of replacement operations |412| `dryRun` | boolean | No | `false` | Validate edits without writing |413414Include 3–5 lines of surrounding context in `oldText` to uniquely target the location. Unmatched edits are reported in `unmatchedEdits`.415416---417418#### `mv` — Move or rename419420Move or rename a file or directory. Parent directories of the destination are created automatically. Falls back to copy+delete for cross-device moves.421422| Parameter | Type | Required | Default | Description |423| :------------ | :----- | :------: | :------ | :--------------- |424| `source` | string | Yes | — | Source path |425| `destination` | string | Yes | — | Destination path |426427---428429#### `rm` — Delete file or directory430431Delete a file or directory.432433| Parameter | Type | Required | Default | Description |434| :------------------ | :------ | :------: | :------ | :------------------------------ |435| `path` | string | Yes | — | Path to delete |436| `recursive` | boolean | No | `false` | Delete non-empty directories |437| `ignoreIfNotExists` | boolean | No | `false` | No error if the path is missing |438439> [!WARNING]440> Non-empty directories with `recursive: false` return `E_INVALID_INPUT` with guidance to retry using `recursive: true`.441442---443444#### `apply_patch` — Apply unified patch445446Apply a unified diff patch to a file. Always validate with `dryRun: true` before writing.447448| Parameter | Type | Required | Default | Description |449| :----------------------- | :------ | :------: | :------ | :----------------------------------------------------- |450| `path` | string | Yes | — | Target file path |451| `patch` | string | Yes | — | Unified diff patch content (must include hunk headers) |452| `fuzzFactor` | integer | No | `0` | Fuzzy matching tolerance |453| `autoConvertLineEndings` | boolean | No | `true` | Auto-convert line endings to match the target file |454| `dryRun` | boolean | No | `false` | Validate without writing |455456If patch application fails, regenerate a fresh patch via `diff_files` against the current file content and retry.457458---459460#### `search_and_replace` — Search and replace across files461462Replace text in all files matching a glob. Replaces **all** occurrences per file. Use `dryRun: true` to preview scope before writing.463464| Parameter | Type | Required | Default | Description |465| :-------------- | :------ | :------: | :------ | :----------------------------------------------------------------------- |466| `filePattern` | string | Yes | — | Glob for target files (e.g. `**/*.ts`) |467| `searchPattern` | string | Yes | — | Text to find |468| `replacement` | string | Yes | — | Replacement text |469| `path` | string | No | root | Search root directory |470| `isRegex` | boolean | No | `false` | Treat `searchPattern` as RE2 regex; supports capture groups (`$1`, `$2`) |471| `dryRun` | boolean | No | `false` | Preview matches without writing |472473---474475### Resources476477| URI | Description | MIME Type |478| :----------------------------- | :--------------------------------- | :-------------- |479| `internal://instructions` | Usage guidance for models | `text/markdown` |480| `filesystem-mcp://result/{id}` | Ephemeral cached large tool output | varies |481482When a tool response includes a `resource_link`/`resourceUri`, treat it as authoritative for full payload retrieval and call `resources/read` with that URI.483484### Prompts485486| Prompt | Description |487| :--------- | :---------------------------------------- |488| `get-help` | Returns usage instructions for the server |489490### Tasks (Background Execution)491492The server declares full task capabilities (`tasks/list`, `tasks/cancel`). The following tools support task-based invocation with progress notifications:493494`find`, `tree`, `read`, `read_many`, `stat_many`, `grep`, `mkdir`, `write`, `mv`, `rm`, `calculate_hash`, `apply_patch`, `search_and_replace`495496Include `_meta.progressToken` in a `tools/call` request to receive `notifications/progress` updates. Use `tools/call` with a `task` field to invoke as a background task, then poll `tasks/get` and retrieve output via `tasks/result`.497498Recommended task follow-up loop:4995001. Start with `tools/call` + `task` (optional `_meta.progressToken`).5012. Poll `tasks/get` until terminal status (`completed`, `failed`, `cancelled`).5023. Fetch final payload with `tasks/result`.503504Task status notifications (`notifications/tasks/status`) are best-effort and emitted only when the transport/runtime provides a notification sender.505506Cancellation semantics:507508- `tasks/cancel` is the canonical cancellation API.509- Clients should treat `E_CANCELLED` as cancellation even if a transport/client surfaces a terminal failure shape.510511## Configuration512513### CLI514515```text516filesystem-mcp [options] [allowedDirs...]517```518519| Option | Description |520| :----------------- | :-------------------------------------------------------- |521| `[allowedDirs...]` | Positional: one or more directories the server may access |522| `--allow-cwd` | Allow the current working directory as an additional root |523| `-v, --version` | Display server version |524| `-h, --help` | Display help |525526Examples:527528```bash529# Single directory530filesystem-mcp /project/src531532# Multiple directories533filesystem-mcp /project/src /project/tests534535# Current working directory536filesystem-mcp --allow-cwd537538# Combined539filesystem-mcp /project/src --allow-cwd540```541542### Allowed Directories543544Directories are resolved from three sources, merged at runtime:5455461. **CLI arguments** — positional directory paths passed at startup.5472. **MCP Roots protocol** — directories provided by the connected client after initialization (accepted only if they are within the CLI baseline when CLI directories are set).5483. **`--allow-cwd`** — the current working directory is added automatically.549550> [!TIP]551> If no directories are configured at startup and the connected client does not supply MCP Roots, all tool calls will fail. Pass at least one directory argument or use `--allow-cwd`.552553### Compatibility554555Set `FS_CONTEXT_STRIP_STRUCTURED=1` to strip `structuredContent` from tool results and `outputSchema` from tool definitions for compatibility with clients that only consume text content.556557## Security558559- **Path validation**: All operations use `isPathWithinDirectories` to prevent path traversal attacks.560- **Glob safety**: Glob patterns are validated to reject absolute paths and `..` traversal before execution.561- **Safe regex**: `re2` executes regex (no catastrophic backtracking); `safe-regex2` rejects unsafe patterns before use.562- **Hidden files**: Excluded from listings and searches by default; opt in with `includeHidden: true`.563- **Ignored directories**: `node_modules`, `.git`, `dist`, and similar directories are excluded by default; opt in with `includeIgnored: true`.564- **Windows safety**: Reserved device names (e.g. `CON`, `NUL`, `COM1`) and drive-relative paths (e.g. `C:path`) are rejected at the CLI.565- **Input limits**: Paths are bounded to 4,096 characters; patterns to 1,000 characters.566- **Atomic writes**: File writes use an atomic write-then-rename strategy to prevent partial writes.567- **Docker**: The container runs as a non-root user (`mcp`).568569> [!IMPORTANT]570> All diagnostic output goes to `stderr`. Tool handlers must never write to `stdout`, as doing so would corrupt the stdio transport.571572## Development573574### Install575576```bash577npm ci578```579580### Scripts581582| Script | Command | Purpose |583| :-------------- | :-------------------------------------------------------- | :---------------------------------- |584| `dev` | `tsc --watch` | Watch-mode TypeScript compilation |585| `dev:run` | `node --watch dist/index.js` | Run built server with file watching |586| `build` | `node scripts/tasks.mjs build` | Production build |587| `test` | `node scripts/tasks.mjs test` | Run full test suite |588| `test:fast` | `node --test --import tsx/esm src/__tests__/**/*.test.ts` | Fast test runner (no build step) |589| `test:coverage` | `node scripts/tasks.mjs test --coverage` | Test with coverage |590| `lint` | `eslint .` | Lint source files |591| `lint:fix` | `eslint . --fix` | Auto-fix lint issues |592| `format` | `prettier --write .` | Format all files |593| `type-check` | `node scripts/tasks.mjs type-check` | TypeScript type checking |594595### MCP Inspector596597```bash598npm run inspector599```600601Or manually:602603```bash604npx @modelcontextprotocol/inspector node dist/index.js /path/to/dir605```606607## Build & Release608609Releases are triggered manually via [GitHub Actions](.github/workflows/release.yml) (`workflow_dispatch`). The pipeline:6106111. Bumps `package.json` and `server.json` to the selected version (patch / minor / major or custom).6122. Runs lint, type-check, tests, and build.6133. Commits, tags (`vX.Y.Z`), and creates a GitHub Release with auto-generated notes.6144. Publishes to **npm** (`@j0hanz/filesystem-mcp`) with OIDC provenance.6155. Publishes to the **MCP Registry** (`io.github.j0hanz/filesystem-mcp`).6166. Builds and pushes the **Docker image** (`ghcr.io/j0hanz/filesystem-mcp`) for `linux/amd64` and `linux/arm64`.617618The [Glama](https://glama.ai/mcp/servers/j0hanz/filesystem-mcp) listing requires a separate manual release step on the Glama dashboard.619620### Docker Build (local)621622```bash623docker build -t filesystem-mcp .624```625626## Troubleshooting627628**No directories configured**629If no directories are provided at startup and the client doesn't supply MCP Roots, all tool calls fail with `E_ACCESS_DENIED`. Use `roots` to inspect configured roots.630631**Path outside allowed directories**632Tools return `E_ACCESS_DENIED` when a path is outside all allowed roots. Use `roots` first to see what is available.633634**Empty directory or no matches**635`find` and `grep` return empty results rather than errors when nothing matches. Verify the pattern and root path.636637**Pattern rejected (`E_INVALID_PATTERN`)**638Glob patterns cannot be absolute or use `..` to traverse upward. RE2 patterns are validated before use.639640**Non-empty directory delete fails**641`rm` returns `E_INVALID_INPUT` for non-empty directories without `recursive: true`. Either set `recursive: true` or remove contents first.642643**Patch application failed**644`apply_patch` requires valid unified hunk headers (`@@ -N,M +N,M @@`). Regenerate the patch with `diff_files` against the current file content and retry.645646**Stdout contamination**647The server uses stdio transport. Never write to `stdout` in custom integrations. All diagnostic output goes to `stderr`. For Claude Desktop, check `~/Library/Logs/Claude/mcp*.log` (macOS) or the equivalent on Windows.648649## License650651[MIT](LICENSE)652
Full transparency — inspect the skill content before installing.