Production-grade RAG (Retrieval-Augmented Generation) MCP server built with C# and .NET, exposing document search, retrieval, and ingestion tools with tenant-scoped security and multi-strategy retrieval (vector, structural, graph-based).
SmartDocs MCP server demonstrates solid foundational quality with clear naming conventions (verb_noun pattern: search, get_chunk, graph_search, ingest) and comprehensive parameter descriptions. All 6 tools have descriptions and input schemas with typed parameters. However, critical gaps exist: (1) duplicate tool names ('search' appears twice with different implementations), creating LLM disambiguation confusion; (2) output schemas are not explicitly documented in the source, return types are inferred from code (e.g., ChunkLookupResult, IReadOnlyList<RetrievalResult>) but not formally declared in tool metadata; (3) cancellationToken parameter appears in 4 tools but is not a standard MCP pattern and adds noise to the interface; (4) error handling lacks actionable recovery guidance, ChunkLookupResult.NotFoundOrDenied deliberately obscures the reason (not-found vs denied), which prevents LLMs from self-correcting; (5) no explicit rate limiting, timeout guidance, or per-tool permission declarations. The ingest tool correctly flags itself as WRITE with security warnings, but lacks dry-run or confirmation patterns. Descriptions average ~150 chars (within baseline 194), but lack dependency hints and when-to-use guidance.
Fetch a single chunk by its stable ChunkId (e.g. 'hr-vacation#0'). Read-only. Returns not-found-or-denied when the id does not exist or is outside the caller's clearance.
Search the SmartDocs knowledge graph and return LazyGraphRAG subgraph summaries for questions that span multiple entities or relationships. Read-only. Results are scoped to the caller's clearance.
WRITE TOOL — mutates the corpus and widens the security surface. Queues free-text content for ingestion into a silo and returns a tracking id. Unlike the read-only search tools, enabling this lets a client add content that later searches will surface; gate, audit, or omit it accordingly.
Search the in-memory docs corpus and return up to K matching entries.
Search the SmartDocs corpus and return up to K of the most relevant chunks. Read-only. Results are scoped to the caller's clearance.
Duplicate tool name 'search' (DocsSearchTool vs SearchTool) creates LLM disambiguation ambiguity. LLMs cannot distinguish between in-memory substring search and full corpus semantic search without reading descriptions carefully.
Output schemas not formally documented. Return types (ChunkLookupResult, RetrievalResult, DocHit) are inferred from code but not declared in tool metadata. LLMs cannot plan downstream tool calls without knowing response structure.
Error handling lacks actionable recovery guidance. ChunkLookupResult.NotFoundOrDenied deliberately conflates not-found and denied cases, preventing LLMs from self-correcting or suggesting alternatives.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 61 | 2026-07-28+ | v2 |
Search the SmartDocs corpus and return the top-K reranked chunks (the default, highest-quality search). Read-only. Results are scoped to the caller's clearance.
CancellationToken parameter in 4 tools (get_chunk, graph_search, ingest, search) is not standard MCP and adds interface noise. MCP handles cancellation via protocol-level mechanisms, not tool parameters.
No explicit permission declarations or scope metadata. Tools reference ITenantContext and security filters internally, but do not expose required permissions (e.g., 'read:docs', 'write:corpus') to the agent.