Skip to main content
Glama
cledupe

CSV MCP Server

by cledupe
README.md
# CSV MCP Server

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](https://github.com/jlowin/fastmcp) and [Polars](https://github.com/pola-rs/polars) for efficient CSV processing with server-side filter expressions.

## Technologies

| Technology | Purpose |
|---|---|
| **Python 3.10+** | Runtime |
| **[FastMCP](https://github.com/jlowin/fastmcp)** | MCP server framework |
| **[Polars](https://github.com/pola-rs/polars)** | High-performance CSV loading and filtering |
| **[Docker](https://www.docker.com/)** | Containerized deployment |
| **[pytest](https://docs.pytest.org/)** | Testing framework |

## Available Tools

| 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 |

## Quick Start

### Without Docker

1. **Install dependencies:**

   ```bash
   pip install mcp polars
   ```

2. **Place your CSV files** in the `./data/` directory (or set `CSV_DIR` to a custom path).

3. **Run the server:**

   ```bash
   python server.py
   ```

   The server starts in `stdio` mode by default, which is what AI clients like Claude Desktop and Cursor expect.

### With Docker

1. **Place your CSV files** in the `./data/` directory.

2. **Build and start the container:**

   ```bash
   docker compose up -d
   ```

   The server runs in HTTP mode on `http://localhost:8000/mcp`.

3. **Verify connectivity:**

   ```bash
   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}'
   ```

## Configuration

### Environment Variables

| 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 |

## AI Client Integration

### OpenCode

Add to your `opencode.json`:

**Local (stdio):**

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "csv-mcp": {
      "type": "local",
      "command": ["python", "server.py"],
      "environment": {
        "CSV_DIR": "./data"
      },
      "enabled": true
    }
  }
}
```

**Docker (HTTP):**

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "csv-mcp": {
      "type": "remote",
      "url": "http://localhost:8000/mcp",
      "enabled": true
    }
  }
}
```

### Claude Desktop / Cursor

For `stdio` mode:

```json
{
  "mcpServers": {
    "csv-mcp": {
      "command": "python",
      "args": ["/path/to/server.py"],
      "env": {
        "CSV_DIR": "/path/to/data"
      }
    }
  }
}
```

For Docker (HTTP):

```json
{
  "mcpServers": {
    "csv-mcp": {
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

## Usage Examples

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 |

## Testing

```bash
# 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
```

## Security

- **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