16 KiB
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.