Repository navigation
2.1.0
[2.1.0] - 2026-09-21
Added
-
πππ Knowledge base + MCP server (opt-in, MariaDB 11.8+ only) πππ β store documents grouped by topic; llamaman chunks them (~1200 chars, paragraph-aligned, 200 overlap), embeds them through a llama.cpp instance launched with Embedding model enabled, and stores the vectors in a MariaDB
VECTORcolumn with aDISTANCE=cosineindex. One code path, three ways in:- Settings β MCP tab β enable toggles, embedding-model picker, topic list (filter by name, delete), test search, Re-embed everything, and (with Expose over MCP on) a Copy config.json button that copies a ready-to-paste
mcpServersblock for this endpoint, including anAuthorization: Bearer <your-api-key>placeholder when Require Authentication is on. - REST under
/api/kb/*β status, settings, topics (optionally created as a given API key's private topic), documents (list/get/add/delete), search, re-embed + status. Admin-only: UI sessions and cluster peers are accepted, requests authenticated with an API key get 403 (keys use the MCP endpoint). - MCP endpoint at
POST /mcp/knowledgeβ JSON-RPC 2.0, protocol revisions 2025-06-18 / 2025-03-26 / 2024-11-05. Read-only tools:kb_list_topics,kb_list_documents,kb_search,kb_get_document. Mutating tools, each behind its own setting (off by default) and hidden fromtools/listwhile off:kb_ingest_document(creates the topic if missing; 200 KB per call; one ingest at a time, others get "ingest busy, retry shortly") andkb_delete_document/kb_delete_topic(topic delete cascades to its documents; irreversible).
How it behaves:
- Adding documents goes through
POST /api/kb/documentsor the MCPkb_ingest_documenttool β the MCP tab lists and deletes topics but has no add form. A document is keyed by topic + title; resubmitting identical content (sha256) is a no-op that skips embedding. - Search embeds the query with the same model and returns matched passages, best first, with a score clamped to 0β1 (
max(0, 1 - cosine_distance/2)). Searching before anything has been embedded returns "knowledge base is empty". - Embedding model is chosen by model name, not instance: the dropdown lists every embedding-enabled instance across the cluster, deduplicated by name. An embed call uses a healthy matching instance on this node; failing that, wakes a sleeping/stopped one on this node, or waits for one that is already starting; failing that, forwards to a peer that has both Knowledge base and Expose over MCP turned on and has the model running there (or asleep, stopped or starting there, in which case that peer wakes it or waits for it); failing that, relaunches the model on the node that last served it (at most 3 attempts per model per 10 minutes β once that budget is spent and another attempt fails, the remembered node is forgotten). Otherwise it fails with "no live embedding instance".
- Timeouts: embed calls use a 5 s connect / 30 s read timeout (60 s read for peer-forwarded calls), so a hung embedding server produces an error rather than a request that never returns. Local embed calls are recorded in the request log (
kb-embed); peer-forwarded ones are logged on the peer. - Dimension lock: the first embed records the vector dimension. An embed or search that produces a different dimension is refused with a prompt to run Re-embed everything. Only the dimension is checked β switching to a different model with the same dimension is not detected, so re-embed manually when you change models.
- Re-embed clears all chunks and re-embeds every document in a background job with progress reporting. One job per process; the table drop/recreate on a dimension change is guarded by a cluster-wide MariaDB
GET_LOCK. Re-embedding an empty KB leaves the dimension lock untouched.
Access modes (
kb_mcp_access, MCP access in the tab):- Global (default) β every MCP client works on the shared pool: it sees all shared topics and, if ingest/delete are allowed, can change them. New topics go into the shared pool. Keys' private topics (created in Per API key mode) are not visible in Global mode.
- Per API key β every MCP request needs an API key, even with Require Authentication off. Topics a key creates are private to that key. Each key also sees the shared pool (topics created in Global mode or through the UI/REST) read-only: it can search and read it, but ingest or delete there is refused. Another key's topics and documents come back as "not found", and responses carry a
sharedflag instead of key IDs. Switching modes never moves or deletes data. After switching Global β Per API key, everything already in the knowledge base stays visible to every key as the shared pool. After switching Per API key β Global, private topics stay private (hidden from all clients) and reappear for their keys when you switch back; the admin UI always shows everything. The MCP tab labels each topicsharedor with its owning key's name.
Settings (seven keys):
kb_enabled,kb_mcp_enabled,kb_mcp_access(global|per_key),kb_mcp_ingest,kb_mcp_delete,kb_embedding_model, andkb_embedding_instance(selects an instance by ID on the local node; only used when no model name is set).Auth: in Global mode
/mcp/knowledgefollows the app-wide Require Authentication setting β on means a valid API-key bearer is required, off means the endpoint is open. In Per API key mode a valid key is always required, and cluster peers (which carry no key) are refused. API keys are still not restricted to the knowledge base: a key that can use MCP can also call the inference endpoints. The MCP tab shows the endpoint URL on port 42069 (the route is registered on the app, so it also answers on 5000).Off means off: with the feature disabled,
/mcp/knowledgereturns 404 in both access modes, and a strict-backend test verifies no request path touches anykb_*storage method. There is no migration: thekb_*tables are created lazily on first use and only on MariaDB. On the JSON backend or MariaDB older than 11.8 the tab shows a banner saying why, and enabling is refused. KB data is cluster-wide (not node-scoped); each node's heartbeat advertises its KB/MCP flags. #96 - Settings β MCP tab β enable toggles, embedding-model picker, topic list (filter by name, delete), test search, Re-embed everything, and (with Expose over MCP on) a Copy config.json button that copies a ready-to-paste