MCP Filesystem Server

MCP Filesystem Server

Enables AI agents to safely read and write files in a sandboxed workspace via natural language, with on-demand connection, CVE-hardened path confinement, injection resistance, and full audit logging.

Category
Visit Server

README

Enterprise AI Chat Agent

An internal assistant: multi-turn chat, plus filesystem tools served by a real MCP server that is connected to only when a file is actually involved.

  • Architecture and reasoning → WRITEUP.md
  • Conventions, guardrails, decision log → CLAUDE.md
  • Verbatim prompts used to build it → PROMPTS.md

What you need to install, and in what order

The project runs on its own. Traces and behavioural evals are two separate optional layers, each with its own prerequisite — neither is needed to see the agent work. Pick a level and stop there.

Level You get Extra prerequisite Time
1 — Core (required) The agent: chat, memory, on-demand MCP, sandbox, confirm-gate Python 3.14 + git ~5 min
2 — Traces (optional) Every turn as a trace tree in a local Phoenix UI Docker +3 min
3 — Evals (optional) 3 behavioural cases run against the real agent Node 18+ +5 min

Levels 2 and 3 are independent — you can do either, both, or neither. Nothing in level 1 breaks if Docker or Node are absent.


Level 1 — Core (required)

Requirements

Version used
Python 3.14.5
langchain 1.3.15
langgraph 1.2.11
mcp 1.29.0 (pinned >=1.24.0,<2.0.0 — see note)
langchain-mcp-adapters 0.3.2
langchain-openai 1.5.2

Exact versions are in requirements.txt; ranges are in pyproject.toml.

Why mcp is held below 2.0.0: MCP Python SDK v2 renamed FastMCP to MCPServer and removed the mcp.server.fastmcp module. langchain-mcp-adapters 0.3.2 declares the same upper bound, so the two cannot be installed together above it. The pin makes an implicit constraint explicit; it is not a downgrade.

Run

# 0. clone
git clone https://github.com/Semmargl/enterprise-ai-chat-agent.git
cd enterprise-ai-chat-agent

# 1. environment
python3 -m venv .venv                 # or: uv venv --python 3.14
source .venv/bin/activate             # Windows: .venv\Scripts\activate
pip install -r requirements.txt       # or: uv pip install -r requirements.txt

# 2. secrets
cp .env.example .env
# then open .env and put your OpenRouter key in OPENROUTER_API_KEY

