Skip to content

Latest commit

 

History

History
214 lines (167 loc) · 8.23 KB

File metadata and controls

214 lines (167 loc) · 8.23 KB

rag-gateway MCP reference (Step 3.3)

Overview

The gateway exposes the same Phase 2 pipeline as a set of Model Context Protocol tools, so LLM agents (Claude Desktop, IDE assistants, anything that speaks MCP) can drive the full RAG stack — retrieve, query, ingest — without a bespoke HTTP/gRPC client.

The server is built on the official mcp Python SDK (mcp.server.fastmcp.FastMCP) and transported over stdio. There is one implementation, in Python (rag_gateway.mcp); the @ragplatform/mcp npm package is a thin launcher that shells out to it (see the launcher README).

Server name: ragplatform.

Tool REST equivalent Returns
query POST /v1/query answer (when generate=true) + citations + routing summary
retrieve POST /v1/retrieve fused chunk references + routing summary
ingest POST /v1/ingest/document per-document ingest outcome

Every call must carry a tenant_id; results are tenant-scoped.

Usage

Run the server

# Directly
python -m rag_gateway.mcp

# Via the npm launcher (shells out to the Python server)
npx -y @ragplatform/mcp

Wire it into an MCP client (e.g. Claude Desktop claude_desktop_config.json):

{
  "mcpServers": {
    "ragplatform": {
      "command": "npx",
      "args": ["-y", "@ragplatform/mcp"]
    }
  }
}

ragctl smoke command

uv run ragctl mcp-query "what is RAG?" --tenant acme --generate

Drives an in-memory MCP client/server session — no stdio process, no infrastructure. Mirrors ragctl query (REST) and ragctl grpc-query (gRPC) so the three surfaces stay in lock-step.

ragctl mcp-serve runs the blocking stdio server (the same entry point as python -m rag_gateway.mcp).

Tool catalogue

query

End-to-end RAG: understand → route → optional rerank → optional pack → optional generate.

Argument Type Default Notes
query string required
tenant_id string required; empty → error
principal_id string mcp-anon recorded on the RequestContext
corpus_ids string[] restrict to these corpora
top_k int 5 candidates to retrieve/rerank
rerank bool true run the two-stage reranker
pack bool true run the context packer
pack_budget int 2048 token budget for packing
generate bool false call the LLM for an answer
generate_max_tokens int 1024 LLM cap when generate=true
generate_temperature float 0.0 LLM temperature

Returns McpQueryResult: request_id, query, shape, bm25_fallback, answer (null unless generate=true and chunks were retrieved), citations (each: index, chunk_id, document_id, source_uri, excerpt, score), chunks_n, chunk_refs_n, total_ms. Citation index matches the bracket markers in answer.

retrieve

Retrieval only — understand → route, returning fused chunk references and the routing decision without rerank/pack/LLM.

Argument Type Default
query string required
tenant_id string required
principal_id string mcp-anon
corpus_ids string[]
top_k int 5

Returns McpRetrieveResult: request_id, query, shape, bm25_fallback, chunk_refs (each: chunk_id, corpus_id, score), total_ms.

ingest

Ingest a single text document into a corpus through the full pipeline (parse → chunk → enrich → PII → embed → store).

Argument Type Default Notes
corpus_id string required
tenant_id string required
content string required; UTF-8 text, empty → error
principal_id string mcp-anon
filename string informational; used for MIME sniffing
mime_type string overrides MIME detection
source_uri string defaults to upload:///<filename>

Returns McpIngestResult: document_id, status, chunk_count, embedding_count, blocked_chunk_count, bytes_in, error.

Tool argument ↔ request-model parity

The query / retrieve tool arguments are kept field-for-field in sync with rag_core.gateway_types.QueryRequest / RetrieveRequest (minus the two deferred fields below). A conformance test (tests/contract/test_mcp_tool_compat.py) fails CI if a request-model field is added without a matching tool argument:

  • filters — structured filter expressions are deferred from the MCP surface (mirrors the gRPC Query shape); revisit when an agent use case needs them.
  • request_id — minted fresh per tool call (an MCP client has no request-id concept), so it is never caller-supplied.

Error envelope

Domain failures are raised as MCP ToolError, so the client receives a result with isError = true and a content text of the form code: message — the same code + message carried by the REST GatewayError body and the gRPC trailing-metadata envelope. All three surfaces report identical failure modes; only the transport differs.

Trigger Detail prefix
missing tenant_id AUTH_ERROR: tenant_id is required
empty ingest content INVALID_ARGUMENT-class ValueError: empty document content
ACLDeniedError ACL_DENIED: …
RateLimitError RATE_LIMITED: …
RetrievalError RETRIEVAL_ERROR: …

RagError subclasses contribute their .code; non-RagError exceptions fall back to the class name.

Observability

Structured-log events emitted via rag-observability (same extra={"event_kind": …} pattern as the REST + gRPC surfaces):

  • mcp.server_built — one per build_mcp_server call.
  • mcp.server_listening — emitted by serve() before the stdio loop.
  • mcp.query_complete — one per successful query tool call.
  • mcp.ingest_complete — one per successful ingest tool call.

Internals

The implementation lives under apps/gateway/src/rag_gateway/mcp/:

  • server.pybuild_mcp_server(...) factory, the three @mcp.tool registrations, serve(...) stdio entry point, and the error mapping.
  • backend.py — the ToolBackend Protocol (the seam) + InProcessBackend (composes the Phase 2 pipeline directly, reusing rag_gateway.query's answer/citation helpers).
  • types.py — the lean agent-facing output models + projection functions.
  • __main__.pypython -m rag_gateway.mcp.

build_mcp_server accepts the same composition kwargs as rag_gateway.app.build_app, so a single set of SPI implementations serves REST + gRPC + MCP in one process. Defaults pull from the shared build_default_* helpers.

Extension points

  • Backend topology: pass a ready ToolBackend to build_mcp_server to fully control execution. The current default is InProcessBackend; a future GatewayClientBackend (HTTP client to a running gateway) slots in at this seam without touching the tool layer. See ADR-0012.
  • PolicyEngine: threaded through to the same egress_text consult used by REST in _generate_answer — see architecture/policy-engine.md.
  • LLM / reranker / packer / understanding / router / ingest pipeline: each is an injectable kwarg on build_mcp_server.

See also