# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

**Setup:**
```bash
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env        # fill in credentials
cp .mcp.example.json .mcp.json
```

**Run the server (stdio, default):**
```bash
python src/mcp_server.py
```

**Run over SSE (for mcp-inspector):**
```bash
python src/mcp_server.py --transport sse --host 127.0.0.1 --port 55392
# Then attach: npx -y @modelcontextprotocol/inspector --transport sse --server-url http://127.0.0.1:55392/sse
```

**Debug tools locally (no running server needed):**
```bash
python client_debug.py   # edit test_cases list inside the file first
```

**Lint / format:**
```bash
black src/           # line-length 100
flake8 src/
mypy src/
```

**Tests:**
```bash
pytest               # runs tests/ directory in async mode
```

## Architecture

The server is a single-process MCP server (`src/mcp_server.py`) that dispatches all tool calls through two decorated handlers: `list_tools()` and `call_tool()`. Both transport modes (stdio and SSE/HTTP via uvicorn) are supported from the same entry point via `--transport`.

```
src/
├── mcp_server.py                # Entry point; all Tool definitions and call_tool dispatch live here
├── tools/                       # Thin wrappers: call client methods, catch exceptions, return {status, ...}
│   ├── neo4j_tools.py
│   ├── snowflake_tools.py
│   ├── mysql_tools.py
│   ├── aws_tools.py
│   └── sound_recording_tools.py # Domain tools — currently only get_delivery_history (queries Snowflake)
├── db/                          # Connection managers (lazy connect on first use)
│   ├── neo4j_client.py
│   ├── snowflake_client.py      # Supports key-pair (SNOWFLAKE_KEY as base64 DER) or password auth
│   └── mysql_client.py
└── aws/                         # boto3 wrappers
    ├── lambda_client.py
    ├── sfn_client.py
    └── s3_client.py
```

**Adding a new tool** requires three changes, all in `src/mcp_server.py`:
1. Add a `Tool(...)` entry in `list_tools()`
2. Add an `elif name == "..."` branch in `call_tool()`
3. Implement the function in the appropriate `src/tools/` module

All tool functions must return `{"status": "success", ...}` or `{"status": "error", "message": str(e)}` — the server serializes the return value directly as JSON to the MCP client.

## Environment variables

All credentials come from `.env` (loaded at startup; `.env` is gitignored, `.env.example` is tracked):

| Service | Key variables |
|---|---|
| Neo4j | `NEO4J_URI`, `NEO4J_USERNAME`, `NEO4J_PASSWORD` |
| Snowflake | `SNOWFLAKE_ACCOUNT`, `SNOWFLAKE_USER`, `SNOWFLAKE_KEY` (base64 DER) or `SNOWFLAKE_PASSWORD`, `SNOWFLAKE_ROLE`, `SNOWFLAKE_DATABASE`, `SNOWFLAKE_WAREHOUSE`, `SNOWFLAKE_SCHEMA` |
| MySQL | `MYSQL_HOST`, `MYSQL_USER`, `MYSQL_PASSWORD` |
| AWS | `AWS_REGION` (default `us-east-1`), standard credential chain |
| Transport | `MCP_TRANSPORT`, `MCP_HOST`, `MCP_PORT`, `MCP_SSE_PATH`, `MCP_MESSAGE_PATH` |

## MCP client config

`.mcp.json` (gitignored) registers this server with Claude Code. Template is `.mcp.example.json`. Use the project-local `.mcp.json` rather than a global config so paths stay portable.
