io.github.dbhat93/grounded
Click on "Install 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., "@io.github.dbhat93/groundedDo you integrate with Fiserv DNA, and is it generally available?"
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.
Grounded
A trust-first answer layer for high-trust sales. Cite the source or say "I don't know." Never confidently wrong.
Try the live demo: type a hard sales question and watch it answer with a citation, label GA vs roadmap, or refuse to guess.
See CONCEPT.md for the thesis and market read, and ARCHITECTURE.md for the production design. This repo is the working core of the wedge: a grounded copilot.
What this is
Type a product / integration / security question, get back one vetted answer with a citation and a live-vs-roadmap label, or a refusal ("not in the knowledge base"). It runs against a fictional testbed company (Kestrel, a made-up fraud/KYC SaaS selling into banks) so there is zero proprietary data anywhere in the repo.
The core design decision: the answer returned is the vetted fact, verbatim. Nothing is composed or paraphrased by a model, so it structurally cannot hallucinate. Grounding is the whole product; a constrained LLM composition layer is a later, optional dial (see ARCHITECTURE).
Related MCP server: local-docs-mcp
Run it
python3 -m grounded "do you integrate with fiserv dna?" # one-shot (hybrid, default)
python3 -m grounded --lexical "..." # lexical only (fast, no model)
python3 -m grounded --eval # guardrail eval (hybrid)
python3 -m grounded --lexical --eval # guardrail eval (lexical)
python3 -m grounded --watch evals/sample_call.txt # live entity-triggered mode
python3 -m grounded # interactive REPLRetrievers: hybrid (default; lexical + dense, production), --lexical (stdlib, deterministic, no dependencies, offline), --dense (semantic only), --rerank (experimental; adds a cross-encoder, currently underperforms the ensemble, see below). Hybrid and dense need sentence-transformers, lancedb, and a one-time model download (thenlper/gte-large); the KB vectors are then cached in an on-disk LanceDB store.
The guardrail
evals/eval_set.jsonl is 118 adversarial questions built to attack the "never wrong" promise: answerable paraphrases (GA), synonym/word-form paraphrases ("operating hours" for support hours), beta/roadmap traps phrased as if live, honest-no, off-domain, leading absolute-claim traps ("guarantee 100% of fraud"), standard/version variants ("SOC 1" vs SOC 2), and near-miss brand variants ("Fiserv Premier" vs Fiserv DNA). The harness scores each as:
CORRECT right answer, right row
REFUSED_OK correctly said "not in the KB"
MISS refused when it could have answered (safe, not harmful)
WRONG confident-wrong, or answered when it should have refused
WRONG must be 0. --eval exits non-zero if it is not. This is the release gate. Current results by retriever (93 answerable of 118):
retriever | correct | miss | wrong |
lexical | 84 | 9 | 0 |
dense (gte-large) | 87 | 6 | 0 |
hybrid (default) | 89 | 4 | 0 |
How grounding is enforced
Retrieval, not generation. The vetted row is the answer.
Refuse below a confidence threshold. No match, no answer.
Shared-token gate. A match built on one incidental word ("policy", "fraud") is rejected. A single shared token answers only when it is a proper-noun/acronym the buyer named (Salesforce, SAML, detected by case in the source), or when the whole question is one distinctive KB term ("consortium").
Number/version guard. A question that pins a number the matched row does not carry refuses instead of answering the sibling ("SOC 1" against a SOC 2 row, "ISO 27001", "TLS 1.3").
Curated negative knowledge. Known near-miss products the buyer might name are in the KB as explicit "not supported" rows ("Fiserv Premier" when only Fiserv DNA is vetted), so the copilot gives a definitive correct answer instead of confusing a sibling for the real thing.
Twin collapse. The same fact stored in two files (Q&A bank + capability matrix) is one result, not a false "ambiguous."
Loud status labels. Every capability answer is tagged GA / BETA / ROADMAP / NOT SUPPORTED, with a caution line for anything not generally available.
Staleness flag. A row verified more than 90 days ago is flagged "re-confirm before quoting."
Retrieval (production hybrid)
Retrieval is where recall is won, and it is separated from the guarantee: the grounding contract (finalize) is identical no matter which retriever produced the candidates. Three retrievers share it.
Lexical (TF-IDF, stdlib) nails proper nouns and acronyms (Salesforce, SOC 2, Fiserv) and carries the token gate. Dense (thenlper/gte-large over a LanceDB vector store) closes the synonym and word-form gap ("operating hours" ~ "support hours"). Hybrid runs both pipelines through the full contract and combines their verdicts: whichever pipeline confidently answers wins, a topic-name anchor breaks a two-answer disagreement, and both refusing refuses. Union recall, and because each pipeline is tuned to zero-wrong, the union stays zero-wrong.
The embedding model was chosen by an eval-backed bake-off (six models, metric = max correct at WRONG = 0, threshold swept, same contract for all):
model | dim | correct | synonym (of 12) | wrong |
lexical (baseline) | n/a | 84 | 3 | 0 |
all-MiniLM-L6-v2 | 384 | 77 | 4 | 0 |
bge-small | 384 | 82 | 4 | 0 |
bge-base | 768 | 85 | 5 | 0 |
bge-large | 1024 | 86 | 7 | 0 |
e5-large | 1024 | 84 | 5 | 0 |
gte-large (chosen) | 1024 | 87 | 8 | 0 |
Two findings worth keeping. First, all-MiniLM-L6-v2 (a common default) was the worst, below lexical, and at a recall-tuned threshold it answered "can your platform spot money laundering patterns?" with check fraud (a Beta capability) at a score higher than a correct answer elsewhere. The eval harness caught that compliance confident-wrong. Model quality is the variable, not the architecture. Second, even the best dense model alone (87) is only +3 over lexical, because dense still misses the proper nouns lexical nails. That is the case for hybrid, which lands at 89, above either alone, still zero-wrong.
The reranker did not earn the default
A cross-encoder rerank stage (--rerank, retrieval/rerank.py) was built and baked off the same way: union candidate generation, then a cross-encoder, then the same contract. It underperformed at zero-wrong: ms-marco-MiniLM 78, bge-reranker-base 81, bge-reranker-large 82, versus the ensemble's 89. A single reranked list plus one threshold cannot match the ensemble's two independently calibrated shots, and MS-MARCO-trained rerankers are not calibrated for a small, terse fact KB (rerankers pay off on large, passage-like candidate sets). It is kept behind --rerank to revisit as the corpus grows; the ensemble stays the default. The eval rejected the technique, which is the point.
Still open (see ARCHITECTURE): the pgvector production store and a constrained LLM composition layer.
Structured / deterministic layer (default; --no-routed to disable)
python3 -m grounded "do you support temenos t24?" # deterministic-first, on by defaultSome questions have exactly one correct value: whether a capability is live or roadmap, whether a certification is held, an uptime SLA, a latency number, a retention period. Those are deterministic, and answering them by similarity search is a needless risk. The router sends them to an exact lookup against structured triples and defers everything open-ended to the probabilistic retrieval path. Two triple kinds today:
Status:
(entity, status, GA|Beta|Roadmap|Not-supported), derived from every fact'sstatus. "Do you support Temenos T24?" comes backexact (deterministic lookup), ROADMAP, not a confidence score.Value: a value question ("what is your uptime SLA?", "what are your operating hours?") maps by distinctive trigger tokens to the one vetted fact that holds the value.
Safety gates keep it from ever weakening the guarantee: status fires only on a uniquely-named entity (ambiguous defers), value fires only on a unique trigger match, and the number guard rides both, so "is SOC 1 certified?" cannot resolve the SOC 2 triple (it defers and refuses). Deterministic routing is on by default and holds zero-wrong on both bases (routed+lexical 85, routed+hybrid 89); on the lexical base it even recovers a synonym miss ("operating hours" resolves deterministically). The triple is just a knowledge-graph (subject, predicate, object); the KB's status field was already one. Next: promote value triples into the KB schema itself rather than a curated declaration.
Faithfulness verifier (--verify, and verify to calibrate)
python3 -m grounded verify # calibrate the gate
python3 -m grounded --verify "..." # answer with the gate onThe run-time twin of the eval gate: a check that an answer's claim is actually entailed by its cited source, run at answer time. It's built now, while it is a deliberate no-op over verbatim answers (the claim is the source), so it can be calibrated on known-good content and trusted before composition ever turns on. On that day the claim is a generated sentence and an unsupported one is vetoed here, before it reaches the buyer. Default is a local NLI cross-encoder (egress-safe, swappable for a MiniCheck-class faithfulness model).
Calibration (verify) proves the two things that make it trustworthy: over real (claim vs its own source) pairs it must not reject known-good answers, and over adversarial (claim vs an unrelated source) pairs it must reject. Current: 0 false-rejects of 85 (100% pass, so it never causes a miss) and 94% rejection of 84 mismatches (5 generic answers weakly entail unrelated sources; tuned when generation exists).
Use it from any agent (MCP)
Grounded is an MCP server, so any MCP client (Claude Desktop, IDEs, other agents) can call it and inherit the guarantee: one tool, grounded_answer(question), returns a vetted, cited, labeled answer or an explicit refusal. It never fabricates, so an agent that calls it cannot be led into a confident wrong answer.
python -m grounded mcp # run the server (stdio)Register it in an MCP client's config (paths are for this repo; adjust to yours):
{
"mcpServers": {
"grounded": {
"command": "/Users/dhirajbhat/.pyenv/versions/3.11.10/bin/python",
"args": ["-m", "grounded.mcp_server"],
"env": { "PYTHONPATH": "/Users/dhirajbhat/Desktop/grounded" }
}
}
}Defaults to routed + lexical (instant start, no model download, no egress). Set GROUNDED_MCP_MODE=hybrid in env for semantic retrieval.
Live watch mode (entity-triggered)
--watch is the live-call form factor. It reads a transcript stream (a file, or stdin) and, for each line, fires only when the line names a known entity (a product, integration, acronym, or competitor the KB knows), then surfaces the grounded card for it. If nothing is vetted, it stays silent. A per-topic cooldown stops the same card firing on every mention.
python3 -m grounded --watch evals/sample_call.txtOn the sample call it surfaces a GA card when the prospect names "Fiserv DNA", a BATTLE CARD when they name a competitor ("SentinelIQ"), a ROADMAP card with a caution for "Temenos T24", and an honest NOT SUPPORTED for "FedRAMP". It says nothing for an unknown competitor ("FalconX") or for chit-chat.
The design is a borrowed pattern with the discipline inverted. A live copilot that fires retrieval on keywords is common; the trick here is that the trigger only starts the lookup, and the same cite-or-refuse engine decides whether anything is safe to show. Trigger on entities, not on question-detection (which is slow and error-prone); ground every surfaced card. The trigger is deliberately high-precision (named entities only), so a capability asked in plain words ("do you do real-time scoring") does not fire; widening the trigger vocabulary is a knob, traded against noise on a live call.
Live call earpiece (real Meet / Zoom, local and private)
--watch proves the form factor over a transcript. The meeting bot takes it
to a real call. It reuses the same engine, so it inherits cite-or-refuse; the only
new part is where the words come from.
python -m grounded meeting-bot fixtures/transcript_gong_acme_bank.txt # replay a call
python -m grounded meeting-bot --list-devices # find the audio tap
python -m grounded meeting-bot --live # real call, local--live captures the call's audio on your own Mac, transcribes it with a local
Whisper model, and whispers a grounded card to you when the buyer asks something
vetted (a refusal on a clear question it cannot vet, silence otherwise). Nothing
leaves the machine: no cloud transcription, no bot in the meeting. Speaker
attribution is free, because the call's output audio is only the other side (your
own mic is never echoed back to you), so every captured utterance is a buyer turn.
It holds "never wrong out loud" through a noisy transcript: when Whisper heard "correlation keystone" for "Corelation Keystone", the curated negative fact still returned NOT SUPPORTED instead of the wrong core. A bad transcript can cause a miss (silence); it does not cause a confident wrong answer. Setup (BlackHole + Multi-Output Device) and the design are in grounded/realtime/README.md. A Recall.ai cloud-bot seam is included for teams that want a joined bot instead.
Knowledge / ingestion layer
python3 -m grounded ingestPulls documents and transcripts from mocked enterprise sources, extracts them, and turns documents into candidate facts with provenance and a freshness class, while mining transcripts only for questions. It runs over mock fixtures (fixtures/); nothing is auth-wired.
Formats: XLSX, PDF, DOCX are extracted for real (openpyxl / pypdf / python-docx). Cloud docs arrive as one of these through a source connector.
Sources: local is real. Google Drive, SharePoint, Office 365, and the transcript/call-intel connectors (Gong, Otter, Granola, Zoom, Sybill, Wispr, Minutes) are mocked: they declare support and return fixtures, but do no auth and make no API calls. Real enterprise auth is a later step, and nothing above the connectors changes when it lands, because everything speaks
RawDoc.Provenance: every candidate fact carries its source system, document, and exact locator (
Capabilities!row5,section: EU data residency,pages 1-1).Freshness: each fact has a TTL by claim class (security 180d, capability 120d, pricing 90d, roadmap 60d, competitor 45d); anything past its TTL is flagged stale.
Source-of-truth conflict detection: when two sources make different claims about the same topic (the Google Sheet says EU residency is Roadmap, the SharePoint doc says GA), the pipeline flags it and holds both out of the served KB for curation instead of silently picking one.
The trust boundary: documents are vettable and can become facts. Transcripts are untrusted (a rep can say something wrong on a call) and never auto-promote to a fact. They are mined for the buyer questions asked, checked against the KB for coverage and gaps, and a human must promote anything.
Promotion (ingestion feeds retrieval)
python3 -m grounded promoteCloses the loop: accepted facts (fresh, non-conflicting) are coverage-gated against the hand-authored KB, and only the ones the KB does not already answer are written to kb/promoted.jsonl and served. Duplicates are skipped; conflicts and stale facts are held. On the fixtures: 16 accepted, 15 skipped as already-covered (semantic dedup catches near-duplicates like "Encryption" vs the existing encrypted-at-rest fact), 1 net-new promoted (Databricks export from the mocked Google Sheet). Before, "do you export to databricks?" refused; after, it answers GA with a citation back to Capabilities!row9. Both evals stay zero-wrong (lexical 84, hybrid 89).
The served KB is kb/*.jsonl (hand-authored) plus kb/promoted.jsonl, kept separate so promotion is auditable and reversible. Known limitation: semantic dedup can false-positive on sibling entities ("ServiceNow case sync" was skipped as matching the Salesforce case-sync fact); entity-aware dedup and curated negative facts are a curation-layer task.
Layout
CONCEPT.md the pitch (thesis, market gap, defensibility)
ARCHITECTURE.md the production design, build order, decision log
grounded/ the package
grounding.py the contract: threshold, guards, labels, refusal <- the product
facts.py the Fact model + KB loader
text.py tokenization + entity (strong-token) detection
render.py CLI + live-surface rendering, staleness
retrieval/lexical.py TF-IDF retriever
retrieval/dense.py gte-large over a vector store
retrieval/store.py VectorStore interface + LanceDB
retrieval/hybrid.py the lexical + dense ensemble (default)
retrieval/rerank.py experimental cross-encoder stage
ingestion/ connectors, extract, factify, freshness, conflict, pipeline
realtime/ the live call earpiece (meeting bot + local Whisper)
cli.py modes (one-shot, REPL, watch, eval, ingest, promote,
meeting-bot, mcp, verify) + entry
kb/*.jsonl vetted facts (fictional Kestrel): qa, capabilities, competitors
kb/promoted.jsonl facts promoted from ingestion (provenance-carrying)
fixtures/ mock docs + transcript for ingestion
evals/eval_set.jsonl the 118-case zero-wrong guardrail
evals/sample_call.txt a sample transcript for --watchNot yet built (see ARCHITECTURE for the full plan)
Constrained LLM composition on top of the verifier (verbatim stays the default until the gate is trusted for generation).
Real enterprise auth for the cloud connectors (mocked today); pgvector production store.
Entity-aware dedup on the promotion path (curation layer).
Multi-tenant, audit trail, own SOC 2.
Available Tools
1 toolgrounded_answerA
Answer a product, integration, security, or commercial question from vetted, cited knowledge, or refuse.
Returns EITHER a grounded answer, carrying a live-vs-roadmap status label (GA / BETA / ROADMAP / NOT SUPPORTED / BATTLE CARD) and a source citation, OR an explicit refusal when nothing is vetted matches. It never fabricates and never presents a roadmap item as live. Call this instead of answering such a question yourself. If it refuses, do not guess: follow up in writing.
| Name | Required | Description | Default |
|---|---|---|---|
| question | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden, and it does so thoroughly. It discloses refusal behavior, the guarantee that it never fabricates, that roadmap items are not presented as live, and the exact response shape (status label plus citation).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences long and front-loaded with the primary purpose. Every sentence adds necessary information: what it answers, what it returns, how it behaves, and how to handle refusals. There is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one parameter, no output schema, and no sibling tools, the description provides everything needed to invoke the tool correctly and interpret its result. It covers input scope, output format, refusal behavior, and follow-up action, making it contextually complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides no description for the single 'question' parameter, so the tool description must compensate. It defines what kinds of questions are appropriate (product, integration, security, commercial) and implies the question is natural language. It does not explicitly state formatting or phrasing requirements, but for a single free-text parameter this is sufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Answer') and resource ('product, integration, security, or commercial question') and clarifies the two possible outcomes: a grounded answer or an explicit refusal. This makes the tool's role clear and distinguishable from simply answering directly, even without sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly instructs the agent to use this tool instead of answering such questions itself and gives follow-up guidance if a refusal occurs: 'Call this instead of answering such a question yourself. If it refuses, do not guess: follow up in writing.' This is direct, actionable usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
With only one tool, there is no possibility of confusing it with another. The tool's purpose is clearly defined and self-contained.
A single tool cannot exhibit naming inconsistencies. 'grounded_answer' is descriptive and follows a readable pattern.
One tool feels thin for most servers, but the narrow scope of grounded question-answering justifies a minimal surface. It falls into the borderline category.
The tool covers the full domain of answering from vetted knowledge, including refusals and citations. There are no obvious missing operations for this purpose.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Governed, auditable knowledge your team curates for its AI assistants, self-hostable
Your company's brain for AI agents. Cited, permission-aware knowledge across every system.
Shared, permission-aware company context for AI agents, with provenance, approvals and audit.
Your team's shared, verified knowledge for AI agents: ask what's true, record what you learn.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceCreates and searches private, local RAG libraries from documentation to ground AI assistants in authoritative sources, reducing hallucinations by providing current, accurate context from your own docs instead of relying on outdated training data.21MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to perform semantic, hybrid, and filtered search on indexed local documentation with RAG capabilities.2MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to crawl, index, and retrieve information from technical documentation using semantic search, with optional knowledge graph validation for code hallucination detection.MIT
- FlicenseNot gradedqualityBmaintenanceEnables traceable, version-aware question answering over product documentation, combining vector and graph retrieval to return cited evidence and support agentic workflows.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/dbhat93/grounded'
If you have feedback or need assistance with the MCP directory API, please join our Discord server