finance-mcp-server
README.md
# finance-mcp-server
A standalone MCP (Model Context Protocol) server that exposes an H2
database as a set of tools an LLM can call: `list_tables`,
`describe_table`, `run_query`, `run_update`, `sample_rows`.
This is intentionally a separate Python process/repo from the Java
service — they only share the H2 database itself.
## Important: running alongside a Java service
Embedded H2 (`jdbc:h2:./data/mydb`) locks the database file for a single
process. If your Java service opens H2 that way, this Python server can't
connect to the same file at the same time. Two ways around that:
**Option A — H2 TCP server mode (recommended for this setup)**
Run H2 as a small server process; both your Java app and this MCP server
connect to it over TCP as clients:
```bash
java -cp h2-2.2.224.jar org.h2.tools.Server \
-tcp -tcpAllowOthers -ifNotExists
```
Then both sides use a URL like:
```
jdbc:h2:tcp://localhost:9092/./data/mydb
```
**Option B — `AUTO_SERVER=TRUE`**
Keep the embedded URL in your Java app but append `;AUTO_SERVER=TRUE`.
H2 will then also accept other connections to the same file.
This project defaults to Option A (see `.env.example`).
## Setup
```bash
# 1. Get the H2 driver jar (match your H2 version)
mkdir -p drivers
curl -L -o drivers/h2.jar \
https://repo1.maven.org/maven2/com/h2database/h2/2.2.224/h2-2.2.224.jar
# 2. Python env
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
# 3. Configure
cp .env.example .env
# edit .env if your JDBC URL / credentials differ
# 4. Fetch the H2 driver JAR **before** first startup
This is a required step — the server will fail to start (or fail to connect) without the H2 jar present.
```bash
scripts\fetch_h2_driver.sh
```
> ⚠️ **Known issue:** a missing or wrong H2 jar version was the main setup blocker. Make sure `fetch_h2_driver.sh` completes successfully and downloads the jar version your H2 database file was created with — a version mismatch between the driver jar and the `.mv.db` file format will cause connection failures. Confirm the jar lands wherever `server.py` expects it (check the script/config for the exact path) before moving on.
# 5. Start H2 in TCP server mode (separate terminal), then run:
python server.py
```
`jaydebeapi` starts an embedded JVM to load the H2 driver, so you need a
JDK/JRE installed and on `PATH` (or `JAVA_HOME` set) — this is separate
from whatever JVM your Java service runs under.
## Trying it with Claude Desktop
Add to your Claude Desktop MCP config
(`~/Library/Application Support/Claude/claude_desktop_config.json` on
macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows):
```json
{
"mcpServers": {
"h2-database": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["/absolute/path/to/h2-mcp-server/server.py"],
"env": {
"H2_JDBC_URL": "jdbc:h2:tcp://localhost:9092/./data/mydb",
"H2_USER": "sa",
"H2_PASSWORD": "",
"H2_ALLOW_WRITES": "false"
}
}
}
}
```
Restart Claude Desktop, then ask it something like "what tables are in
my H2 database?" — it will call `list_tables` / `describe_table` /
`run_query` as needed.
## Safety notes
- `run_query` only accepts `SELECT` statements.
- `run_update` (INSERT/UPDATE/DELETE/MERGE) is **disabled by default** —
set `H2_ALLOW_WRITES=true` to turn it on.
- Both tools block `DROP`, `TRUNCATE`, `ALTER`, `GRANT`, `REVOKE`,
`SHUTDOWN`, and user-management statements outright.
- This is demo-grade guarding (regex-based), not a substitute for a
real permissions model — don't point it at a production database
with real user data without tightening this further.
## Moving to AWS later
Swap the last line of `server.py`:
```python
mcp.run(transport="stdio")
```
for:
```python
mcp.run(transport="streamable-http")
```
and put it behind whatever orchestrator/API layer talks to your LLM
provider — stdio only works for local parent/child process setups.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues