MCP tools can do useful work before you connect an AI assistant. You can discover a server's tools, ask one to create a file and read the result back through the protocol. No chatbot subscription is needed for that experiment.
This is a practical way to understand what you are about to give an assistant access to. A server described as a "filesystem connection" may expose writing, editing and moving tools as well as reading. Seeing those tools and their inputs is more informative than trusting the connection's friendly name.
Here you will use the actual MCP Inspector and the reference filesystem server to create hello.txt inside a disposable folder. You will then try reading a separate harmless file outside that folder and observe the denial. The result is a real file and a tool-response record, not a simulated agent conversation.
The finished result
The executed local run discovered both read_text_file and write_file, created a 39-byte UTF-8 file and read back this exact content:
MCP created this file without a model.
The file ends with a newline. A read request for our own separate outside.txt fixture returned a tool error. It did not return that fixture's contents. Those are observations from the pinned tools and this configuration, not a certification that every filesystem server or MCP host has the same boundary.
What you need
The recorded run used Node.js 24.22.1, MCP Inspector 2.13.0 and @modelcontextprotocol/server-filesystem 2.1.0 on Linux. Inspector's current documentation requires Node 22.19.0 or newer. The commands below use Bash, suitable for Linux, macOS or WSL. They are not PowerShell syntax.
Package installation needs internet access. After installation the calls in this lesson use local standard input/output transport. No API key, cloud account, model call, private repository or payment is involved. The optional replay program later also needs Python 3.
Use an empty disposable folder. The reference server exposes write-capable tools inside its configured directories, so do not substitute your home directory or a folder of personal documents.
1. Install two tools in one project folder
mkdir mcp-folder-demo
cd mcp-folder-demo
npm init -y
npm install --save-exact @modelcontextprotocol/inspector@2.13.0 @modelcontextprotocol/server-filesystem@2.1.0
mkdir allowed
lab_allowed=$(node -p 'require("node:path").resolve("allowed")')
lab_outside=$(node -p 'require("node:path").resolve("outside.txt")')
node -e 'require("node:fs").writeFileSync("outside.txt", "OUTSIDE_CANARY\n")'
allowed is the only directory passed to the server. The outside file belongs to this experiment too; it contains no secret. Testing with a harmless canary lets you inspect a denied request without probing a real private file.
The installation creates a package lock. Keep it if you want to reproduce the exact dependency resolution rather than merely the two top-level version numbers.
2. Discover the tool surface
./node_modules/.bin/mcp-inspector --cli \
./node_modules/.bin/mcp-server-filesystem "$lab_allowed" \
--method tools/list --format json
Look inside result.tools. The recorded tool list included read_text_file, write_file, edit_file, move_file and list_allowed_directories, among others. A returned schema describes the arguments a tool accepts. It does not mean that you have approved every future call to that tool.
Now inspect the effective folder scope:
./node_modules/.bin/mcp-inspector --cli \
./node_modules/.bin/mcp-server-filesystem "$lab_allowed" \
--method tools/call --tool-name list_allowed_directories --format json
Confirm that the returned directory is the absolute allowed folder you created. Stop and inspect your configuration if it is broader than expected. Do not infer scope solely from the command you intended to run.
3. Create a file through MCP, then read it back
./node_modules/.bin/mcp-inspector --cli \
./node_modules/.bin/mcp-server-filesystem "$lab_allowed" \
--method tools/call --tool-name write_file \
--tool-arg "path=$lab_allowed/hello.txt" \
--tool-arg 'content="MCP created this file without a model.\n"' \
--format json
./node_modules/.bin/mcp-inspector --cli \
./node_modules/.bin/mcp-server-filesystem "$lab_allowed" \
--method tools/call --tool-name read_text_file \
--tool-arg "path=$lab_allowed/hello.txt" --format json
Inspector parses the quoted content argument as a JSON string, including its newline. The read response should contain the same sentence. You can also open allowed/hello.txt in your ordinary text editor. This independent filesystem check confirms an effect, rather than relying only on a success message.
We authorized this one write directly through the CLI. No model selected or approved it. Connecting the server to a model later adds a decision-making layer; the filesystem tools already have their own execution capability.
4. Observe a failed request and repair the path
./node_modules/.bin/mcp-inspector --cli \
./node_modules/.bin/mcp-server-filesystem "$lab_allowed" \
--method tools/call --tool-name read_text_file \
--tool-arg "path=$lab_outside" --format json
For the pinned Inspector, a tool response with isError: true produces exit code 5. In our run, the outside-folder read was denied. A nonzero exit is the expected result for this step, not a reason to broaden the server's directories.
Repair the request by pointing it back to $lab_allowed/hello.txt and rerun the previous read command. It should succeed. The repair changes the mistaken requested path while keeping the same narrow folder scope.
If a script uses the result, inspect the exit status and error payload. A JSON response is not automatically a successful tool result. The Inspector's documented error classes distinguish tool errors from authentication and connection failures.
What this teaches about connecting an assistant
Review three things separately: which tools the server advertises, what each tool can affect, and which calls your host permits. A readOnlyHint is descriptive metadata on a particular tool, not a switch that turns the whole filesystem server into a read-only connection. A server process also runs with the operating-system permissions of the account that launched it. This exercise does not create an operating-system sandbox.
Protocol versions matter. The current filesystem documentation distinguishes command-line directory scope on 2026-07-28 connections from the deprecated Roots behavior of 2025-era clients, which can replace the directory list. Check the negotiated behavior and effective directory list in the host you actually use. This CLI exercise does not establish how a different host will configure the same server.
The reference implementation has had security fixes, so review its current release notes and advisories before adopting it. The four observations here do not test symlink races, hard links, every path form or malicious server code. Keep your first connection disposable and inspect permissions before using real data.
Optional: repeat the complete probe automatically
With the tools already installed in this project, add their executable folder to this shell's PATH:
export PATH="$PWD/node_modules/.bin:$PATH"
python mcp_folder_demo.py
Save the complete program below as mcp_folder_demo.py. It creates a separate temporary directory, exercises the real tools and removes that temporary directory when finished. The hello.txt from the manual steps stays in your project folder.
"""Run after installing Inspector 2.13.0 and filesystem server 2.1.0 on PATH."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
inspector = shutil.which("mcp-inspector")
server = shutil.which("mcp-server-filesystem")
if not inspector or not server:
raise SystemExit("Install the pinned npm tools and add their .bin folder to PATH")
with tempfile.TemporaryDirectory(prefix="mcp-folder-") as directory:
root = Path(directory)
allowed = root / "allowed"
allowed.mkdir()
outside = root / "outside.txt"
outside.write_text("OUTSIDE_CANARY\n", encoding="utf-8")
receipts = []
def invoke(method, tool=None, arguments=None, expected_exit=0):
command = [inspector, "--cli", server, str(allowed),
"--method", method, "--format", "json"]
if tool:
command += ["--tool-name", tool, "--tool-args-json", json.dumps(arguments or {})]
result = subprocess.run(command, capture_output=True, text=True, timeout=20)
receipts.append({"method": method, "tool": tool, "exit": result.returncode,
"stdout": result.stdout, "stderr": result.stderr})
assert result.returncode == expected_exit, result.stderr
return json.loads(result.stdout)["result"]
tools = invoke("tools/list")["tools"]
names = {tool["name"] for tool in tools}
assert {"write_file", "read_text_file", "list_allowed_directories"} <= names
print("DISCOVERY read_text_file=YES write_file=YES")
scope = invoke("tools/call", "list_allowed_directories")
assert str(allowed) in json.dumps(scope)
print("SCOPE allowed_folder=CONFIRMED")
target = allowed / "hello.txt"
expected = "MCP created this file without a model.\n"
invoke("tools/call", "write_file", {"path": str(target), "content": expected})
assert target.read_text() == expected
print("WRITE file=hello.txt bytes=" + str(len(expected.encode('utf-8'))))
readback = invoke("tools/call", "read_text_file", {"path": str(target)})
assert any(block.get("text") == expected for block in readback["content"])
print("READBACK content=MATCH")
denied = invoke("tools/call", "read_text_file", {"path": str(outside)}, expected_exit=5)
assert denied.get("isError") is True
assert "OUTSIDE_CANARY" not in json.dumps(denied)
print("OUTSIDE_FOLDER result=DENIED")
assert outside.read_text() == "OUTSIDE_CANARY\n"
print("CHECK PASS: real MCP discovery, write, readback and denied read")
Complete observed stdout:
DISCOVERY read_text_file=YES write_file=YES
SCOPE allowed_folder=CONFIRMED
WRITE file=hello.txt bytes=39
READBACK content=MATCH
OUTSIDE_FOLDER result=DENIED
CHECK PASS: real MCP discovery, write, readback and denied read
The server writes startup diagnostics to stderr, and the denied request has an error diagnostic. The program captures and checks each call's exit status; the raw responses remain in its in-memory receipts list during execution. It does not silently treat an error as success or persist a security audit to a service.
Sources and limits
This tutorial was executed on October 31, 2026 using the pinned packages. MCP Inspector documentation describes its three clients; the CLI guide documents arguments and exit codes; the filesystem server README describes tools and directory controls. These sources establish the mechanisms, not reader demand or performance improvements.
AI assisted the writing and local tool execution. No AI host, paid model, private data, remote server, customer workflow or independent beginner trial was involved. The useful takeaway is concrete: you can inspect and exercise a real MCP tool before giving an assistant access to it, and you can verify the resulting file yourself.