governed-rag-mcp
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., "@governed-rag-mcpSearch for information about access control in our knowledge base."
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.
Governed RAG MCP
Governed RAG MCP is a small Python reference implementation for governed retrieval over the Model Context Protocol (MCP). It exposes a deliberately narrow FastMCP server over stdio: exactly three tools and one machine-readable resource.
The retrieval core is synchronous. Pydantic validates requests at the boundary, an environment-bound source ACL constrains search scope, and strict confidence mode returns NO_RELEVANT_CONTEXT instead of passing through weak context. Hybrid retrieval combines SQLite FTS5 and sqlite-vec rankings with Reciprocal Rank Fusion (RRF).
This project is suitable for evaluation, local integration, and as a basis for further hardening. Operators still own identity binding, process isolation, index provenance, dependency review, backups, and deployment controls.
Engineering evidence
Verified locally on 2026-08-10; every value is reproduced by make ci:
Gate | Verified result |
Unit, integration, and real MCP | 47 passed |
Branch-aware Python coverage | 87.59% (minimum gate: 80%) |
Repository dogfooding | HitRate@5 = 1.00; MRR = 1.00; 6/6 modules at rank 1; ACL denial PASS |
Static contracts | Ruff clean; strict mypy clean |
Dependency audit | 0 known vulnerabilities reported by |
Publication guard | PASS; no secret value is emitted in its report |
Container smoke | healthy; UID/GID 10001; read-only filesystem and no network required |
The evaluation corpus is this repository itself. The golden suite asks about RRF, ACL, grounding, Pydantic contracts, safe ingestion, and telemetry, then verifies that retrieval lands on the corresponding implementation file. Tests are deliberately excluded from the search corpus so the expected query text cannot leak into its own answer.
Related MCP server: policy-corpus
Why this architecture is production-oriented
Small protocol surface: three read-only tools and one resource over MCP
stdio.Fail-closed boundaries: Pydantic rejects malformed input, ACL is bound outside tool payloads, and weak evidence is withheld with an explicit absence reason.
Hybrid retrieval with provenance: FTS5 and
sqlite-vecstay independently measurable; RRF combines ranks without pretending their raw score scales are equivalent.Atomic offline indexing: allowlisted inputs build a shadow database that replaces the serving index only after completion and integrity verification.
Observable without content capture: telemetry is aggregate-only and never records query or chunk text.
Reproducible verification: CI runs typing, lint, coverage, E2E, retrieval metrics, dependency audit, publication audit, and a non-root container build.
Production-oriented does not mean universally production-ready. The operator must still bind identity, isolate trust domains, protect index provenance, and apply the limits documented below.
Public surface
The MCP surface is intentionally fixed.
Type | Name | Purpose |
Tool |
| Search authorized knowledge using hybrid, FTS-only, or vector-only retrieval. |
Tool |
| Return source classes and aggregate chunk counts, never chunk text. |
Tool |
| Return index integrity, aggregate inventory, and process-local aggregate telemetry. |
Resource |
| Describe the transport, tools, resource, retrieval methods, governance controls, and synchronous runtime as JSON. |
There are exactly three tools. Index construction is an offline operation, not an MCP tool.
search_knowledge
Argument | Type | Default | Constraint |
| string | required | Visible text, 1-500 characters. |
| integer |
| 1-20 results. |
| string |
|
|
| string |
|
|
| string or null |
| Optional scope matching |
| string |
|
|
Results carry their source path, line range, project, confidence level, branch scores, and text_is_untrusted_context: true. The server returns retrieved text; it does not generate an answer or make retrieved instructions trustworthy.
In strict mode, low-confidence candidates are removed. If no candidate remains, the response status is exactly NO_RELEVANT_CONTEXT, with an explicit reason such as strict_blocked_low, acl_denied, plane_failed, or no_results.
Architecture at a glance
flowchart LR
H[MCP host] -->|stdio| M[FastMCP server]
M --> P[Pydantic boundary]
P --> A[Environment-bound ACL]
A --> S[Synchronous search service]
S --> F[SQLite FTS5]
S --> V[sqlite-vec]
F --> R[Reciprocal Rank Fusion]
V --> R
R --> G[Confidence gate]
G --> O[Results or NO_RELEVANT_CONTEXT]
S --> T[Aggregate telemetry]See Architecture, Threat model, and Architecture Decision Records.
Quickstart
Local virtual environment
Prerequisites: Python 3.11 or newer, a C-compatible Python environment for sqlite-vec, and GNU Make.
make setup
. .venv/bin/activate
make demo
make testmake demo builds a deterministic index from the repository's explicit public allowlist. It is dogfooding: only approved source and documentation paths are read. Symlinks, oversized files, NUL-containing content, invalid UTF-8, and recognized secret or private-path patterns fail the ingest.
Run the stdio server against the generated index:
GOVERNED_RAG_CLIENT_PROFILE=restricted \
GOVERNED_RAG_INDEX=data/knowledge.sqlite \
.venv/bin/governed-rag-mcpAn MCP host launches that command and exchanges protocol messages over stdin and stdout. Do not place ordinary log output on stdout.
Example host configuration:
{
"mcpServers": {
"governed-rag": {
"command": ".venv/bin/governed-rag-mcp",
"env": {
"GOVERNED_RAG_CLIENT_PROFILE": "restricted",
"GOVERNED_RAG_INDEX": "data/knowledge.sqlite"
}
}
}
}Relative paths are resolved from the server process working directory. Use deployment-appropriate absolute paths in real host configuration without committing machine-specific paths.
Docker
The image builds its deterministic allowlisted index during docker build and runs the server as a non-root user:
docker build --tag governed-rag-mcp:local .
docker run --rm -i \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=16m \
--security-opt no-new-privileges \
--env GOVERNED_RAG_CLIENT_PROFILE=restricted \
governed-rag-mcp:localKeep -i: MCP uses stdin and stdout. The packaged index is queried read-only.
Access control
GOVERNED_RAG_CLIENT_PROFILE is a deployment binding, not a caller-supplied tool argument. A missing, empty, or unknown value resolves to restricted; it never expands access.
Profile | Explicitly searchable sources |
|
|
|
|
|
|
For source=all, config is excluded even for auditor and must be requested explicitly. An unauthorized explicit source returns NO_RELEVANT_CONTEXT with acl_denied and no results.
The profile applies to the server process. If callers require different trust levels, run separately configured processes and bind identity outside this server. list_knowledge_sources and rag_status return aggregate source names and counts; they do not apply per-result ACL filtering.
Retrieval and grounding
FTS5: searchable terms are converted to quoted literals and passed through parameterized SQL.
Vector:
sqlite-vecperforms nearest-neighbor retrieval using the configured embedder.Hybrid: both ranked lists are merged with RRF (
k0=60) before the result limit is applied.Confidence: agreement between both branches is high confidence; a single FTS hit or sufficiently close vector hit is medium; weaker vector-only hits are low.
Strict behavior: low-confidence candidates are withheld rather than presented as grounded context.
Degradation: if embedding fails during hybrid search, FTS results may still be returned with degraded coverage. Vector-only embedding failure returns
NO_RELEVANT_CONTEXTwithplane_failed.
Coverage always states which sources were queried or skipped by ACL. It lists failed sources when the failure path can attribute them; hybrid embedding degradation is instead represented by degraded and degraded_reason. Treat coverage as part of the result contract, not optional diagnostics.
Embedding providers
The default hashing embedder is deterministic and dependency-free. It exists only for tests and the public self-indexing demo; it is not a substitute for a semantic embedding model and its retrieval quality is intentionally limited.
Set GOVERNED_RAG_EMBEDDING_PROVIDER=ollama to use the optional Ollama adapter. Ollama receives the complete text being embedded, including queries and indexed chunks, so its endpoint is a separate privacy and availability boundary. The adapter accepts HTTPS endpoints, or HTTP only for localhost and loopback IP literals; it rejects embedded credentials, query strings, and fragments.
Variable | Default | Meaning |
|
| SQLite index path. |
| restricted on missing or invalid input | Process-wide ACL profile. |
|
|
|
|
| Demo hashing-vector dimensions. |
|
| Ollama embeddings endpoint. |
|
| Ollama model name. |
|
| Expected Ollama vector dimensions. |
The query embedder must match the model and dimensions used to build the index. Rebuild the index when either changes.
Telemetry
Telemetry is aggregate-only and process-local. It records request count, average latency, and counters by profile, requested source, response status, and winning source. It does not record query text or chunk text. Counters reset when the process restarts and are exposed through rag_status.
Aggregate telemetry reduces content exposure but is not anonymous usage analytics. Profile and source counters can still reveal coarse usage patterns to callers that can invoke rag_status.
Honest limits
stdioprovides no network authentication, authorization, TLS, or rate limiting. Those controls belong at the process or gateway boundary.The environment profile is not user identity and is not suitable by itself for mixed-trust callers sharing one process.
ACLs operate at source-class granularity, not per document, row, tenant, or field.
Aggregate inventory from
list_knowledge_sourcesandrag_statusis not filtered by caller profile.The index has an integrity check but no built-in signature, origin attestation, encryption, retention policy, or backup workflow.
Retrieved chunks are untrusted context. Downstream hosts must resist prompt injection and enforce their own tool policies.
The allowlist and pattern checks reduce accidental publication; they are not a complete secret-detection system.
Optional Ollama availability and privacy depend on the configured endpoint.
The deterministic hashing embedder is a demo mechanism with limited semantic quality.
Search is synchronous and intended for bounded local workloads; benchmark with representative data before deployment.
Project documents
Available Tools
3 toolslist_knowledge_sourcesA
List source classes and chunk counts without returning chunk text.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It clearly states that the tool lists source classes and chunk counts and explicitly notes that it does NOT return chunk text—a key behavioral limitation. This is adequate for a read-only listing operation, though it doesn't mention any other side effects or prerequisites.
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 a single clear sentence with no filler. It conveys the main purpose and a key limitation efficiently, making it easy to parse and act upon.
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?
While the output schema provides return structure, the description gives enough context for such a simple tool with no parameters. It doesn't define what 'source classes' exactly means, but the sibling tool names and the idea of knowledge sources provide adequate context. The omission of chunk text is explicitly addressed.
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?
There are zero parameters, so the schema provides no parameter details. The description adds meaningful context about the output (source classes and chunk counts) and the exclusion of chunk text, which helps the agent understand what the tool offers despite having no inputs to configure.
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 uses a specific verb ('List') and names the resource ('knowledge sources') with a clear output scope ('source classes and chunk counts'). The clarification 'without returning chunk text' differentiates it from the sibling search_knowledge tool, which likely returns chunk contents.
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?
The description implies its use for obtaining an overview of sources without chunk text, but it does not explicitly state when to use this tool versus siblings like search_knowledge or rag_status. There is no direct comparison or exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rag_statusA
Return safe aggregate health and telemetry without query or chunk text.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the transparency burden. It discloses that the operation is 'safe' (implying read-only) and 'aggregate' (indicating summary rather than raw data), and explicitly states it does not return query or chunk text. These details go beyond a minimal description, though it lacks specifics on what health metrics are included, which is likely covered by the output schema.
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 a single, front-loaded sentence: 'Return safe aggregate health and telemetry without query or chunk text.' It contains zero filler words and every phrase adds value, making it highly concise and well-structured.
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 the tool's low complexity (no parameters), the presence of an output schema, and a description that clearly conveys its purpose and boundaries, the description is complete enough for an agent to understand when and how to invoke it. The statement 'without query or chunk text' provides crucial context for distinguishing it from sibling tools.
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 tool has zero parameters, so schema coverage is effectively 100% with nothing to explain. The baseline for zero parameters is 4, and the description correctly avoids any parameter-related claims that might be misleading.
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 clearly states the tool returns 'safe aggregate health and telemetry,' which is a specific verb+resource combination. It also distinguishes itself from siblings by noting it operates 'without query or chunk text,' differentiating it from search_knowledge and list_knowledge_sources.
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?
The description provides clear context: use this tool for aggregate health and telemetry, and it explicitly mentions it does not involve query or chunk text, implying it is not for content retrieval. However, it does not name alternative tools explicitly or provide a formal 'when to use' statement, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_knowledgeA
Search governed knowledge. Low-confidence context is removed in strict mode.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | hybrid | |
| limit | No | ||
| query | Yes | ||
| source | No | all | |
| project | No | ||
| confidence | No | strict |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds one behavioral detail: 'Low-confidence context is removed in strict mode.' This is useful and not apparent from the schema. However, without annotations, the description should disclose more (e.g., permissions, read-only nature, pagination), which it does not.
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 two sentences, front-loaded with the core purpose, and the second sentence adds valuable behavioral context. No filler or redundancy.
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?
With 6 parameters and no annotations, this description is too sparse. The output schema may define return values, but the description does not explain the tool's capabilities (e.g., filtering by source, project, or mode) well enough for an agent to use it effectively.
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 has 0% description coverage, so the description must compensate for parameter meaning. It clarifies that 'strict' (the confidence parameter) removes low-confidence context, but it does not explain mode, source, project, or limit parameters. This leaves a significant gap.
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 'Search governed knowledge' uses a specific verb and resource, clearly distinguishing it from sibling tools like list_knowledge_sources and rag_status. The action and object are immediately clear.
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?
Usage is implied by the verb 'search', but no explicit guidance is given on when to use this tool vs. listing sources or checking rag status. Alternatives are not mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v0.1.0- First observed
list_knowledge_sources - First observed
rag_status - First observed
search_knowledge
TDQS
Scored across 3 tools
Each tool has a distinct purpose: listing source metadata, checking system status, and performing search. There is no overlap or ambiguity between them.
Two tools use verb_noun naming (list_knowledge_sources, search_knowledge), while rag_status follows a noun_noun pattern. The inconsistency is minor and does not hinder readability.
Three tools is a reasonable count for a focused RAG server that provides search and monitoring capabilities. While on the small side, it is neither too sparse nor overwhelming.
The surface covers core operations: listing sources, searching, and checking status. Missing management operations like adding/removing sources may be out of scope for a governed read-only interface.
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 data discovery, exact queries, decisions, simulations, and runtime utilities over MCP.
Read-only MCP for identity resolution and write guardrails.
Read-only MCP tools for AI agent discovery, structured resources, and NIULAI information.
Read-only MCP access to a documented IT fleet: state, changes, posture. 15 tools.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceProvides hybrid retrieval (dense + BM25 + RRF) with collection-based isolation and document ingestion for private knowledge access via MCP.MIT
- FlicenseNot gradedqualityBmaintenanceRead-only MCP server providing 5 tools for hybrid search, clause retrieval, policy versioning, code lookup, and plan rider override queries over a synthetic medical-policy corpus.-
- FlicenseNot gradedqualityCmaintenanceProvides read-only, citation-backed semantic search and retrieval-augmented generation over enterprise documents via standardized MCP tools, with local embeddings for privacy.-
- FlicenseAqualityCmaintenanceProvides read-only MCP tools to search and retrieve evidence-grounded knowledge compiled from video content, including hybrid semantic and lexical search with citations.5-
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/Rlealbarili/governed-rag-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server