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

16 KiB
Raw Permalink Blame 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 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 into your existing MCP configuration, preserving other servers:

[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.

MCP JSON clients

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, 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.

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

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:

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:

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:

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.

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 lists 78 route files with methods and links to source. The older API reference 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.

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 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 has 13 passed / 0 failed. The combined default-env report has 17 passed / 1 failed: the placeholder secret fails against production. The deployment-env production report 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 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.

# 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:

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.