MCP Sentinel · Architecture
System architecture

How MCP Sentinel is built

A single-tenant-per-user web app that audits Model Context Protocol servers. Every user-host connection passes through one SSRF-hardened connector; detection is deterministic (no LLM); auth tokens are ephemeral. React SPA ⇄ REST/JSON ⇄ Hono/Node ⇄ PostgreSQL.

data / control flow security spine (SSRF · tokens · ReDoS) layer / module trust boundary

client Frontend — React 18 + Vite SPA (TypeScript)

saas app shell · token-driven UI (light/dark) · TanStack Query · React Router. All MCP-origin strings rendered escaped (INV-8).
LandingLogin / RegisterDashboard + new-scan Report + findings drill-downRaw JSON-RPC viewer Endpoint history + grade trendCompare / diff Share / exportPublic shared report
REST / JSON over HTTPS · httpOnly session cookie · double-submit CSRF
Backend — Hono on Node.js (TypeScript) · npm-workspaces monorepo (apps/api, apps/web, packages/shared)

http HTTP layer

Middleware chain (in order): security headers + CSP/HSTS → request-id + structured logging → rate limiter → session/auth → CSRF/Origin → router. Errors → RFC 9457 problem+json via onError on every router.
routes /api/*auth middlewareCSRF / Origin guard rate limiter (ip · user)zod validationproblem+json errors

services Service layer tenant-scoped via withUserScope (INV-5)

The only callers of the data layer. identity.ts is the pre-auth identity module (exempt from tenant scoping by design).
identity (auth · sessions · HIBP)ScanService ReportServiceDiffServiceEndpointServiceShareService

scanner core Deterministic engine no LLM in this path (INV-7)

A scan flows left → right. Hard caps: 10s deadline · 5 MB/response · JSON depth ≤ 64 · per-user concurrency ≤ 3.

SafeConnector

SSRF chokepoint: resolve-all-IPs deny-list, IP pinning, redirect re-validation

McpClient

JSON-RPC over Streamable HTTP: initializetools/resources/prompts·list (INV-14)

Normalizer

zod-validate untrusted items · canonical hash per definition

RuleEngine

7 detectors over a linear-time matcher (ReDoS-safe, INV-9)

Grader

severity → posture grade A–F

tool-poisoningexcessive-scopesecret-leak rug-pullmissing-authtransport-hygiene

data Data layer — Drizzle ORM

All user-scoped access via withUserScope. Secrets redacted before write; no table stores a user MCP auth token (INV-3).

store PostgreSQL 16

9 tables · UNIQUE on lower(email) & (user_id, url_normalized) · per-tenant isolation.
userssessionsendpointsscans findingsinventory_itemsscan_diffs share_linksaudit_log

External systems & trust boundary

untrusted Target MCP server

Arbitrary user-supplied URL. Endpoint, DNS, responses, and any pasted token are all attacker-influenceable.
  • Reached only through SafeConnector (INV-1 / INV-2).
  • Denied: loopback · RFC1918 · link-local · 169.254.169.254 · ULA · IPv4-mapped-private.
  • Opt-in SCAN_ALLOW_HOSTS (default empty) for trusted localhost dev servers.

outbound HaveIBeenPwned

Breached-password screening on register (NIST 800-63B).
  • k-anonymity range API — only the first 5 SHA-1 hex chars leave the process.
  • Fails open on outage; toggle with HIBP_ENABLED.

Scan data flow

1 POST /api/scans → auth → rate limit → zod (scheme/userinfo/length).
2 ScanService find-or-creates the endpoint (ON CONFLICT) + a running scan row.
3 SafeConnector validates scheme, resolves & deny-lists every IP, pins the connection.
4 McpClient handshakes then enumerates tools/resources/prompts under caps (SSE + JSON).
5 Normalizer zod-validates & canonicalizes → ServerInventory + per-tool hash.
6 RuleEngine runs each detector → severity-ranked Finding[] (evidence redacted).
7 Grader maps findings → grade A–F.
8 ReportService persists report + findings; DiffService diffs vs the prior scan.
9 The auth token is discarded — it never leaves request scope (INV-3).

Architectural spine — enforced invariants

SSRF Egress containment

  • INV-1 all user-host egress via SafeConnector.
  • INV-2 connector is the single chokepoint.
  • INV-14 initialize precedes enumeration.

secrets Token & data handling

  • INV-3 tokens never persisted.
  • INV-4 logger redaction (no raw tokens).
  • INV-9 linear-time matcher (ReDoS-safe).

isolation Tenant & UI safety

  • INV-5 reads via withUserScope.
  • INV-7 no LLM in detection path.
  • INV-8 no dangerouslySetInnerHTML.

Stack & deployment

runtime Technology

React 18ViteHonoNode LTS PostgreSQL 16Drizzle ORMzodundici (IP pinning) scrypt (node:crypto)pinoVitestPlaywright

deploy Topology

  • docker compose: db + app (API serves the built SPA).
  • HTTPS-only: TLS at a reverse proxy, HTTP→HTTPS redirect, HSTS.
  • Structured JSON logs · audit_log trail · header-buffer sizing.
← Gallery