mcp

package
v1.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package mcp is lore's MCP (Model Context Protocol) driving adapter: it exposes lore's grounded retrieval and Q&A use cases as MCP tools so any MCP client (Claude Desktop, editors, agent frameworks) can call a private corpus and get back cited answers. Like internal/cli it is a driving adapter — it wires the same internal/app use cases to a protocol surface (the official Go MCP SDK as transport) and holds no business logic. It is read-only: no add/sync/rm/init tools are registered.

Because it is lore's first long-running process, the storage and provider handles in Deps are opened once by the composition root and reused for the server's lifetime; tool calls hit that warm state and never re-open the DB.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AskInput

type AskInput struct {
	Collections    []string `` /* 130-byte string literal not displayed */
	Question       string   `json:"question" jsonschema:"the question to answer using only these collections"`
	K              int      `json:"k,omitempty" jsonschema:"number of chunks to ground on (default 8)"`
	Budget         int      `json:"budget,omitempty" jsonschema:"cap the grounding to roughly this many tokens, trimming within k (0 = no cap)"`
	Rerank         bool     `` /* 162-byte string literal not displayed */
	Hybrid         bool     `json:"hybrid,omitempty" jsonschema:"fuse BM25 keyword search with vector search (recovers exact-term and identifier matches)"`
	MMR            bool     `json:"mmr,omitempty" jsonschema:"diversify grounding with Maximal Marginal Relevance (single-collection; not with rerank)"`
	Recency        bool     `json:"recency,omitempty" jsonschema:"prefer recently-updated documents via a time decay (not with rerank/mmr)"`
	Where          []string `` /* 136-byte string literal not displayed */
	SourceGlob     string   `json:"source_glob,omitempty" jsonschema:"restrict grounding to documents whose source matches this glob, e.g. '*.pdf'"`
	Strict         bool     `json:"strict,omitempty" jsonschema:"when true, return an error instead of an ungrounded answer if no chunks match"`
	IncludeSources *bool    `json:"include_sources,omitempty" jsonschema:"include each cited chunk's full text in the citations (default true)"`
}

AskInput is the `ask` tool's arguments.

type AskOutput

type AskOutput struct {
	Answer    string     `json:"answer" jsonschema:"the synthesized answer; inline [n] markers reference the citations"`
	Citations []Citation `json:"citations" jsonschema:"the chunks the answer cites, in [n] order"`
	Grounded  bool       `json:"grounded" jsonschema:"false means nothing matched and the answer rests on model knowledge alone"`
}

AskOutput is the `ask` tool's structured result.

type Chunk

type Chunk struct {
	ChunkID     string `json:"chunk_id" jsonschema:"the chunk's ID"`
	Seq         int    `json:"seq" jsonschema:"the chunk's position within its document"`
	HeadingPath string `json:"heading_path,omitempty" jsonschema:"the document section the chunk came from (structure-aware chunkers only)"`
	Text        string `json:"text" jsonschema:"the chunk's stored text"`
}

Chunk is one stored chunk returned by get_chunks (the cat --chunk shape).

type Citation

type Citation struct {
	Ordinal    int    `json:"ordinal" jsonschema:"the [n] marker this citation has in the answer text"`
	Source     string `json:"source" jsonschema:"source URI of the cited document"`
	Seq        int    `json:"seq" jsonschema:"the chunk's position within its document"`
	ChunkID    string `json:"chunk_id" jsonschema:"the cited chunk's ID; pass to get_chunks to fetch it"`
	Collection string `json:"collection,omitempty" jsonschema:"origin collection (set only for multi-collection answers)"`
	Text       string `json:"text,omitempty" jsonschema:"the cited chunk's text (present when include_sources is true)"`
}

Citation is one cited chunk in an answer.

type CollectionInfo

type CollectionInfo struct {
	Name       string `json:"name" jsonschema:"the collection name"`
	Model      string `json:"model" jsonschema:"the embedding model the collection is pinned to"`
	Dimensions int    `json:"dimensions" jsonschema:"the embedding dimensionality"`
	Documents  int    `json:"documents" jsonschema:"number of documents ingested"`
	Chunker    string `json:"chunker" jsonschema:"the pinned chunker spec"`
}

CollectionInfo is one collection's summary in list_collections.

type CollectionStatusInput

type CollectionStatusInput struct {
	Collection string `json:"collection" jsonschema:"the collection to inspect"`
}

CollectionStatusInput is the `collection_status` tool's arguments.

type CollectionStatusOutput

type CollectionStatusOutput struct {
	Name       string `json:"name" jsonschema:"the collection name"`
	Model      string `json:"model" jsonschema:"the embedding model the collection is pinned to"`
	Dimensions int    `json:"dimensions" jsonschema:"the embedding dimensionality"`
	Documents  int    `json:"documents" jsonschema:"number of documents ingested"`
	Chunks     int    `json:"chunks" jsonschema:"number of indexed chunks"`
	Chunker    string `json:"chunker" jsonschema:"the pinned chunker spec"`
	// LastIngestAt is the most recent document ingestion time (RFC3339); it
	// advances on any re-ingest, unlike a collection's birth timestamp. Empty
	// for a collection with no documents.
	LastIngestAt string `json:"last_ingest_at,omitempty" jsonschema:"timestamp of the most recently ingested document; advances on any re-ingest"`
	// CorpusDigest is the corpus content identity (hex sha256 over the document
	// set); it changes on any add, removal, or edit and is the stable handle for
	// a provenance snapshot.
	CorpusDigest string `json:"corpus_digest" jsonschema:"content digest of the document set; changes on any add, removal, or edit"`
}

