mcp-ai-wpoos-gateway-ops
Operational guide for the NV oOS MCP Gateway (addons/mcp-gateway → mirror nvoos-mcp-gateway → Cloudways Velocity at mcp.nvoos.pro, issue
SKILL.md.agents/skills/mcp-ai-wpoos-gateway-ops/SKILL.md
GitHubmcp-ai-wpoos — Gateway ops
What / where
- Canonical source:
addons/mcp-gateway/(Node, express, zero-added-deps, env-configured, fail-closed). - One-way mirror:
nvdigitalsolutions/nvoos-mcp-gateway(main) via.github/workflows/sync-mcp-gateway.yml— snapshot commit per sync, no--force, version-guarded (olderpackage.jsonversions are skipped). Never commit to the mirror directly. - Deploy target: Cloudways Velocity at
https://mcp.nvoos.pro. Auto-deploy fires on the mirror push; env vars are dashboard-only (no Cloudways API/MCP surface for Velocity). - Tracking issue: #6902. Deploy guide:
docs/operations/deployment/mcp-gateway-velocity-setup.md. Submission pack:docs/operations/deployment/mcp-gateway-directory-submission.md.
Live map (verified 2026-11-01)
| Slug | Site | Visibility |
|---|---|---|
demo |
https://nvoos.pro |
Public — demo key, listings |
sascha |
https://nirmanawellness.nvdigital.solutions |
Private client — own key |
ideabits |
https://ideabits.nvdigital.solutions |
Private client — own key |
console |
https://console.nvoos.cloud |
(not bound at time of writing) |
PUBLIC_SITE_SLUGS=demo— public/healthreports onlydemo;/health/full(keyed) reports every site.- Demo key (published in directory listings, never in the repo): bound to
demoonly, allowlistedget_environment_status+deep_research. - Client sites carry their own public keys (one key may bind both ideabits+sascha when the same client owns them).
Public keys — GATEWAY_PUBLIC_KEYS
- Syntax:
key=slug-a,slug-b;key2=slug-c(or a JSON object{"key":["slug-a"]}).;= entry separator,== key→sites,,= multiple sites. A trailing;is harmless. Whitespace is trimmed. - Keys are 32-byte
base64url(node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))") — the alphabet can never contain;,,, or=, so no quoting is needed. Minimum length 16 (MIN_KEY_LENGTH). - One variable, one line: the Velocity dashboard must have a single
GATEWAY_PUBLIC_KEYSrow holding the whole map — duplicate rows do not merge. - Fail-closed: a key bound to an unconfigured slug (no
NVOOS_SITE_<SLUG>_URL/_TOKEN) is a boot error and takes the whole gateway down — add the site vars in the same env edit as the key. - Rotation: new key in
GATEWAY_PUBLIC_KEYS, old one inGATEWAY_PUBLIC_KEYS_PREVIOUS(accepted with a one-time warning), remove once consumers switched. PUBLIC_SITE_SLUGS(added 2026-11-01, PR #7347): comma-separated slugs visible on the public/health; unset/*= all (legacy). Hidden sites stay invisible publicly and their degradation does not flip the publicstatus;/health/fullalways reports everything. Unknown slugs are boot warnings, never fatal (a typo hides sites — the safe direction).
Upstream 401 playbook (the recurring failure)
Symptom: tools/list → _meta.gateway.errors.<slug>: "upstream error (401)"
(the gateway degrades gracefully — other sites keep flowing).
- Identify the host:
GET /health/fullwith any key →sites.<slug>.url. - Probe the site directly:
curl -s -X POST https://<host>/wp-json/mcp-ai/v1/mcp -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}'— the plugin's structured{"code":"wp_mcp_ai_mcp_auth_required",...}401 means the operator token is stale/rotated (not a bot-wall; a Cloudways Anti-Bot/Imunify wall would return HTML/403). - Fix on the target site: Settings → External Operators → re-mint the
demo/client operator's token (full
op_xxxx.SECRET, both halves, no trailing whitespace) and set its Allowed tools (least privilege — e.g.get_environment_statusfor public demo keys). - Update
NVOOS_SITE_<SLUG>_TOKENin the Velocity env (env edits restart the app —/healthuptimeresets). - Verify:
tools/listshows no_meta.gateway.errors+ one safetools/call(e.g.<slug>.get_environment_status).
Deploy verification ladder
- Version marker:
/health.versionmust equaladdons/mcp-gateway/package.json'sversion. TheVERSIONconstant insrc/index.jsis a hardcoded string that must track it (PR #7345 added the comment + a health test that enforces the contract — a version bump that misses the constant now fails the suite). Historical: the 0.2.0 bump forgot it and/healthlied 0.1.1. - 0.2.0 fingerprints (independent of the marker):
traceparentresponse header + RFC 9558RateLimit-*headers (the policy layer). - Restart clock:
uptimetells when the app last restarted — compare against the mirror-sync time to judge whether a deploy landed. - Stale deploy (mirror advanced,
/healthversion behind, uptime older than the sync): Velocity auto-deploy missed it → Deployment Manager shows a commit not in the mirror history → disconnect/reconnect the GitHub repo and redeploy (§7 of the setup guide). Also the CI-skip-marker incident: a squash body absorbing[ci skip]runs zero workflows — recover with a follow-up PR touchingaddons/mcp-gateway/**orgh workflow run sync-mcp-gateway.yml --ref alpha-working. - Env edit pitfall: paste-append, never replace the whole env set — the replace dropped three site-var groups in one session (2026-11-01).
Registry publishing (mcp-publisher)
- Binary:
C:/Users/rasta/.mcp-publisher/mcp-publisher.exe(device-flow session stored on the machine; the JWT expires — re-runmcp-publisher login githubbefore publish; the flow prints a GitHub device code and polls). validatehits the live registry schema (no auth).descriptionmust be ≤ 100 chars (422 otherwise; the bridge entry used 95).publishfrom theaddons/mcp-gateway/dir (resolvesserver.jsonfrom the CWD). Entry:io.github.nvdigitalsolutions/nvoos-mcp-gateway(remote-only; no packages/ownership marker needed for remotes).- Verify:
GET https://registry.modelcontextprotocol.io/v0.1/servers?search=<name>→count:1,_meta.io.modelcontextprotocol.registry/official.status: active. Detail URL:/v0.1/servers/<encodeURIComponent(name)>/versions/<version>. - Propagation: mcp.directory, PulseMCP, and Glama auto-import from the official registry — no manual submission; check +24h/+7d. Only mcpservers.org needs a manual form (https://mcpservers.org/submit).
- Demo-key rule: the key value is published in each directory listing but must never be committed to the repo or issues.
Assets & tests
addons/mcp-gateway/assets/is served at/assets(static middleware). Logo for listings:https://mcp.nvoos.pro/assets/nvoos-logo.png(512×512, converted from the brand favicon via PowerShell System.Drawing; ship the source JPG alongside).- The local
.git/info/excludeignores*.png/*.jpg(per-worktree guard) —git check-ignore -v <path>before adding, thengit add -ffor deliberate assets. - Tests:
npm testhangs on Windows after the quota suites (pre-existing; run targeted files instead —node --test src/routes/health.test.js src/utils/config.test.js src/middleware/auth.test.js).node --test <dir>does not recurse — pass explicit files or the package script.
Cross-references
mcp-ai-wpoos-schedule-anything-ops— the Velocity deploy/mirror-sync mechanics shared with the other Velocity apps.mcp-ai-wpoos-git-ops— sibling-PR conflict resolution, shared-worktree rules,.git/info/excludeforce-add.- Docs:
docs/operations/deployment/mcp-gateway-velocity-setup.md,docs/operations/deployment/mcp-gateway-directory-submission.md,docs/project/proposals/061-mcp-registry-publishing-implementation-plan.md.