Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mcphub.app/llms.txt

Use this file to discover all available pages before exploring further.

This page describes the actual moving parts of MCPHub today. Anything not listed here is not implemented — there is no built-in Redis, no Prometheus exporter, no WebSocket server, no plugin loader.

Process model

MCPHub runs as a single Node.js (Express) process. The entrypoint is src/index.ts, which delegates to AppServer in src/server.ts. AppServer is responsible for:
  1. Initializing i18n (src/utils/i18n.ts).
  2. Bootstrapping the default admin user (src/models/User.ts:initializeDefaultUser).
  3. Initializing the optional upstream-MCP OAuth client provider (src/services/oauthService.ts) and the optional MCPHub OAuth authorization server (src/services/oauthServerService.ts).
  4. Wiring middlewares (src/middlewares/index.ts) and HTTP routes (src/routes/index.ts).
  5. Spawning / connecting all enabled upstream MCP servers via initUpstreamServers() in src/services/mcpService.ts.
  6. Mounting the SSE / streamable-HTTP MCP routes (/mcp/:group, /sse/:group, and their user-scoped variants /:user/mcp/..., /:user/sse/...).
  7. Serving the built frontend from frontend/dist/ (unless DISABLE_WEB=true).
Shutdown is handled in AppServer.shutdown(): stop the HTTP server, close all upstream MCP clients, then close the database pool if database mode is on.

Top-level directories

PathPurpose
src/server.tsAppServer class — process lifecycle, MCP route registration.
src/index.tsCLI entrypoint that constructs and starts AppServer.
src/routes/index.tsAll HTTP route definitions (single file).
src/middlewares/Auth (auth.ts), user context (userContext.ts), i18n, common middleware.
src/controllers/One controller per resource (servers, groups, users, tools, prompts, resources, logs, activities, OAuth, bearer keys, templates, market, cloud, registry, MCPB upload, health, config).
src/services/Long-lived domain services — see the table below.
src/dao/Data access layer with a file backend (default) and a TypeORM-based DB backend (*DaoDbImpl.ts). The factory in src/dao/DaoFactory.ts selects the implementation.
src/db/TypeORM DataSource, entities (src/db/entities/), repositories, subscribers. Loaded only in database mode.
src/models/Lightweight in-memory models (e.g. User, OAuth) that wrap the DAO layer for convenience.
src/clients/Upstream MCP client wrappers (stdio / SSE / streamable-http / OpenAPI).
src/types/Shared TypeScript types — start here when looking for config schemas.
src/utils/Helpers: rate limiting, JWT, vector helpers, file migration, bearer-token parsing, etc.
src/betterAuth.tsOptional Better Auth integration (GitHub/Google OAuth).
frontend/Vite + React dashboard. Talks to the API over /api. In dev, frontend/vite.config.ts proxies to http://localhost:3000.

Service layer