CollectionStatusOutput is one collection's detailed status, including its chunk count (the field list_collections omits to stay cheap).

type Config

type Config struct {
	// Collections restricts which collections the tools expose, as exact names or
	// globs (path.Match against the collection name). Empty exposes all local
	// collections.
	Collections []string
	// Version is reported to clients in the MCP initialize handshake.
	Version string
}

Config tunes the server: the collection scope and the version reported to clients.

type Deps

type Deps struct {
	Catalog *app.Catalog
	Query   *app.Querier
	Ask     *app.Asker
	// Retriever composes retrieval (hybrid/rerank/mmr/recency/where/cap) for the
	// ask/query tools — the same use case the CLI and eval use.
	Retriever *app.Retriever
	// Rerank is nil when no rerank provider is configured; the ask/query tools
	// return a tool error if rerank is requested in that case (mirroring the CLI).
	Rerank *app.Reranker
	// Tokens backs the ask tool's budget trimming.
	Tokens app.TokenCounter
	// Index backs collection_status's chunk count (read-only; Entries).
	Index app.VectorIndex
}

Deps are the lore use cases the MCP tools invoke, wired by the composition root (via the cli mcp command). They are warm, already-opened handles reused across every tool call.

type GetChunksInput

type GetChunksInput struct {
	Collection string   `json:"collection" jsonschema:"the lore collection the chunks belong to"`
	ChunkIDs   []string `json:"chunk_ids" jsonschema:"the chunk IDs to fetch; unknown IDs are omitted from the result"`
}

GetChunksInput is the `get_chunks` tool's arguments.

type GetChunksOutput

type GetChunksOutput struct {
	Chunks []Chunk `json:"chunks" jsonschema:"the found chunks, in request order; absent IDs are omitted"`
}

GetChunksOutput is the `get_chunks` tool's structured result.

type Hit

type Hit struct {
	Text        string   `json:"text" jsonschema:"the chunk's text"`
	Source      string   `json:"source" jsonschema:"source URI of the chunk's document"`
	Score       float64  `json:"score" jsonschema:"vector similarity score (higher is more similar)"`
	ChunkID     string   `json:"chunk_id" jsonschema:"the chunk's ID; pass to get_chunks to fetch it again"`
	Seq         int      `json:"seq" jsonschema:"the chunk's position within its document"`
	Collection  string   `json:"collection,omitempty" jsonschema:"origin collection (set only for multi-collection queries)"`
	RerankScore *float64 `json:"rerank_score,omitempty" jsonschema:"cross-encoder relevance score (present only when rerank was used)"`
}

Hit is one retrieved chunk in the query result (the standard lore hit object plus its origin collection).

type ListCollectionsInput

type ListCollectionsInput struct{}

ListCollectionsInput is empty — list_collections takes no arguments.

type ListCollectionsOutput

type ListCollectionsOutput struct {
	Collections []CollectionInfo `json:"collections" jsonschema:"the collections this server exposes"`
}

ListCollectionsOutput is the `list_collections` tool's structured result.

type QueryInput

type QueryInput struct {
	Collections []string `json:"collections" jsonschema:"the lore collection name(s) to search; at least one, all sharing one embedding space"`
	Query       string   `json:"query" jsonschema:"the search text"`
	K           int      `json:"k,omitempty" jsonschema:"number of chunks to return (default 8)"`
	SourceGlob  string   `json:"source_glob,omitempty" jsonschema:"restrict to documents whose source matches this glob, e.g. '*.pdf'"`
	Rerank      bool     `` /* 162-byte string literal not displayed */
	Hybrid      bool     `json:"hybrid,omitempty" jsonschema:"fuse BM25 keyword search with vector search (recovers exact-term and identifier matches)"`
	MMR         bool     `json:"mmr,omitempty" jsonschema:"diversify results with Maximal Marginal Relevance (single-collection; not with rerank)"`
	Recency     bool     `json:"recency,omitempty" jsonschema:"prefer recently-updated documents via a time decay (not with rerank/mmr)"`
	Where       []string `` /* 126-byte string literal not displayed */
}

QueryInput is the `query` tool's arguments.

type QueryOutput

type QueryOutput struct {
	Hits []Hit `json:"hits" jsonschema:"the matching chunks, best first"`
}

QueryOutput is the `query` tool's structured result.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is lore's configured MCP server: the SDK server with lore's tools registered, plus the scope it enforces. Build it with New, then serve over stdio (ServeStdio) or Streamable HTTP (ServeHTTP).

func New

func New(deps Deps, cfg Config, logger *slog.Logger) (*Server, error)

New builds the server, validating the collection scope and registering every read-only tool. A nil logger discards logs (never writes to stdout).

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(ctx context.Context, addr, token string) error

ServeHTTP serves the MCP protocol over the SDK's Streamable HTTP transport, bound to addr. A bare ":port" (empty host) is bound to 127.0.0.1 — local by default. When token is non-empty every request must carry "Authorization: Bearer <token>". Binding to a non-loopback host without a token is refused (a usage error), so a network-exposed server is never unauthenticated. The server stays up across tool failures and shuts down gracefully on ctx cancel.

func (*Server) ServeStdio

func (s *Server) ServeStdio(ctx context.Context) error

ServeStdio serves the MCP protocol over stdin/stdout until the client disconnects or ctx is cancelled. stdout carries JSON-RPC only — logs go to the injected logger (stderr), never stdout, so the protocol stream stays clean.

A startup failure (Connect) is returned. Once serving, the client closing the pipe (EOF) or ctx being cancelled (SIGINT) is normal stdio termination and returns nil; only a genuine mid-session transport error is surfaced.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL