maha-mcp-bridge
OfficialREADME.md
# maha-mcp-bridge
Zero-trust local MCP bridge for the [Maha Provenance Standard](https://www.mahastrategies.com/mps) API. Your source data stays on your machine; only sanitized context ever reaches the API.
## Install
```sh
npm install -g @mahastrategies/maha-mcp-bridge
```
## Quick start
```sh
maha login # paste your mhaic_ credential (input hidden), verified live
maha status # token validity + remaining audit credits
maha logout # remove the stored credential
```
Credentials are verified against the live backend before being stored in a user-only file (`0600`), like the AWS and gcloud CLIs. Set `MAHA_MPS_CREDENTIAL` instead for CI and containers — it always takes precedence and nothing is written to disk.
`MAHA_MPS_API_URL` overrides the backend origin (https required, localhost exempt) for staging and local development.
## The MCP bridge
```sh
maha serve # stdio MCP server; requires `maha login` first
```
`maha serve` refuses to start without a valid credential — an unauthenticated host exposes no tools. Register it with any MCP client, e.g. Claude Code:
```json
{ "mcpServers": { "maha": { "command": "maha", "args": ["serve"] } } }
```
### Tools
| Tool | What it does |
|---|---|
| `get_schema_definition` | Tables and columns of a configured local database, redacted. |
| `query_internal_db` | One read-only SQL statement; rows capped, cells truncated, results redacted locally. |
| `mps_audit_passage` | Redacts a passage locally, then submits the sanitized text for an MPS claim-level audit. |
| `mps_local_audit_summary` | Aggregate counts from the local hash-chained ledger. No payloads. |
### Two-tier PII redaction
Before any row or schema reaches the agent it passes through two redaction tiers, and both are counted separately in the ledger:
1. **Regex tier** (always on, fast): emails, SSNs, payment cards, phones, access/bearer tokens, secret-named fields, plus any custom patterns.
2. **Contextual tier** (local ONNX model via [`@huggingface/transformers`](https://github.com/huggingface/transformers.js)): a Named Entity Recognition model (`Xenova/bert-base-NER`) catches free-text PII the regexes miss — `PER` (people), `LOC` (locations), `ORG` (organizations), `MISC`. It runs **entirely on your machine** on the native `onnxruntime-node` backend; the model downloads once to `~/.cache/maha-mcp-bridge/` and never phones home afterward.
The model loads lazily so it never blocks the MCP handshake, and if it can't load (offline, disk, etc.) the bridge degrades to regex-only rather than failing. Disable it with `"pii": { "contextual": { "enabled": false } }` or `MAHA_MPS_DISABLE_NER=1`. Redaction is best-effort, not a guarantee that every entity is caught.
> **The contextual (NER) tier works out of the box.** `onnxruntime-node` ships prebuilt native binaries for macOS, Linux, and Windows (x64 and arm64) inside the npm package, so a plain `npm install -g` runs the full `regex + NER` pipeline with no extra flags. (Recent npm prints an `npm warn allow-scripts` about the package's `postinstall`; on the supported platforms that script isn't needed — the binary is already bundled.)
>
> You never have to guess which tiers are live: **`maha status` reports the active redaction tier** — `Redaction regex + NER`, `regex-only (NER unavailable)`, or `regex-only (NER disabled)` — and `maha serve` prints the same on startup. If your platform has no prebuilt binary, NER is skipped and the bridge degrades to regex-only (safely, not fatally). Only then do you need to rebuild the backend from source:
>
> ```sh
> npm install -g --allow-scripts=onnxruntime-node @mahastrategies/maha-mcp-bridge
> ```
### Read-only, enforced twice
A statement gate rejects anything that isn't a single `SELECT`/`WITH`/`SHOW`/`EXPLAIN`/`DESCRIBE`, and every query then runs inside a server-side `READ ONLY` transaction that is always rolled back — so a data-modifying CTE that slips past the gate still dies in the database engine.
### Configuration
`~/.config/maha-mcp-bridge/config.json`:
```json
{
"databases": [
{ "name": "appdb", "kind": "postgres", "urlEnv": "APPDB_URL" },
{ "name": "legacy", "kind": "mysql", "urlEnv": "LEGACY_DB_URL" }
],
"pii": { "customPatterns": [{ "name": "employee_id", "source": "EMP-\\d{6}" }] }
}
```
Connection URLs come from environment variables (`urlEnv`); inline `url` values are rejected if they embed a password. Use a database role with read-only grants as a third layer.
Every tool invocation is recorded in a local, hash-chained SQLite ledger (`0600`) holding only hashes and redaction counts — never passage text, SQL, or rows.
## Configuration (contextual model)
```json
{
"pii": {
"contextual": { "enabled": true, "model": "Xenova/bert-base-NER", "minScore": 0.5 }
}
}
```
## Mount a book
Mount a purchased book as a local MCP server so your agent can navigate it by section instead of scrolling a wall of text:
```sh
maha book mount the-imagined-life # uses your MHAIC token (~/.maha/config.json or MHAIC_TOKEN)
```
On first use it prompts for your `mhaic_` token (input hidden), verifies it, and stores it `0600`. Register the mounted book with any MCP client:
```json
{ "mcpServers": { "maha-book-the-imagined-life": { "command": "maha", "args": ["book", "mount", "the-imagined-life"] } } }
```
`maha book mount` prints this exact snippet on a successful mount. The book is fetched once (entitlement-checked) and served from memory — the tools are:
| Tool | What it does |
|---|---|
| `list_chapters` | The book's outline: sections and per-section chunk counts. |
| `read_section` | One section's text, by heading (partial match allowed) or numeric index. |
| `search_concepts` | Ranked plain-text search across the book's chunks. |
The full text of each book is free to read on the web; this structured, agent-queryable form is the paid endpoint. If your token isn't entitled, `maha book mount` prints the purchase URL instead of starting.
## Security notes
- The contextual model runs locally; database rows are never sent anywhere for inference.
- `npm audit` is clean (0 vulnerabilities). Inference uses the maintained [`@huggingface/transformers`](https://github.com/huggingface/transformers.js) on the native `onnxruntime-node` backend — no `onnxruntime-web`/`protobufjs`. `adm-zip` (pulled by `onnxruntime-node` to unpack its native binary) is pinned to a patched `^0.6.0` via a package override.
## Why open source
Security teams should be able to audit exactly what leaves the building. The bridge is MIT-licensed; the cloud control plane (billing, idempotent credit ledger, audit engine) is the paid service behind it.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues