sh-mcp/servers/sh-mcp-finance/README.md
Adam Moussa 9bf85aef29 Add runnable sh-mcp-ops and sh-mcp-finance servers
Two thin composition-root servers over the shared transport (design.md §3):
- ops: internal-data, knowledge-base, google-maps, gmail, calendar, tasks,
  reminders. finance: qbo, payments (audited + redacted on egress).
- config from env only (no hardcoded ids/issuer/tables); SH_MCP_ENV selects
  LocalAuthProvider + dev clients (local) vs CognitoAuthProvider + real stubs
  (aws). Finance applies the 15-min finance-token TTL ceiling (design.md §2.5).
- index.ts is the only place .listen() is called; a Lambda handler placeholder
  is exported but not depended on.
- synth-only CDK stubs (no real IAM/Cognito/WAF) so 'cdk synth' has a valid app
  (build-plan §6); READMEs document local run, dev tokens, curl, MCP Inspector.
2026-06-26 12:48:26 -04:00

81 lines
2.6 KiB
Markdown

# sh-mcp-finance
Finance-tier Sea Haven MCP server. Exposes the **finance** tool registry
(qbo `search_vendors`, payments `lookup_payment_by_*` — see `docs/design.md §3`)
over the same two interfaces as `sh-mcp-ops` (MCP Streamable HTTP + OpenAPI 3.1),
through the same shared dispatch path.
Finance is **sensitive, read-only, and fully audited**: every tool call emits a
structured audit record and the response is redacted on egress (bank account /
routing / card / SSN / tax-id masked) before it leaves the server
(`docs/design.md §2.5, §7.3`).
## Run locally (no AWS, no Cognito)
```bash
npm install
npm run build
SH_MCP_ENV=local PORT=8082 npm run start -w @sh-mcp/server-finance
# or: SH_MCP_ENV=local npm run dev -w @sh-mcp/server-finance
```
### Endpoints
Identical shape to `sh-mcp-ops`: `GET /healthz`, `GET /openapi.json` (both
unauthenticated), `POST /mcp`, and `POST /tools/:name` (both authenticated).
### Dev bearer tokens (local only)
| Token | Identity | Scopes |
| ------------------- | -------------------------- | ------------------------------------------- |
| `dev-finance` | accounting@seahavenind.com | `ops:read`, `finance:read` |
| `dev-finance-admin` | adam@seahavenind.com | `ops:read`, `finance:read`, `finance:admin` |
Ops-tier tokens (`dev-ops-only`, `dev-assistant`) are **rejected** by this server
(audience binding).
### Sample curl — redaction on egress
```bash
TOKEN=dev-finance
curl -s -X POST localhost:8082/tools/lookup_payment_by_vendor \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"vendor":"Harbor"}' | jq
# → bankAccountNumber / bankRoutingNumber / cardNumber are "[REDACTED]";
# vendor, amount, invoice number are intact.
```
Each call writes one structured audit line to stdout (CloudWatch in Lambda):
```json
{
"kind": "audit",
"sub": "...",
"tool": "lookup_payment_by_vendor",
"argsHash": "<sha256>",
"decision": "allow",
"result": "ok",
"ts": "..."
}
```
Args are **hashed, never logged raw** — secrets never reach the audit log.
### MCP Inspector
Point it at `http://localhost:8082/mcp` (Streamable HTTP) with
`Authorization: Bearer dev-finance`.
## Environment
Same as `sh-mcp-ops` plus `PAYMENTS_TABLE` (aws mode). Finance additionally
applies the **15-minute TTL ceiling** on `finance:*` tokens in `aws` mode
(`docs/design.md §2.5`). `aws` mode is not runtime-exercised in Phase 1.
## CDK
`cdk/app.ts` is a **synth-only** placeholder (no real IAM/Cognito/WAF) — the
finance least-privilege role and audit wiring land in a later phase behind the
mandatory IAM cross-review.