Filesystem Watcher MCP
README.md
# Filesystem Watcher MCP
[](https://pypi.org/project/filesystemwatcher-mcp)
[](https://pypistats.org/packages/filesystemwatcher-mcp)
[](LICENSE)
[](https://www.python.org/downloads/)
`filesystemwatcher-mcp` lets your AI coding agent (Gemini, Claude, Cursor, Copilot, etc.)
watch directories for live file-system changes. It acts as a
[Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server, giving your
agent event-driven access to file creations, modifications, deletions, and moves —
without busy-polling.
## Key features
- **Event-driven file watching**: Uses [Watchdog](https://github.com/gorakhargosh/watchdog) for cross-platform native OS events (`inotify`, `FSEvents`, `ReadDirectoryChangesW`).
- **Safe by design**: Blocks watching system-critical paths on Windows, macOS, and Linux. Strict path guardrails are enforced server-side.
- **Flexible filtering**: Filter events by file extension, glob pattern, or event type (`created`, `modified`, `deleted`, `moved`).
- **Debounced events**: Rapid successive events on the same file are coalesced over a 500 ms window — no duplicate noise.
- **Consume-once semantics**: `poll_events` drains the queue, making it easy to integrate into agent loops.
- **Explicit error surfacing**: All failure modes (permission denied, OS backend crash, watch limit) return structured `{"success": false, "error": "..."}` responses rather than crashing silently.
## Requirements
- [Python](https://www.python.org/) 3.10 or newer.
- [uv](https://docs.astral.sh/uv/) (recommended) or `pip`.
## Getting started
Add the following config to your MCP client:
```json
{
"mcpServers": {
"filesystemwatcher": {
"command": "uv",
"args": ["run", "python", "src/server.py"]
}
}
}
```
> [!NOTE]
> Make sure you have cloned the repository and installed dependencies (`uv sync`) before pointing your MCP client at the server.
### MCP Client configuration
<details>
<summary>Antigravity</summary>
To use the Filesystem Watcher MCP server, follow the instructions from <a href="https://antigravity.google/docs/mcp">Antigravity's docs</a> to install a custom MCP server. Add the following config to the MCP servers config:
```json
{
"mcpServers": {
"filesystemwatcher": {
"command": "uv",
"args": ["run", "python", "src/server.py"]
}
}
}
```
</details>
<details>
<summary>Claude Code</summary>
Use the Claude Code CLI to add the server (<a href="https://code.claude.com/docs/en/mcp">guide</a>):
```bash
claude mcp add filesystemwatcher --scope user uv run python src/server.py
```
</details>
<details>
<summary>Copilot / VS Code</summary>
Follow the MCP install <a href="https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_add-an-mcp-server">guide</a> and use the standard config from above.
</details>
<details>
<summary>Cursor</summary>
Go to `Cursor Settings` -> `MCP` -> `New MCP Server`. Use the config provided above.
</details>
<details>
<summary>Gemini CLI</summary>
```bash
gemini mcp add filesystemwatcher uv run python src/server.py
```
Alternatively, follow the <a href="https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md#how-to-set-up-your-mcp-server">MCP guide</a> and use the standard config from above.
</details>
<details>
<summary>Windsurf</summary>
Follow the <a href="https://docs.windsurf.com/windsurf/cascade/mcp#mcp-config-json">configure MCP guide</a> using the standard config from above.
</details>
### Your first prompt
Enter the following prompt in your MCP client to check if everything is working:
```
Watch my home directory for any new file creations and tell me when something appears.
```
Your agent should call `watch_directory` and then periodically call `poll_events` to report changes.
## Tools
- **File system watching** (4 tools)
- [`watch_directory`](#watch_directory)
- [`poll_events`](#poll_events)
- [`list_active_watches`](#list_active_watches)
- [`unwatch`](#unwatch)
### `watch_directory`
Start watching a directory for file system events. Returns a `watch_id` used to identify this watch session.
| Argument | Type | Default | Description |
|---|---|---|---|
| `path` | `str` | **required** | Absolute path to the directory to watch |
| `recursive` | `bool` | `false` | Also watch all subdirectories |
| `extensions` | `list[str]` | `null` | Filter by extension, e.g. `[".py", ".js"]` |
| `pattern` | `str` | `null` | Glob pattern matched against file name, e.g. `"*.log"` |
| `ignore_patterns` | `list[str]` | `null` | Glob patterns to exclude, e.g. `["*.tmp", ".git/*"]` |
| `event_types` | `list[str]` | `null` | Subset of `["created", "modified", "deleted", "moved"]` |
**Error responses** — on failure `success` is `false` and `error` explains why:
| Condition | Example error |
|---|---|
| Path blocked by safety guardrails | `"Watching '/etc' is not allowed: protected system location."` |
| Process lacks read permission | `"Permission denied: cannot watch '/protected'. Check read access."` |
| OS watcher backend failed to start | `"Filesystem observer failed to start for '...'. Backend may be unavailable."` |
| Concurrent watch limit reached | `"Watch limit reached (50 active watches). Call unwatch() first."` |
### `poll_events`
Drain and return queued file system events (consume-once semantics).
| Argument | Type | Default | Description |
|---|---|---|---|
| `watch_id` | `str` | `null` | Filter events by watch ID; if omitted, all watches are drained |
| `max_events` | `int` | `50` | Maximum events to return (1–500) |
If `watch_id` is provided but does not match any active watch, the response includes a `warning` field to prevent agents from silently spinning on a stale ID:
```json
{
"count": 0,
"events": [],
"warning": "No active watch found with id 'abc-123'. Use list_active_watches to see current watch IDs."
}
```
### `list_active_watches`
Return a summary of all currently active watches.
### `unwatch`
Stop and remove a watch by `watch_id`.
## Configuration
The server currently has no command-line flags; all configuration is done via the
tool arguments at runtime.
You can inspect available tools interactively with the MCP Inspector:
```bash
npx @modelcontextprotocol/inspector mcp dev src/server.py
```
## Safety guardrails
The server blocks watching dangerous system paths:
| Platform | Blocked (exact) | Blocked (subtree) |
|---|---|---|
| Windows | `C:\` | `C:\Windows`, `C:\Program Files`, `C:\ProgramData` |
| Linux | `/` | `/etc`, `/sys`, `/proc`, `/usr`, `/dev`, `/boot`, … |
| macOS | `/` | `/System`, `/Library`, `/usr`, `/private`, … |
Watching `C:\Users` or `/home` directly is also blocked; individual user home directories are allowed.
**Concurrent watch limit**: A maximum of **50 active watches** are allowed at any time to prevent exhausting the OS inotify quota. Call `unwatch` to free a slot before creating a new one.
> [!WARNING]
> The MCP server exposes file-system event data to MCP clients. Avoid watching directories that contain sensitive or personal data you would not want shared with your AI agent.
## Debouncing
Events are coalesced over a **500 ms window** per `(event_type, path)` key. Rapid
successive events on the same file (e.g. multiple writes during a save) are
reported as a single event.
## Development
```bash
# Clone and install dependencies
git clone https://github.com/your-org/filesystemwatcher-mcp
cd filesystemwatcher-mcp
uv sync
# Run the server directly
uv run python src/server.py
# Run with MCP Inspector
npx @modelcontextprotocol/inspector mcp dev src/server.py
# Run tests
uv run pytest
# Security audit
uv run pip-audit
```
## Known limitations
- Only local file systems are supported; network mounts may not deliver native OS events reliably.
- The server must be restarted to pick up changes to ignored/blocked path configuration.
TDQS
A3.9/5.0
Scored across 4 tools
Disambiguation5/5
Each tool has a distinct purpose: starting, listing, polling, and stopping watches. No overlap or ambiguity.
Naming Consistency4/5
All tools use verb_noun snake_case pattern. 'unwatch' is slightly non-standard but still clear and consistent.
Tool Count5/5
4 tools is appropriate for a filesystem watcher, covering all essential operations without being too many or too few.
Completeness5/5
Covers full lifecycle: create (watch_directory), read (list_active_watches, poll_events), delete (unwatch). No obvious gaps for basic watching.
Maintenance
ActivityInactive
ResponsivenessNo issues