The services in src/services/ are the core domain layer. Notable members:
ServiceResponsibility
mcpService.tsLifecycle of all upstream MCP clients (connect, reconnect, capability cache, tool/prompt/resource registries).
sseService.tsHandles HTTP requests on /sse/* and /mcp/* and proxies them to the right upstream client / group / smart route.
smartRoutingService.tsVector-search-based tool discovery. Requires Postgres + pgvector and an OpenAI-compatible embedding endpoint.
vectorSearchService.tsEmbedding store and similarity search backing smart routing.
oauthService.tsActs as an OAuth client to upstream MCP servers that require OAuth.
oauthServerService.tsActs as an OAuth authorization server for downstream MCP clients (uses @node-oauth/oauth2-server).
betterAuthConfig.ts + src/betterAuth.tsOptional social-login layer; mounted at ${basePath}${betterAuthConfig.basePath} (default /api/auth/better).
activityLoggingService.tsRecords request/response activities. Persists to the mcphub_activity table; only active in database mode.
logService.tsIn-process log buffer that powers /api/logs and the SSE stream at /api/logs/stream.
templateService.tsExport / import of mcp_settings.json snapshots and group templates.
marketService.ts / cloudService.ts / registry.tsRead-mostly catalogs surfaced by the dashboard.
keepAliveService.tsOptional periodic ping for sse upstream servers.

Data layer

MCPHub supports two storage backends. The choice is decided once at startup:
useDatabase = (USE_DB === 'true') OR (USE_DB unset AND DB_URL set)

File mode (default)

All persistent state lives in mcp_settings.json (path configurable via MCPHUB_SETTING_PATH). Users, servers, groups, system config and OAuth state are read/written through src/dao/*Dao.ts file implementations. This is the simplest deployment mode and works for single-instance use.

Database mode

When enabled, MCPHub uses TypeORM against PostgreSQL. The schema is defined by entities in src/db/entities/:
  • User, BearerKey, OAuthClient, OAuthToken
  • Server, Group, SystemConfig, UserConfig
  • BuiltinPrompt, BuiltinResource
  • Activity — request/response logging (only populated in DB mode).
  • VectorEmbedding — pgvector-backed table used by smart routing.
The DAO factory in src/dao/DaoFactory.ts swaps in the *DaoDbImpl.ts variants when database mode is on. A one-time migration script src/scripts/migrate-to-database.ts copies an existing mcp_settings.json into the database; the helper in src/utils/migration.ts runs the same path on first start. See Database Configuration for setup details.

Request paths

There are three classes of HTTP route, all defined in src/routes/index.ts and mounted by AppServer:
  1. Public endpoints (no auth):
    • GET /health
    • GET ${basePath}/config, GET ${basePath}/public-config
    • All /oauth/* and /.well-known/oauth-* endpoints (the OAuth flow itself).
    • All ${basePath}/api/openapi* and ${basePath}/api/tools/... OpenAPI endpoints.
    • POST /api/auth/login, POST /api/auth/register.
  2. Authenticated dashboard / management API under ${basePath}/api/*. Authentication is enforced by src/middlewares/auth.ts, which accepts (in order):
    • A configured bearer key (/api/auth/keys) whose accessType is all.
    • An OAuth access token issued by MCPHub’s authorization server (when enabled).
    • A Better Auth session cookie (when enabled).
    • An x-auth-token JWT issued by /api/auth/login, or the same value as a ?token= query.
    • If systemConfig.routing.skipAuth is true, unauthenticated dashboard API calls receive a synthetic guest user with admin privileges.
  3. MCP transport routes: ${basePath}/mcp/:group?, ${basePath}/sse/:group?, plus their user-scoped variants ${basePath}/:user/mcp/... and ${basePath}/:user/sse/.... These are rate-limited via mcpConnectionRateLimiter and pass through sseUserContextMiddleware before being dispatched by sseService.ts. Per-route bearer key scopes (accessType !== 'all') are enforced inside sseService.ts.

Observability

What actually ships today:
  • GET /health — process & database & MCP-server connection status.
  • GET /api/logs, DELETE /api/logs, GET /api/logs/stream (Server-Sent Events of the in-memory log buffer).
  • GET /api/activities* — query the mcphub_activity table. Database mode only.
There is no Prometheus exporter, no OpenTelemetry SDK initialization and no built-in distributed tracing. If you need those, scrape /health//api/logs/stream or wrap the process at the infrastructure layer (sidecar, log shipper, etc.).

Frontend

The dashboard is a Vite + React + Tailwind app under frontend/. After pnpm build it is emitted to frontend/dist/ and served by the backend as static files at ${basePath}/. In development (pnpm dev), Vite runs on :5173 and proxies /api, /mcp, /sse, /oauth, /health to the backend on :3000 — see frontend/vite.config.ts. The frontend uses the same JWT / Bearer / Better Auth session that the management API expects; it does not have its own auth.