test_mcp.py•9.04 kB
#!/usr/bin/env python
import unittest
import tempfile
import os
from pathlib import Path
from fastapi.testclient import TestClient
from mcp_filesystem_tools import app
# ---------------------------------------------------------------------------
# Test class for File System MCP server
# ---------------------------------------------------------------------------
class TestFileSystemMCP(unittest.TestCase):
def setUp(self):
# Create a new TestClient for each test
self.client = TestClient(app)
# Create a temporary directory for testing
self.temp_dir = tempfile.mkdtemp()
self.test_file_path = os.path.join(self.temp_dir, "test.txt")
self.test_content = "Hello, this is a test file!\nSecond line."
# Create a test file
with open(self.test_file_path, "w") as f:
f.write(self.test_content)
def tearDown(self):
# Clean up temporary files
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
# -----------------------------------------------------------------------
# Basic health/liveness
# -----------------------------------------------------------------------
def test_health(self):
r = self.client.get("/health")
self.assertEqual(r.status_code, 200)
response = r.json()
self.assertEqual(response["status"], "ok")
self.assertEqual(response["service"], "File System MCP Server")
# -----------------------------------------------------------------------
# Tool discovery
# -----------------------------------------------------------------------
def test_list_tools_success(self):
r = self.client.get("/list_tools")
self.assertEqual(r.status_code, 200)
tools = {tool["name"] for tool in r.json()}
expected_tools = {
"list_directory",
"read_file",
"write_file",
"get_file_info",
"create_directory",
"delete_file",
}
self.assertTrue(expected_tools.issubset(tools))
# -----------------------------------------------------------------------
# Tool invocation - list_directory
# -----------------------------------------------------------------------
def test_list_directory(self):
r = self.client.post(
"/invoke_tool",
json={"tool": "list_directory", "inputs": {"path": self.temp_dir}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["path"], os.path.abspath(self.temp_dir))
self.assertIn("items", response)
self.assertIn("total_count", response)
# Check if our test file is in the list
file_names = [item["name"] for item in response["items"]]
self.assertIn("test.txt", file_names)
def test_list_directory_default_path(self):
r = self.client.post(
"/invoke_tool",
json={"tool": "list_directory", "inputs": {}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertIn("items", response)
self.assertIn("total_count", response)
def test_list_directory_nonexistent(self):
r = self.client.post(
"/invoke_tool",
json={"tool": "list_directory", "inputs": {"path": "/nonexistent/path"}},
)
self.assertEqual(r.status_code, 500)
# -----------------------------------------------------------------------
# Tool invocation - read_file
# -----------------------------------------------------------------------
def test_read_file(self):
r = self.client.post(
"/invoke_tool",
json={"tool": "read_file", "inputs": {"file_path": self.test_file_path}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["file_path"], os.path.abspath(self.test_file_path))
self.assertEqual(response["content"], self.test_content)
self.assertEqual(response["encoding"], "utf-8")
self.assertEqual(response["size"], len(self.test_content))
def test_read_file_nonexistent(self):
r = self.client.post(
"/invoke_tool",
json={
"tool": "read_file",
"inputs": {"file_path": "/nonexistent/file.txt"},
},
)
self.assertEqual(r.status_code, 500)
# -----------------------------------------------------------------------
# Tool invocation - write_file
# -----------------------------------------------------------------------
def test_write_file(self):
new_file_path = os.path.join(self.temp_dir, "new_file.txt")
new_content = "This is a new file created by MCP!"
r = self.client.post(
"/invoke_tool",
json={
"tool": "write_file",
"inputs": {"file_path": new_file_path, "content": new_content},
},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["file_path"], os.path.abspath(new_file_path))
self.assertEqual(response["message"], "File written successfully")
# Verify file was actually created
self.assertTrue(os.path.exists(new_file_path))
with open(new_file_path, "r") as f:
self.assertEqual(f.read(), new_content)
# -----------------------------------------------------------------------
# Tool invocation - get_file_info
# -----------------------------------------------------------------------
def test_get_file_info(self):
r = self.client.post(
"/invoke_tool",
json={"tool": "get_file_info", "inputs": {"path": self.test_file_path}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["path"], os.path.abspath(self.test_file_path))
self.assertEqual(response["name"], "test.txt")
self.assertEqual(response["type"], "file")
self.assertEqual(response["extension"], ".txt")
self.assertIn("size", response)
self.assertIn("created", response)
self.assertIn("modified", response)
self.assertIn("permissions", response)
def test_get_directory_info(self):
r = self.client.post(
"/invoke_tool",
json={"tool": "get_file_info", "inputs": {"path": self.temp_dir}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["path"], os.path.abspath(self.temp_dir))
self.assertEqual(response["type"], "directory")
self.assertNotIn("extension", response)
# -----------------------------------------------------------------------
# Tool invocation - create_directory
# -----------------------------------------------------------------------
def test_create_directory(self):
new_dir_path = os.path.join(self.temp_dir, "new_directory")
r = self.client.post(
"/invoke_tool",
json={"tool": "create_directory", "inputs": {"dir_path": new_dir_path}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["dir_path"], os.path.abspath(new_dir_path))
self.assertEqual(response["message"], "Directory created successfully")
# Verify directory was actually created
self.assertTrue(os.path.exists(new_dir_path))
self.assertTrue(os.path.isdir(new_dir_path))
# -----------------------------------------------------------------------
# Tool invocation - delete_file
# -----------------------------------------------------------------------
def test_delete_file(self):
# Create a file to delete
delete_file_path = os.path.join(self.temp_dir, "to_delete.txt")
with open(delete_file_path, "w") as f:
f.write("This file will be deleted")
r = self.client.post(
"/invoke_tool",
json={"tool": "delete_file", "inputs": {"path": delete_file_path}},
)
self.assertEqual(r.status_code, 200)
response = r.json()["output"]
self.assertEqual(response["path"], os.path.abspath(delete_file_path))
self.assertEqual(response["message"], "File deleted successfully")
# Verify file was actually deleted
self.assertFalse(os.path.exists(delete_file_path))
# -----------------------------------------------------------------------
# Negative‑path checks
# -----------------------------------------------------------------------
def test_invoke_unknown_tool(self):
r = self.client.post("/invoke_tool", json={"tool": "nope", "inputs": {}})
self.assertEqual(r.status_code, 404)
# If this file is run directly, run unittest main
if __name__ == "__main__":
unittest.main()