claims-mcp-server
README.md
# claims-mcp-server
A secure, read-only Model Context Protocol (MCP) server over a synthetic health-insurance claims SQLite database.
## What and Why
Meridian Health TPA processes about 3,000 health insurance claims a day and internal operations teams want AI assistants to query claims data. Under strict security and compliance rules, **no AI agent is ever granted direct database access**, and every access requires an immutable audit trail. This repository provides the controlled layer in between: a read-only MCP server exposing five parameterized tools with authentication, per-tool authorization, rate limiting, untrusted text sanitization, and fail-closed audit logging.
## Quickstart
Get running in three simple commands:
```bash
# 1. Install dependencies
uv sync
# 2. Seed synthetic database and generate an API key
uv run python scripts/seed_db.py --out data/claims.db && uv run python scripts/make_key.py --id analyst-1 --tools all
# 3. Start the server over HTTP
uv run python -m claims_mcp --transport http
```
To run the demo client in a separate terminal:
```bash
uv run python scripts/demo_client.py --key <PLAINTEXT_KEY_FROM_STEP_2>
```
Alternatively, run locally with stdio (for local inspectors and dev):
```bash
uv run python -m claims_mcp --transport stdio
```
## Architecture
```
MCP Client (AI agent / demo_client.py / inspector)
| stdio or streamable HTTP (127.0.0.1, Bearer key)
v
+-----------------------------------------------------------+
| server.py (MCPServer, 5 tools, handlers are plain `def`) |
| |
| 1 authenticate -> key_id (security.py) |
| 2 rate limit per key_id (security.py) |
| 3 authorize tool for key_id (security.py) |
| 4 validate inputs (models.py) |
| 5 open read-only connection (db.py) one per call |
| 6 run fixed parameterized SQL (queries.py) |
| 7 build output, sanitize text (models.py, security.py) |
| 8 write audit line, FAIL CLOSED (audit.py) |
| 9 return result |
+-----------------------------------------------------------+
| |
v v
claims.db (read-only) audit.jsonl (append-only)
```
## Tools Exposed
1. `get_claim(claim_id)`: Fetches full claim record joined with provider network status and member plan.
2. `list_member_claims(member_id, status=None, limit=20, offset=0)`: Paginated claim history ordered newest first.
3. `get_coverage_rule(plan_id, procedure_code)`: Policy coverage rules, prior authorization flag, and fee limits.
4. `get_member_ytd_summary(member_id, year)`: Aggregations by status, deductible, annual limit, and remaining limit.
5. `get_claim_notes(claim_id, limit=10)`: Clinical and administrative notes, sanitized and flagged `untrusted: true`.
## Security Summary
- **Read-Only Database Layer (SPEC S1):** Triple defense using SQLite URI `mode=ro`, `PRAGMA query_only = ON`, and a strict SQLite Authorizer that blocks all writes, mutations, table creation, and PRAGMA modifications.
- **Strict Parameterization (SPEC S2, S3):** 100% parameterized SQL with `?` placeholders. Zero string interpolation, verified by an automated AST scanner in CI.
- **Hashed Authentication (SPEC S4):** Static bearer keys hashed at rest with SHA-256 in `keys.json` and verified with constant-time comparison (`hmac.compare_digest`).
- **Tool Authorization & Rate Limiting (SPEC S5, S6):** Per-key allowlists and fixed-window rate limiting.
- **Untrusted Text Sanitization (SPEC S7):** Strips control characters, zero-width spaces, and bidi override tags; caps text at 1,000 characters; and marks output `untrusted: true`.
- **Fail-Closed Audit Logging (SPEC S9, S10):** Append-only JSONL log with zero payload or sensitive note leakage. If writing to the audit log fails, the request fails closed and returns no data.
- **Intercepted Validation (SPEC S13):** Eliminates raw input echoing on validation errors while maintaining complete typed JSON schemas for clients.
For detailed security mitigations and STRIDE threat analysis, read [THREAT_MODEL.md](THREAT_MODEL.md).
## Known Limitations
- **Adversarial Text Influence:** A model reading `get_claim_notes` can still be influenced by hostile text. Labeling data as untrusted is not enforcement; the real mitigations are read-only isolation, absence of write tools, and human-in-the-loop workflows in Project B.
- **Localhost HTTP Only:** Plaintext HTTP (no TLS) intended for localhost or container-mesh deployment behind an external TLS reverse proxy.
- **Single Process In-Memory Rate Limiting:** Rate limits are stored in memory and reset if the process restarts.
- **Manual Key Rotation:** API keys are rotated by updating `keys.json`.
- **Audit File Integrity:** The append-only JSONL log is not cryptographically signed or tamper-evident.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues