MEGAINFRA-WEBAPP/docs/setup/api-and-mcp-connections.md

233 lines
16 KiB
Markdown
Raw Normal View History

# MEGA INFRASTRUCTURE — API and MCP connection guide
Historical connection audit, **5 October 2026**, Africa/Johannesburg. This guide describes this checkout and the live checks saved alongside it.
**Remote MCP update:** See [the remote purchasing MCP guide](./remote-purchasing-mcp.md) for the implemented same-app endpoint, dedicated credentials, client settings and deployment status. The audit below describes the earlier local-only transport and preserves its verified API findings.
**Yes: the app has an HTTP API and a working read-only MCP server.** MCP runs as a local process and reads your hosted PocketBase database using existing credentials. Its current transport is **stdio**: there is no MEGA MCP URL, port, API key or OAuth login.
## Addresses and access
| Connection | Address / setting | Authentication |
| --- | --- | --- |
| Production app API | `https://mega.dash.apphub.co.za/api` | Login session or route-specific secret |
| Local app API | `http://localhost:6004/api` | Currently PIN fallback; ordinary routes do not require a session |
| PocketBase REST API | `https://pb.mega.infra.apphub.co.za/api` | PocketBase token in `Authorization` |
| MEGA MCP | `mega-infrastructure`, local stdio | PocketBase credentials from env file |
| MEGA MCP permissions | 27 read-only tools | Superuser database reads across all sites |
| n8n MCP, separate service | `https://wfdash.n8n.apphub.co.za/mcp-server/http` | Separate n8n MCP credential; not tested here |
`npm run dev` uses **6004**; `npm run start` uses **3000**. Production exposes HTTPS through the reverse proxy.
There is **no universal MEGA API key** or general API-key issuance route in this checkout. `MINIMAX_API_KEY` and `ANTHROPIC_API_KEY` are outbound AI-provider credentials. They are not needed to use the read-only MCP tools.
## Copy-ready MCP settings
These paths are correct for this computer. The repository and KIOXIA volume must be mounted when the client starts the server. Verification used Node **22.22.3** and the installed dependencies. Change the paths when using another computer.
| Field | Value |
| --- | --- |
| Name | `mega-infrastructure` |
| Transport | `stdio` |
| Command | `/Volumes/KIOXIA/.hermes/node/bin/node` |
| Arguments, in order | `--import`, `tsx`, `--env-file=/Volumes/EXT/DEVELOPMENT/MEGAIFRASTRUCTURE/.env.local`, `/Volumes/EXT/DEVELOPMENT/MEGAIFRASTRUCTURE/src/mcp/server.ts` |
| Working directory | `/Volumes/EXT/DEVELOPMENT/MEGAIFRASTRUCTURE` |
| Startup timeout | 20 seconds |
| Tool timeout | 60 seconds |
| Extra env variables | None; `.env.local` supplies credentials |
| Server URL / MCP API key | Leave blank |
### Codex TOML
Copy [mega-mcp.codex.toml](./mega-mcp.codex.toml) into your existing MCP configuration, preserving other servers:
```toml
[mcp_servers.mega-infrastructure]
command = "/Volumes/KIOXIA/.hermes/node/bin/node"
args = ["--import", "tsx", "--env-file=/Volumes/EXT/DEVELOPMENT/MEGAIFRASTRUCTURE/.env.local", "/Volumes/EXT/DEVELOPMENT/MEGAIFRASTRUCTURE/src/mcp/server.ts"]
cwd = "/Volumes/EXT/DEVELOPMENT/MEGAIFRASTRUCTURE"
startup_timeout_sec = 20
tool_timeout_sec = 60
```
Codex supports these fields in `~/.codex/config.toml` or a project `.codex/config.toml`. Its MCP settings UI supports choosing STDIO and entering the command. Save and restart the MCP connection after adding it. See [official MCP configuration documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).
### MCP JSON clients
[mega-mcp.json](./mega-mcp.json) contains the same command, arguments and working directory in `mcpServers` format, with no secret values. Client configuration filenames and support for `cwd` vary; the table above supplies each field individually.
The tested launch uses Node directly, keeping npm's script banner out of the protocol stream. The repository also provides `npm run mcp` for manual startup. `--import tsx` loads TypeScript without the tsx CLI's extra IPC listener.
After connecting, ask your client to **list sites**, **show purchase orders**, or **show pending verification**. It should discover 27 tools. The Next.js app does not need to be running for MCP; PocketBase must be reachable. Client configuration was prepared, but your personal MCP settings were not edited.
## Credentials: where each actual value lives
The values already exist in the linked, ignored local files. Commands below load them directly, so you do not need to copy secrets into a shareable document.
| Value | Location | Purpose and verification |
| --- | --- | --- |
| `NEXT_PUBLIC_POCKETBASE_URL` | [.env.local](../../.env.local), [cooler.env](../../cooler.env) | Hosted database URL; reachable |
| `POCKETBASE_ADMIN_EMAIL`, `POCKETBASE_ADMIN_PASSWORD` | Both files above | Server/MCP database login; deployment-file credentials worked in live MCP calls |
| `POCKETBASE_ADMIN_TOKEN` | `.env.local` | Preset superuser token; authenticated PocketBase GET passed |
| Production `N8N_INGEST_SECRET` | **`cooler.env`** | Header `x-ingest-secret`; production PO lookup passed |
| Local `N8N_INGEST_SECRET` | `.env.local` | **Still the literal template placeholder.** Local accepts it; production rejected it with 401. Use `cooler.env` for production integrations |
| App user email/password | Your existing named MEGA account | Login returns a `mega_session` cookie; successful named-user login was not live-tested |
| `RECEIPT_CORRECTION_SECRET` | `.env.local`; production value from deployment settings | Extra correction code for posted receipts, not a general API key; production value not verified |
| n8n MCP bearer token | Your existing n8n MCP credential/client settings | Separate from PocketBase and ingest credentials; not tested or copied here |
| AI provider keys | Server/provider credential settings | Outbound AI calls only |
The current PocketBase adapter requires **both email and password even when a preset token exists**. It uses `POCKETBASE_ADMIN_TOKEN` preferentially, otherwise logs in with email/password. A stale preset token is not automatically replaced by password login. See [src/lib/pb.ts](../../src/lib/pb.ts).
`cooler.env` is a deployment reference; `npm run dev` does not automatically load it. `.env.coolify` is a placeholder template. `.env.coolify.local` also retains the placeholder ingest secret. No credentials or deployment settings were changed during this audit.
## API examples
### Public health
```bash
curl --fail-with-body https://mega.dash.apphub.co.za/api/health
```
Expected: HTTP 200 with `status: "ok"`, `uptime`, `timestamp`. Health alone does not prove database access.
### Named-user app session
With `AUTH_MODE=users`, protected app routes read the **`mega_session` cookie**, not an `Authorization: Bearer ...` API key. Use a MEGA user login, not a PocketBase superuser login:
```http
POST https://mega.dash.apphub.co.za/api/auth/login
Content-Type: application/json
{"email":"YOUR_MEGA_USER_EMAIL","password":"YOUR_MEGA_USER_PASSWORD"}
```
A successful response includes `user`, `landing`, and `Set-Cookie: mega_session=...`. Keep the cookie in your API client's cookie jar, then call:
```http
GET https://mega.dash.apphub.co.za/api/dashboard-attention
Cookie: mega_session=YOUR_SESSION_TOKEN
```
The cookie is HttpOnly, SameSite=Lax, Secure in production, with a five-day browser lifetime. PocketBase checks token validity. Password-change requirements, roles and site assignments can deny requests; non-admin users are scoped to assigned sites, with additional route-specific checks.
Local PIN mode does **not** authenticate ordinary API requests: `getCurrentUser()` supplies the PIN admin identity without a cookie. The local dashboard GET returned 200 without credentials. Production returned 401 without a session. The browser PIN is not an API key.
### Production machine API
Run this from the repository directory. It loads the **tested production secret** from `cooler.env`; replace `YOUR_PO_NUMBER`:
```bash
node --env-file=cooler.env --input-type=module - <<'NODE'
const poNumber = "YOUR_PO_NUMBER";
const response = await fetch(
`${process.env.APP_URL}/api/purchase-orders/by-number/${encodeURIComponent(poNumber)}/items`,
{ headers: { "x-ingest-secret": process.env.N8N_INGEST_SECRET } },
);
console.log("HTTP", response.status);
console.log(await response.json());
NODE
```
Expected: 200 and `{ po, items }`; unmatched POs may return `po: null`. Missing/wrong secrets return 401. The live check looked up a real PO without retaining its contents in the report.
| Method | Route using `x-ingest-secret` | Purpose |
| --- | --- | --- |
| GET | `/api/purchase-orders/by-number/[poNumber]/items` | Read PO lines |
| GET | `/api/purchase-orders/[id]/delivery-reconciliation` | Read reconciliation snapshot |
| GET | `/api/delivery-notes/[id]/slip` | Read source slip |
| POST | `/api/purchase-orders/ingest` | Ingest PO data; changes records |
| POST | `/api/purchase-orders/process-batch` | Finalise PO extraction; changes records |
| POST | `/api/dn-batches/tick` | Process queued delivery documents; changes records and may call AI |
The ingest secret only authorizes handlers that check it. It does not replace the login cookie on ordinary routes. Receipt corrections additionally require operational authorization, the correction code and same-origin checks. Some Ask/action routes check Origin; `x-ask-user` is an Ask identity selector, not a general API key. General cross-origin browser API access is not configured in this checkout; use a server-side client or the app's own origin.
### Direct PocketBase REST API
PocketBase is a separate service. Send its **raw token** in `Authorization`, rather than the app cookie. See [PocketBase authentication documentation](https://pocketbase.io/docs/authentication/).
```bash
node --env-file=.env.local --input-type=module - <<'NODE'
const response = await fetch(
`${process.env.NEXT_PUBLIC_POCKETBASE_URL}/api/collections/sites/records?page=1&perPage=1&fields=id,name,project_code`,
{ headers: { Authorization: process.env.POCKETBASE_ADMIN_TOKEN } },
);
console.log("HTTP", response.status);
console.log(await response.json());
NODE
```
Superuser database access bypasses app business checks and site restrictions. The supplied MCP process is for the owner/admin; it does not authenticate individual app users. Ordinary PocketBase user-token access is subject to collection rules and was not verified here.
The [current route inventory](./api-route-inventory.md) lists **78 route files** with methods and links to source. The older [API reference](../api-reference.md) contains payload details, but some auth descriptions predate named-user login; current source and this guide take precedence.
## All 27 MCP tools
These were discovered through a live `tools/list`. Full descriptions and JSON input schemas are preserved in [connection-check-results.json](./connection-check-results.json).
| Tools | What they read |
| --- | --- |
| `list_sites`, `get_site_financials`, `get_site_trend` | Site totals and trends |
| `site_report`, `portfolio_report`, `problem_report`, `improvement_report` | Reports and findings |
| `vehicles_needing_attention`, `get_fuel_summary`, `get_vehicle_fuel_log` | Fleet and fuel |
| `get_pending_verification` | Unverified POs and delivery notes |
| `get_purchase_order`, `list_purchase_orders` | Purchase orders and lines |
| `get_delivery_note`, `list_delivery_notes`, `delivery_note_queue` | Delivery notes and queues |
| `top_workers`, `list_employees`, `attendance_today` | Workforce and attendance |
| `list_plant_hours`, `plant_equipment_summary` | Plant hours and summaries |
| `list_fixed_costs`, `list_income_claims`, `supplier_balances` | Costs, income and suppliers |
| `list_imports`, `rain_outlook`, `list_change_requests` | Imports, weather and logged requests |
Argument examples: `list_sites` takes `{}`; `list_employees` and `list_purchase_orders` accept `{ "limit": 1 }`; `get_site_financials` requires `{ "site": "SITE_NAME_OR_CODE_OR_ID" }`; `get_site_trend` additionally accepts `"granularity": "month"` or `"week"`.
Ask chat has separate action/write tools. [src/mcp/server.ts](../../src/mcp/server.ts) registers only the read-only tool set; Ask's actions are not exposed through this MCP server.
## Test results
| Check | Result |
| --- | --- |
| MCP initialize/discovery | Passed with both env files; v1.0.0, 27 tools |
| Live MCP reads | `list_sites`, `list_employees`, `list_purchase_orders`, `get_pending_verification` passed with both env files |
| PocketBase health and preset-token records GET | Both 200 |
| Local app health | 200 |
| Local dashboard GET without session | 200; PIN fallback |
| Production app health | 200 |
| Production dashboard GET without session | 401, `Sign in required` |
| PO lookup without secret, both hosts | Both 401 |
| Local PO lookup with `.env.local` secret | 200; placeholder accepted locally |
| Production PO lookup with `.env.local` secret | **401: credential mismatch** |
| Production PO lookup with `cooler.env` secret | **200: working production credentials** |
| Local `/api/mcp` GET | 404; no HTTP MCP route in this checkout |
| Production `/api/mcp` GET | 401 from login guard; does not establish an HTTP MCP endpoint |
| Focused automated tests | **58 passed in 7 files**, covering auth/login, route classification, health, batch tick, agent loads and read-only enforcement |
The [final local report](./local-connection-check-results.json) has **13 passed / 0 failed**. The [combined default-env report](./connection-check-results.json) has **17 passed / 1 failed**: the placeholder secret fails against production. The [deployment-env production report](./production-connection-check-results.json) has **12 passed / 0 failed**. These are connection checks, not exhaustive tests of every tool and operation.
Successful named-user login, data-changing API operations, n8n MCP authentication and AI-provider calls were not live-tested. Automatic approval review rejected the initial batch-processing endpoint probe because it could mutate queued documents. The final checker uses GET-only app requests and read-only MCP tools; the batch handler was covered by automated tests.
Reports contain schemas, status codes and response shapes, without secrets or business records. UTC timestamps on 4 October at about 22:25–22:27 correspond to **5 October** after midnight in Johannesburg.
## Repeat verification
The [saved checker](../../scripts/check-connections.mjs) loads an env file and prints secret-redacted JSON. App requests are GET-only and MCP tools read-only. With password-only PocketBase credentials, database authentication itself uses the normal login request.
```bash
# Local only, with the app running on 6004.
node scripts/check-connections.mjs
# Production with verified credentials — passed 12/12.
MEGA_CONNECTION_ENV_FILE=cooler.env node scripts/check-connections.mjs https://mega.dash.apphub.co.za
# Compare local credentials against both hosts — exposes the mismatch.
node scripts/check-connections.mjs http://127.0.0.1:6004 https://mega.dash.apphub.co.za
```
Repeat the focused automated tests with:
```bash
npm run test:run -- src/lib/agent/read-only.test.ts src/lib/agent/load.test.ts src/lib/auth/guard.test.ts src/lib/auth/proxy-path.test.ts src/app/api/health/route.test.ts src/app/api/auth/login/route.test.ts src/app/api/dn-batches/tick/route.test.ts
```
Failures produce a nonzero exit code. Run from a terminal with local socket/external network access. The checker changes neither env files nor deployed credentials.
For a URL-based MCP client on another device, the current server would need an authenticated HTTP transport or a supported remote-execution arrangement. This audit did not add one. Local MCP already reads the hosted production database.