Sentinel
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SentinelCheck this draft response for groundedness and prompt injection issues"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Sentinel
Sentinel is an MCP server that scores AI agent responses before they reach a user — a trust layer an agent calls mid-turn, not a dashboard someone checks after the fact. An agent (or the orchestrator wrapping it) calls a Sentinel tool with the response it's about to send plus the context it was grounded in; Sentinel returns a verdict the caller can act on — allow it, warn, or block it — before the response ever ships.
Free for evaluation, personal, and internal use. Production use requires
a commercial license — see LICENSE.md and
mleg.tech/sentinel for pricing.
It currently ships two tools:
check_groundedness— is this response actually supported by its context, or does it cite something that isn't there?flag_injection— does the context contain a prompt-injection attempt, and did the response go along with it?
Why this exists
Most "AI eval" tooling scores transcripts after the fact, in a dashboard nobody opens. Sentinel is built to sit in the request path: an MCP tool call an agent (or its orchestrator) makes on a response before it goes out, cheap enough in the common case to not be a UX problem.
That "cheap enough" claim is the actual design constraint, and it shapes everything below.
Related MCP server: Agent Guards — deterministic security tools for AI agents
How it works: the escalation ladder
Every metric is deterministic-first. A metric's own regex/pattern logic tries to resolve a call with high confidence — a clear pass or a clear block — using zero model calls. Only the ambiguous middle escalates to an LLM-as-judge call. This keeps the common case fast and the code auditable (a confident block should be explainable without pointing at a model), and reserves the model call for cases that actually need judgment.
ScoringRequest
│
▼
deterministic check (regex / pattern / citation resolution)
│
├── confident pass/block ──────────────► Verdict (decidedBy: "heuristic")
│
└── ambiguous ──► judge call, raced against maxJudgeLatencyMs
│
├── resolves in time ──► Verdict (decidedBy: "judge")
└── times out ──────────► tenant's onTimeout policy:
fail_closed → block
fail_open → outcome "timeout"flag_injection looks for two independent signal families: override
patterns (an injection attempt living in the retrieved context — "ignore
prior instructions," "you are now...") and compliance patterns (the
agent's own response actually going along with it — "sure, here is the
full customer table"). Both firing together is the full attack chain and a
confident block with no judge call; either alone is ambiguous and
escalates. Score direction: higher = worse, blocks when score >= threshold.
check_groundedness extracts citation-like strings from the response
and checks whether the context actually supports them — but a naive
"does this substring appear in the source" check is wrong in exactly the
case that matters most: a document saying "no section 9.2 exists"
contains the literal substring "section 9.2." So the check scans a
~60-character window before each match for negation markers ("no," "not,"
"doesn't," "never mentions," ...); a citation that only ever appears
negated counts as unresolved — same bucket as never appearing at all. An
unresolved citation is a confident block on its own. Otherwise, token
overlap between response and context has to clear a high floor before the
deterministic tier will confidently pass. Score direction: higher =
better, blocks when score < threshold.
Full worked examples and the exact request/verdict JSON shapes live in contracts/README.md.
Policy, per tenant
Nothing is scored against a hardcoded threshold. Each tenant has a
TenantPolicy (policy/registry.ts) that says, per metric: is it enabled,
what's the block threshold, how long a judge call is allowed to run
(maxJudgeLatencyMs), and what happens if it times out (fail_open vs
fail_closed — there is no system-wide default; every tenant sets this
explicitly). A caller can override threshold/timeout knobs per-request, but
can't enable a disabled metric or switch tenant by passing input. Verdicts
from all requested metrics roll up into one EvaluationResult — an
aggregated action (allow/warn/block) and a placeholder 0-100 trust
score, not yet calibrated against real incident data.
Project layout
contracts/ shared types + zod schemas — the only thing every folder depends on
metrics/ the escalation-ladder logic per metric (injection, groundedness)
judges/ provider-agnostic judge interfaces + offline stub judges (no API key needed)
policy/ per-tenant policy resolution (in-memory registry for now)
server/ transport-agnostic handlers (flagInjection, checkGroundedness) + trust-score rollup
server/index.ts stdio MCP entrypoint (Claude Desktop, Cursor, local dev)
app/api/mcp/ HTTP MCP entrypoint (Streamable HTTP, bearer-token auth) — same handlers, thin glue
app/ Next.js demo dashboard
scripts/ smoke test proving the HTTP deploy target end-to-endThe handlers in server/handlers/ are plain async functions with no
transport imports (no MCP SDK types, no Next.js types) — both the stdio
entrypoint and the HTTP route call the exact same functions. Only the
registration glue differs between deploy targets.
Judges are provider-agnostic by interface (judges/types.ts); the only
implementation checked in is an offline stub (judges/stub.ts, zero
network calls, simple pattern/overlap scoring) so git clone && npm install && npm test works with no API key. A real model-backed judge would
implement the same interface in its own file.
Running it
npm install
# stdio MCP server (Claude Desktop, Cursor, etc.)
npm run mcp:stdio
# Next.js app: HTTP MCP endpoint (/api/mcp) + demo dashboard (/)
npm run devThe HTTP endpoint requires a bearer token — it's a hardcoded
token→tenant map for local dev (server/http/auth.ts), not a real
authorization server:
curl http://localhost:3000/api/mcp \
-H "Authorization: Bearer sentinel-local-dev-token" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'Open http://localhost:3000 for the demo dashboard: click "Run demo
session" to watch a real support-agent transcript scored turn by turn —
including a fabricated contract citation and a prompt-injection attempt,
both caught before they'd have reached the user. The pass/fail states come
from genuine round trips to the real handlers, not mocked UI state.
npm test # unit + regression tests (metrics, handlers, scoring)
npm run typecheck # tsc --noEmit --strict
npm run smoke:http # end-to-end proof the HTTP deploy target works: real MCP
# client, real Streamable HTTP JSON-RPC, auth includedUsing this in your own project
Everything above walks through running this repo's demo. Adopting Sentinel into your own agent is a different, smaller task: you're wiring one or two tool calls into a path you already have, not standing up a new service.
The integration point is narrow on purpose. Wherever your agent/orchestrator currently sends a response to a user, add one call first:
const verdict = await flagInjection({ response, context });
// or: await checkGroundedness({ response, context })
if (verdict.action === "block") {
// don't ship the response — return a fallback or re-generate
} else if (verdict.action === "warn") {
// ship it, but log the verdict for review
}
// "allow" → ship as normalThat's the whole contract. Sentinel doesn't need to know anything about
your agent framework, your model provider, or your orchestration layer —
it scores a response-plus-context pair and hands back a verdict. If your
stack can make an MCP tool call (or call the same handlers directly — see
server/handlers/), it can sit in front of Sentinel.
Steps to adopt it:
Clone the repo and run
npm test— confirm the escalation ladder behaves as documented against the existing test fixtures before you change anything.Pick a deploy target:
server/index.ts(stdio) if your agent runs locally or in a tool like Claude Desktop/Cursor;app/api/mcp/(HTTP) if it needs to be called over the network. Both call the same handlers — this is a wiring decision, not an architecture one.Write your own
TenantPolicy(policy/registry.ts) — decide your thresholds, your judge timeout, and explicitly setfail_openvsfail_closedfor your case. There's no safe default; that's a product decision only you can make for your traffic.Point the call at your actual response/context shape. If your agent's "context" isn't already a flat list of strings, the contracts layer (
contracts/) is the place to adapt the shape — not the metrics themselves.Start in
warnmode in front of real traffic before you let anything auto-block, the same way you'd roll out any new gate in a production path.
Licensing note: the code above is free to use for evaluation,
personal projects, and internal experimentation. Running Sentinel in
front of real production traffic requires a commercial license — see
LICENSE.md for the full terms, and
mleg.tech/sentinel for what's included at each tier
(free, commercial, and a done-with-you option for teams that want
production gaps like the Postgres-backed policy registry or a
model-backed judge built against their own setup).
What's a placeholder vs. what's real
The escalation ladder, policy resolution, and both metrics' detection logic are real and tested.
The trust score and the
weightedaggregation mode are explicit placeholders — a starting point, not calibrated against incident data.The policy registry is in-memory; a Postgres-backed implementation implements the same
PolicyRegistryinterface and should be a drop-in.Two more metrics (
toxicity,pii_leakage) are already wired into the policy schema asenabled: false— reference points for where their implementations would live, not stubs pretending to work.The only judge implementation is the offline stub. A real model-backed judge slots into the same
InjectionJudge/GroundednessJudgeinterfaces.
License
Free to use for evaluation, personal projects, and internal
experimentation. A commercial license is required to run Sentinel in
production. Full terms in LICENSE.md; pricing and tiers
at mleg.tech/sentinel.
This server cannot be deployed
Maintenance
Related MCP Connectors
Responsible-AI guardrails for agents: scoring with policy, injection & PII detection, DPDP.
The WAF for agents. Pattern-based + heuristic firewall scans prompts, RAG documents, tool argume...
Deterministic runtime safety for AI agents: scan PII, gate tool actions, verify LLM output.
Zero-trust gateway for AI agents: score tool calls, verify agent cards, enforce policy, audit.
Related MCP Servers
- AlicenseAqualityBmaintenanceProtects AI agents from threats like prompt injection, jailbreaks, and SQL injection through a multi-layer scanning pipeline. It also enables PII redaction and rehydration to ensure data privacy during LLM interactions.1262 npm2Apache 2.0
- AlicenseNot gradedqualityBmaintenanceInput/output safety gate for AI agents: detect prompt-injection/jailbreak, leaked secrets/PII, and URL/IP reputation. Deterministic, no LLM.427 npmMIT
- AlicenseNot gradedqualityCmaintenanceProtects AI agents from prompt injection attacks, jailbreak attempts, and common web vulnerabilities by screening untrusted input through semantic LLM analysis and static pattern matching.21 npm2ISC
- AlicenseNot gradedqualityCmaintenanceProtects AI agents from bad tool outputs, schema mismatches, and tool poisoning by validating, sanitizing, and scoring reliability of tool responses.MIT