A Python MCP (Model Context Protocol) server that enables AI assistants to answer natural language questions about company processes and operational data stored in CSV files. Built with FastMCP and Polars for efficient CSV processing with server-side filter expressions.
| Technology | Purpose |
|---|---|
| Python 3.10+ | Runtime |
| FastMCP | MCP server framework |
| Polars | High-performance CSV loading and filtering |
| Docker | Containerized deployment |
| pytest | Testing framework |
| Tool | Description |
|---|---|
list_csv_files |
Lists all CSV files in the configured directory |
get_csv_schema |
Shows column names, data types, and sample rows for a CSV file |
ask_csv_question |
Queries a CSV file using a Polars filter expression |
-
Install dependencies:
pip install mcp polars
-
Place your CSV files in the
./data/directory (or setCSV_DIRto a custom path). -
Run the server:
python server.py
The server starts in
stdiomode by default, which is what AI clients like Claude Desktop and Cursor expect.
-
Place your CSV files in the
./data/directory. -
Build and start the container:
docker compose up -d
The server runs in HTTP mode on
http://localhost:8000/mcp. -
Verify connectivity:
curl -X POST http://localhost:8000/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}},"id":1}'
| Variable | Default | Description |
|---|---|---|
CSV_DIR |
./data |
Path to the directory containing CSV files |
MCP_TRANSPORT |
stdio |
Transport mode: stdio or http |
FASTMCP_HOST |
127.0.0.1 |
Host address for HTTP mode |
FASTMCP_PORT |
8000 |
Port for HTTP mode |
Add to your opencode.json:
Local (stdio):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"csv-mcp": {
"type": "local",
"command": ["python", "server.py"],
"environment": {
"CSV_DIR": "./data"
},
"enabled": true
}
}
}Docker (HTTP):
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"csv-mcp": {
"type": "remote",
"url": "http://localhost:8000/mcp",
"enabled": true
}
}
}For stdio mode:
{
"mcpServers": {
"csv-mcp": {
"command": "python",
"args": ["/path/to/server.py"],
"env": {
"CSV_DIR": "/path/to/data"
}
}
}
}For Docker (HTTP):
{
"mcpServers": {
"csv-mcp": {
"url": "http://localhost:8000/mcp"
}
}
}Once connected, ask your AI assistant questions like:
- "List all available CSV files"
- "Show the schema of processes.csv"
- "Find all rows where status equals 'active' in processes.csv"
The ask_csv_question tool accepts Polars filter expressions:
| Expression | Description |
|---|---|
pl.col("status") == "active" |
Filter by exact match |
pl.col("prazo") > 10 |
Filter by numeric comparison |
pl.col("processo").str.contains("aprov") |
Filter by substring match |
# Run all tests
python -m pytest tests/ -v
# Run with coverage
COVERAGE_FILE=/tmp/.coverage python -m pytest tests/ --cov=server --cov-report=term-missing- Path traversal protection: All file paths are resolved and validated to stay within
CSV_DIR - Expression sanitization: Filter expressions are checked against dangerous patterns (
import,exec,eval, etc.) before evaluation