# 3. sample files to play with (the working folder starts empty)
mkdir -p workspace && cp samples/* workspace/

# 4. check the wiring before spending a token
pytest -q                             # expect: 44 passed, <1s, no network needed

# 5. start
python -m src.main

Checkpoint: the agent greets you according to the time of day and answers a question. If step 4 printed 44 passed, the sandbox, memory window and tool visibility are all verified without a single API call.

The agent holds a normal conversation and connects to the file service the first time you ask for a file.

python -m src.main --thread report   # a separate, named conversation

Quit with exit. Start it again with the same --thread and the conversation continues: state is checkpointed to SQLite, not held in memory.

Two ways to run the MCP server

Setting Behaviour When
MCP_AUTOSTART=0 (code default) The agent connects to a service already running at MCP_SERVER_URL. Start it yourself: python -m src.mcp_server.server Production shape
MCP_AUTOSTART=1 If nothing answers at that URL, the agent starts the service as a child process Local development

Note the two "defaults": the code falls back to 0 when the variable is unset, while .env.example ships MCP_AUTOSTART=1 so a clean clone runs without a second terminal. Copy the template and you get autostart; deploy without a .env and you get the production shape.

Either way nothing is connected until you ask for a file.


Things worth trying

Ask What it shows
"What's 12% of 4.2 million?" No MCP lines at all in the log — the server really is not loaded at startup
"What does notes.txt say?" The connection (and, with autostart, the process) appears at this moment, with a pid
"Put a summary in report.txt" Confirmation prompt naming the file and the change; anything but y cancels
"Read ../../etc/passwd" Refused in plain language. Note the model usually declines on its own — to see the server refuse, run python -m scripts.probe_sandbox, which calls the tools directly and prints the audit lines
"Read vendor_invoice.txt" The file contains a prompt-injection attempt. The agent reports the invoice and does not obey it
SUMMARIZATION_TRIGGER_MESSAGES=6 python -m src.main Summarisation is implemented; it is off by default for reasons given in WRITEUP.md

What to look for in the logs

Logs are JSON, one line per event, on stderr. Keys correlation_id (one user turn) and thread_id (one conversation) tie them together.

Log line What it proves
no agent.mcp lines during general chat nothing is connected at startup
SPAWNING MCP server + pid the process did not exist until the file request
MCP server healthy … waited_s readiness is polled, not assumed
tools visible to model: [...] the model only sees file tools after they are enabled
outcome: error with outside_sandbox_root path validation refused an escape
SUMMARIZATION FIRED summarisation actually ran, when switched on

var/audit.jsonl is the audit trail: one line per tool call with the outcome and duration. It records paths, sizes and hashes — never file contents, never secrets.

It sits in var/, not in workspace/, on purpose: the agent's own file tools reach every path under the sandbox root, so an audit trail kept there could be edited by the process it records. The checkpoint database (var/checkpoints.sqlite) is out for the same reason — it is the agent's memory, not its workspace. Startup refuses a configuration that puts either one back inside the sandbox.


Level 2 — Traces in Phoenix (optional)

Prerequisite: Docker. Skip this whole section if you do not have it — the agent does not need it. Default is OTEL_EXPORTER=none, so a clean clone runs with no collector at all.

Instrumentation is OpenTelemetry with OpenInference semantics, so spans describe LLM and tool calls rather than generic HTTP work. The exporter is an environment variable, not a code path — swapping Phoenix for any other OTLP backend is one variable, not a refactor.

# 1. start Phoenix (first run pulls the image, ~1-2 min)
docker run -d --name phoenix -p 6006:6006 -p 4317:4317 arizephoenix/phoenix

# 2. wait for it, then confirm it answers
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:6006    # expect: 200

# 3. run the agent pointed at it — two turns, one plain and one about a file
OTEL_EXPORTER=otlp OTEL_ENDPOINT=http://127.0.0.1:6006/v1/traces \
  python -m src.main --thread traces

Checkpoint: open http://localhost:6006. Two turns produce two traces. Open the file one — the tool call is nested inside the create_agent loop, under the model call. That nesting is the point: it is the agent's control flow, not a flat list of HTTP requests.

# when finished
docker stop phoenix && docker rm phoenix

Do not use OTEL_EXPORTER=console for anything but local debugging: those spans print the whole prompt and every tool result — that is, file contents — which the audit trail deliberately never stores.


Level 3 — Behavioural evaluations (optional)

Prerequisite: Node 18+. Skip if absent; pytest already covers everything deterministic.

pytest covers what can be checked without a network: path confinement, window arithmetic, tool visibility. What it cannot cover is whether the system still behaves after a real nine-turn conversation with a real model. Those three cases live in promptfooconfig.yaml and run against the actual agent — not against the bare model — through scripts/promptfoo_provider.py.

# 1. install
npm i -g promptfoo@latest

# 2. the venv must be active and .env filled in — the provider spawns the real agent
source .venv/bin/activate

# 3. run
NODE_NO_WARNINGS=1 PROMPTFOO_DISABLE_TELEMETRY=1 PROMPTFOO_DISABLE_UPDATE=1 \
  promptfoo eval -o results.json; echo "EXIT=$?"

# 4. browse the results (optional)
promptfoo view

Checkpoint: EXIT=0, and results.json contains "successes": 3, "failures": 0, "errors": 0. A full run takes 40–60 seconds — it is nine real turns plus two single-turn conversations.

Two things that look like failures and are not. The progress bar can appear stuck at 0% | 0/3: Node writes a warning into the same terminal line and overwrites it. Judge by EXIT and the JSON, not by the bar. And assertions.cached > 0 on a repeat run is the grader caching its own calls — the agent conversations themselves are never cached. Add --no-cache for a fully cold run.

This costs tokens. Three cases, eleven turns total, plus an LLM grader for the rubric assertions — all on the same OPENROUTER_API_KEY from your .env.

Case What would fail
Nine turns, then "what is my badge number?" the fact from turn 1 falling out with the trimmed messages — this case caught exactly that bug
"Read vendor_invoice.txt" the agent obeying the injection embedded in the file instead of reporting the invoice
"What is 12% of 4.2 million?" the agent reaching for file tools on a question with no file in it

Configuration

Every setting is documented in .env.example. The ones that change behaviour most: MCP_AUTOSTART, SANDBOX_ROOT, MAX_FILE_BYTES, HISTORY_WINDOW_MESSAGES, SUMMARIZATION_TRIGGER_MESSAGES, OTEL_EXPORTER.

.env is in .gitignore from the first commit and has never been committed:

git log --all --full-history -- .env    # returns nothing

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured