shared-docs-mcp
Corpus — shared docs + agentic RAG for two coding agents
One Postgres-backed knowledge base with three doors into it:
MCP server (
:8765) — both coding agents connect here with their own API keys, upload docs, and search/ask over everything.Web app (
:8000) — a React SPA (TypeScript, Tailwind, shadcn-style components) over a JSON API: dashboard, document management, hybrid search with visible retrieval ranks, and a streaming cited chat.Postgres + pgvecto.rs — the single source of truth. Agents and humans see the same corpus, filtered by RBAC.
Agent A ──┐ ┌── chunks: vector(1536) + tsvector
Agent B ──┼── MCP :8765 ──┐ │
│ ├── core ──┼── documents (owner, visibility, tags)
Humans ───┴── Web :8000 ──┘ └── users / api_keys / chat history
(React SPA + SSE)The RAG pipeline
Stage | What it does | Why it matters |
Chunking | Markdown header-aware with section paths; code split at function/class boundaries; sentence-boundary windows with overlap elsewhere | Chunks are coherent units, not arbitrary 512-token slices |
Contextual embeddings | Embeds | Cheap version of contextual retrieval; big recall lift on doc corpora |
Hybrid retrieval | pgvecto.rs HNSW cosine + Postgres full-text, fused with RRF (k=60) | Keyword side catches exact identifiers ( |
Answering | Everything is an agent (the | An agent that sees its own empty search result can rephrase; a fixed pipeline can't |
Chunk-level citations | Every chunk carries a permanent 8-char | Clicking a citation scrolls to the exact passage and flashes it. Keys are persistent, so citations in saved chat history still resolve months later |
Dedupe | content SHA-256 per owner | Agents re-uploading the same doc is a no-op |
Two agents, one entry point (core/rag/answer.py routes; both are
deepagents graphs, so one toolset, one trace format, one streaming driver):
fast (
fast.py) — a single agent with the corpus tools and a low recursion cap (~5 searches max). No subagents, no todo list. Seconds.deep (
deep_agent.py) — an orchestrator that plans withwrite_todos, keeps anotes.mdscratchpad, and delegates to three sharply differentiated subagents: scout (fast orientation: what does the corpus even contain), researcher (deep dive on one question, several run in parallel), and verifier (adversarial fact-check of the draft: SUPPORTED / UNSUPPORTED / CONTRADICTED / OVERSTATED, PASS or REVISE). Tens of seconds, ~10–40× the cost.
auto picks with a deliberately conservative heuristic (comparative
vocabulary, multiple questions, long briefs); users override with
Auto / Fast / Deep pills, agents with mode= or the deep_research MCP tool.
If a deep run fails it falls back to the fast path rather than erroring.
Design notes: docs/DEEP_AGENT_RAG.md.
Role-scoped agent tools. The toolset each agent run receives mirrors the
caller's web role (core/rag/agent_tools.py::TOOL_ROLES): viewers get the
read-only set (search_corpus, read_document, list_corpus_documents,
think); editors add save_note (persist a research synthesis back into the
corpus, tagged agent-note); admins add documentation_gaps (what people
asked that got no answer). Capabilities are also enforced server-side — the
table is UX, not the security boundary. whoami over MCP reports the tools a
key's role grants.
Streaming. POST /api/ask is an SSE stream: mode → (step | token)*
→ done. Tool calls stream as pipeline steps (search: "retry policy",
delegate → researcher: …), tokens stream as they're generated, and the
done event carries the authoritative answer + resolved citations — so token
streaming is progressive enhancement, never the source of truth. The MCP
server uses the synchronous ask() on the same engines.
Relevance floor. A bare ORDER BY distance LIMIT k always returns k rows,
so uncovered questions would yield confident-looking noise. Dense hits beyond
RETRIEVAL_MIN_SIMILARITY are dropped, which makes "we found nothing"
possible — and that is what feeds the dashboard's documentation gaps panel
(questions the corpus couldn't answer, aggregated by frequency and people).
Five people asking about deploy rollback and finding nothing isn't a search
problem, it's a missing document. The default floor is provider-aware: the
offline dev embedding needs a much higher floor than a real model.
Related MCP server: astra-knowledge-base-mcp
The web app (webapp/ui)
React 18 + TypeScript + Vite + Tailwind v4, shadcn-style primitives over
Radix, TanStack Query for data, Recharts for the dashboard, dark/light theme.
Django 5 (ASGI) serves the built SPA and owns everything under /api; auth
is a signed-cookie session, so the browser never holds a token. Data access is
the Django ORM over managed = False models (core/models.py) — schema.sql
stays the DDL source of truth because pgvecto.rs columns and generated tsvector
columns don't round-trip through Django migrations. Raw SQL survives only
where the ORM can't speak: the hybrid-retrieval hot path (<=>, RRF) and two
aggregates. All configuration is one typed pydantic-settings model
(core/config.py) that both Django and the MCP server consume.
Dashboard — corpus stats, 30-day charts, composition by tag, per-agent activity, an activity feed, and the documentation-gaps panel.
Chat — SSE streaming with live pipeline steps, mode pills, a collapsible trace panel, and citation chips with hover previews that deep-link to the exact chunk.
Search — hybrid results with visible
vec #/kw #/rrfranks, so retrieval quality is debuggable at a glance.Documents — upload (file or paste), tag, filter, edit (content edits re-chunk + re-embed), delete.
Doc viewer — rendered markdown with a sticky TOC, related docs (centroid similarity) + backlinks, "Ask about this doc", and a "chunk seams" toggle that overlays exactly how the doc was cut for retrieval.
People & access (admin) — team table with role changes, password resets, enable/disable/unlock, dormant-account flags (60 days), agent-key minting and revocation, and the audit log (who did what to whom, with before/after values on role changes).
RBAC & user abstraction
Everything resolves to a Principal (user + role + connection path):
Web session → Principal via email + password (Argon2id, stored in Postgres). Login is throttled: 8 failed attempts locks the account for 15 minutes, and failures are deliberately indistinguishable so the form can't be used to discover which emails are registered.
MCP API key → Principal via the key's bound user. Agents are users.
OAuth 2.1 access token → Principal via the user who approved the client. For MCP clients that only speak OAuth and have nowhere to paste a key: the web app is the authorization server, so the client is sent to the ordinary Corpus login plus a consent screen, and the token it receives is bound to whoever said yes. There is no service account and no default admin — an OAuth client is exactly as privileged as the human behind it. PKCE is mandatory, clients enrol themselves via Dynamic Client Registration (RFC 7591), tokens are opaque and stored only as sha256, and a user can disconnect a client from their account page. See
core/oauth.py.
Roles: viewer (search/chat) < editor (+ upload, delete own) < admin
(+ manage people, roles, keys, delete anything). Documents are org
(visible to all) or private (owner only) — enforced in every SQL query,
so MCP tools and web API can't leak across the boundary.
Vector engine: pgvecto.rs
The schema uses pgvecto.rs
(CREATE EXTENSION vectors) with an HNSW cosine index. Two things to know:
The extension lives in the
vectorsschema; the schema and the connection pool both put it on thesearch_pathso unqualifiedvector,<=>, andavg(embedding)resolve.The app sends embeddings as text (
'[1,2,3]'::vector) and never reads vector values back, so there is no client-side type adapter and no reliance on engine-specific implicit casts.
Run it from tensorchord/pgvecto-rs:pg16-v0.3.0 (both compose files do).
Migrating an existing pgvector/VectorChord install:
migrations/008_pgvecto_rs.sql (rewrites the column type — take a backup).
Quick start
Zero-config (offline, no accounts needed):
bash run_local.shWrites a dev .env, builds the UI once (needs node), starts Postgres + web
(:8000) + MCP (:8765). Open the site and create the first account — it becomes
the admin. Embeddings run on an offline hashing stand-in, so retrieval works
but has no semantics; chat returns top passages until you add
a GOOGLE_API_KEY. If a local postgres owns 5432:
SDR_DB_PORT=5434 bash run_local.sh. Optionally seed sample docs:
.venv/bin/python scripts/dev_seed.pyFull local setup (real retrieval + chat):
cp .env.example .env # fill in keys (see below)
docker compose up -d # Postgres + pgvecto.rs, schema auto-applied
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
(cd webapp/ui && npm ci && npm run build)
uvicorn server.asgi:application --reload --port 8000 # terminal 1
python -m mcp_server.server # terminal 2UI development with hot reload: cd webapp/ui && npm run dev (Vite on :5173,
proxying /api to :8000).
Required in .env:
GOOGLE_API_KEY— Gemini embeddings (gemini-embedding-001) and chat answers (gemini-2.5-flash), the defaults. Swap providers per layer:EMBEDDINGS_PROVIDER=openai|voyage|dev,ANSWER_PROVIDER=anthropic(thenANTHROPIC_API_KEY).
Then: create the first account (admin) → People → mint keys for agent-a
and agent-b → wire them into each agent per
docs/mcp-client-setup.md.
Deploy to production
bash deploy.sh # on any Ubuntu VM: installs docker, builds, starts, health-checksEverything ships from one Dockerfile: stage 1 builds the React UI, stage 2
is the Python image that runs as both the web app (default command) and the
MCP server (compose overrides the command). Full stack in containers — Caddy
(auto-TLS on your domain), web, MCP, Postgres (internal-only, named volume).
https://DOMAIN/ is the web app, https://DOMAIN/mcp is what the agents
connect to. See docs/DEPLOYMENT.md.
MCP tools
upload_document · search_docs · ask_docs (with mode=) ·
deep_research · list_documents · read_document · delete_document ·
whoami
Changing the embedding model
Keep three things in sync: EMBEDDINGS_MODEL, EMBEDDINGS_DIM, and the
vector(1536) column in schema.sql. Changing dimension requires
re-ingesting (drop the chunks table or ALTER COLUMN ... TYPE vector(N)
then re-upload).
Layout
core/ config, db pool, security (Principal/RBAC/API keys),
oauth (OAuth 2.1 authorization server for MCP clients),
citations (cite_key → deep link), analytics
core/rag/ chunking · embeddings · ingest · retrieve (hybrid+RRF)
fast (lean agent) · deep_agent (orchestrator+subagents)
agent_tools (per-principal toolset) · answer (routing+SSE)
mcp_server/ FastMCP HTTP server (the agents' door)
server/ Django (ASGI): settings from pydantic, JSON API + SSE,
serves the built SPA
core/models.py ORM models (managed=False — schema.sql owns the DDL)
webapp/ui/ React SPA (Vite + TS + Tailwind + shadcn-style)
schema.sql applied automatically by docker compose on first boot
migrations/ for existing installs (008 = move to pgvecto.rs)
docs/ deployment, MCP client setup, deep-agent design notesThis server cannot be installed
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 Servers
- Alicense-qualityDmaintenanceLocal MCP server for indexing personal knowledge into SQLite with hybrid search, chunk-level citations, memory tools, and agent orchestration.4MIT
- AlicenseAqualityBmaintenanceMCP server for managing and searching multi-tenant knowledge bases backed by SQLite with FTS5, enabling AI agents to persist and retrieve content via full-text search.131MIT
- AlicenseAqualityDmaintenanceMCP server for semantic code indexing using vector embeddings, enabling AI agents to maintain persistent memory of codebases through natural language queries and intelligent chunking.19764MIT
- Alicense-qualityDmaintenanceA knowledge base MCP server backed by Qdrant vector database with local embeddings for semantic search and document management.11ISC
Related MCP Connectors
User-owned memory for AI agents, Copilot, Claude, IDEs, CLIs, and chat apps over remote MCP.
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
Shared, peer-validated knowledge archive for AI agents — search, contribute, and validate via MCP
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/yashpapa6969/shared-docs-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server