Architecture

July 19, 2026 · View on GitHub

Read this first. One screen, whole repo. For product install docs see root README.md; for hosted deploy/auth/quota internals see hosted-server/docs/ARCHITECTURE.md (a linked deep-dive, not a competing map); for the tool-logic module map see npm-package/ARCHITECTURE.md.

The pipeline — both entrances, one dispatch core

Two entrances exist. Both converge on the same dispatch core — the hosted server never forks tool behavior.

AI client

  ├─ stdio ── npx novada-mcp ──────────────► npm-package/src/index.ts
  │                                            (stdio transport, tool/group filtering)

  └─ HTTP ─── https://mcp.novada.com/mcp ──► hosted-server/vercel/api/mcp.ts
                                               (Vercel Function: auth, quota, rate-limit,
                                                telemetry — wraps the SAME tool catalog)

                        both dispatch through                │
                        ─────────────────────────────────────┘

                                          npm-package/src/core.ts
                                          (TOOLS catalog + dispatch() — side-effect-free,
                                           importable from either transport or tests)


                                    npm-package/src/tools/*.ts (43 files: 40 per-tool
                                    implementations + index.ts barrel + registry.ts +
                                    types.ts)


                                    Novada upstream APIs (proxy network, scraper, SERP)

hosted-server/vercel/api/mcp.ts does not re-implement tools. Its deploy step (hosted-server/scripts/deploy-hosted.sh) builds npm-package/, then vendors the compiled build/ output into hosted-server/vercel/vendor/ — never hand-edited, regenerated every deploy.

Where does X actually live?

The single biggest source of confusion in this repo has been "where do I edit a tool's MCP-facing description?" — three different places could plausibly be it. This table is the resolution, grep-verified against the live code:

ConceptAuthoritative file
Full MCP tool description + inputSchema + annotations (what the client sees)npm-package/src/core.ts_TOOL_DEFINITIONS (~line 171)
Curated visible-tool list + short catalog one-liner (used by novada_discover)npm-package/src/tools/registry.tsTOOL_REGISTRY
Drift guard (registry ⊆ dispatchable, no ghost tools)npm-package/tests/tools/discover.test.ts
Tool implementation + Zod param validationnpm-package/src/tools/<name>.ts
stdio transport wiring, env-based tool/group filtering (NOVADA_TOOLS/NOVADA_GROUPS)npm-package/src/index.ts
HTTP transport, auth, quota, rate-limit, telemetryhosted-server/vercel/api/mcp.ts
MCP resources (read-only reference data)npm-package/src/resources/
MCP prompts (workflow templates)npm-package/src/prompts/
Deploy hosted (build → vendor → gate → deploy → verify)hosted-server/scripts/deploy-hosted.sh

Concretely: to change what an AI client reads for a tool (its description, required params, examples), edit _TOOL_DEFINITIONS in core.ts, not index.ts and not the tools/<name>.ts file (that file only holds the implementation + its own Zod schema).

Distribution

SurfacePackage/URLTransportDeploy target
Local stdio servernpm novada-mcp (npx novada-mcp)stdion/a — runs on the user's machine
Hosted HTTP serverhttps://mcp.novada.com/mcpStreamable HTTPVercel (Node.js serverless Function, not Cloudflare Workers — see below)

Both ship the identical tool catalog and behavior; the hosted surface adds auth, a monthly quota, and rate-limiting on top (see hosted-server/docs/ARCHITECTURE.md for that layer's detail). Browser-automation tools (novada_browser, novada_browser_flow) require NOVADA_BROWSER_WS and work identically on both surfaces — this is a credential requirement, not a hosted-vs-local capability gap (see npm-package/README.md).

Live deploy target is Vercel, not Cloudflare Workers. A dormant CF Workers port exists at hosted-server/worker/ for reference only (not deployed); hosted-server/vercel/ is the active, deployed path. Confirmed directly against hosted-server/vercel/api/mcp.ts's own runtime config (export const config = { runtime: "nodejs", ... }, explicitly chosen over Edge because the tool implementations depend on Node-only modules) and hosted-server/README.md.