Skip to main content
Glama
Saikiran2412

File System MCP Server

by Saikiran2412
README.md
# File System MCP Server

An MCP (Model Context Protocol) server that exposes filesystem operations —
listing directories, reading, writing, and searching files — as tools an
LLM can discover and invoke at runtime. Built as a learning project to
understand MCP's architecture from the ground up, using the low-level
`Server` API (raw JSON Schemas, not the decorator-based `FastMCP` shortcut).

## What this project demonstrates

- How an MCP **server** advertises capabilities to a **host** via `tools/list`,
  and how the host routes an LLM's tool-call decision back via `tools/call`
- Why **tool descriptions are prompt engineering**, not documentation — the
  LLM only ever sees the JSON Schema, never your source code
- Defensive server design: path sandboxing, input validation, structured
  error responses instead of crashes, and result truncation for large
  outputs
- The read-only vs. destructive vs. idempotent distinction MCP tool
  annotations are meant to capture

## Architecture

```
Host (Claude Desktop / MCP Inspector / any MCP client)
   │
   │  tools/list  →  server responds with schemas for all 4 tools
   │  tools/call  →  host sends {name, arguments}, server executes and
   │                 returns a result
   ▼
This server (stdio transport)
   │
   ▼
sandbox/  (all file operations are confined to this directory)
```

The server never calls the LLM and the LLM never calls the server directly —
the host sits in between, using the schemas below to decide when and how to
invoke each tool.

## Tools

| Tool | Type | Description |
|---|---|---|
| `read_file` | read-only | Reads and returns the full text content of a file |
| `list_directory` | read-only | Lists files and folders in a directory (folders suffixed with `/`) |
| `write_file` | destructive | Writes text to a file; refuses to overwrite existing files unless `overwrite: true` |
| `search_files` | read-only | Recursively searches by filename glob pattern and/or file content, capped at 100 results |

All tools operate relative to a sandboxed root directory (`./sandbox`) —
paths are resolved and verified to stay inside that boundary before any
filesystem access happens, blocking path-traversal attempts like
`../../etc/passwd`.

## Setup

```bash
uv sync
```

## Running

**With the MCP Inspector** (recommended for development — shows raw
protocol traffic and lets you call tools manually):

```bash
npx @modelcontextprotocol/inspector uv run main.py
```

Open the URL it prints, click **Connect**, then **Tools → List Tools** to
see all four schemas, and run any tool directly from the form UI.

**As a server for an MCP host** (e.g. Claude Desktop), add to your host's
MCP config:

```json
{
  "mcpServers": {
    "fs-mcp-server": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/fs-mcp-server", "main.py"]
    }
  }
}
```

## Security design

- **Sandboxing** (`resolve_safe_path`): every incoming path is joined onto
  the sandbox root, resolved to an absolute path, and checked with
  `Path.is_relative_to()` to confirm it didn't escape via `..` segments.
  Rejected paths raise a caught `ValueError`, never crash the server.
- **Overwrite protection**: `write_file` will not silently clobber an
  existing file — it requires an explicit `overwrite: true` argument.
- **Result truncation**: `search_files` caps output at 100 matches and
  notes when results were truncated, rather than risking an enormous
  response.
- **Graceful failure everywhere**: missing arguments, non-existent paths,
  wrong path types (file vs. directory), and unreadable/binary files all
  return a structured error message to the caller instead of raising an
  uncaught exception.

## Known limitations / next steps

- Tool annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`)
  are not yet set explicitly — without them, hosts may apply incorrect
  defaults (e.g. flagging a read-only tool as destructive).
- Currently stdio transport only; could be extended to streamable HTTP for
  remote deployment.
- `search_files` content search reads full file contents into memory per
  candidate file — fine for a learning project, would need streaming for
  very large files in production.

## Stack

Python, [`mcp`](https://pypi.org/project/mcp/) (official Anthropic SDK),
`uv` for dependency management.

TDQS

A4.1/5.0

Scored across 2 tools

Disambiguation5/5

The two tools have clearly distinct purposes: one reads file content and the other lists directory contents. There is no overlap or ambiguity.

Naming Consistency5/5

Both tool names follow a consistent verb_noun pattern (read_file, list_directory), making them predictable and easy to understand.

Tool Count2/5

Only 2 tools for a file system server is too few. Typical file operations like write, delete, or copy are missing, making the scope feel thin.

Completeness2/5

The server lacks essential file operations (create, update, delete, copy, move) and advanced directory listing features. The surface is significantly incomplete for a file system server.

Maintenance

ActivityStale
ResponsivenessNo issues