Latest changes all archived

This commit is contained in:
2026-04-04 22:50:19 +01:00
parent e9a282ddb1
commit 223ff2cf5d
31 changed files with 748 additions and 7 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-04-04
@@ -0,0 +1,39 @@
## Context
The MCP server (`mcp/server.py`) exposes KB operations as tools for LLM clients. Collections are an abstraction over tags — internally stored with a `collection:` prefix. The server already has helpers for managing collection tags (`_collection_tag`, `_ensure_exclusive_collection`, `_strip_collection_tags`) and the engine client (`mcp/engine.py`) already has an `update_tags()` method.
Document deletion is supported by the engine API at `DELETE /api/v1/documents/{doc_id}` but has no corresponding engine client method or MCP tool.
## Goals / Non-Goals
**Goals:**
- Expose collection assignment for existing documents via MCP (`kb_set_collection`)
- Expose document deletion via MCP (`kb_delete`)
- Follow existing patterns in `server.py` and `engine.py`
**Non-Goals:**
- Bulk operations (multi-document collection assignment or deletion)
- Tag management beyond collections (direct tag add/remove via MCP)
- Undo/recycle bin for deleted documents
- Changes to the engine API layer — all endpoints already exist
## Decisions
### 1. Reuse `_ensure_exclusive_collection` for kb_set_collection
The server already has `_ensure_exclusive_collection(doc_id, collection)` which removes any existing `collection:*` tags and applies the new one. The `kb_set_collection` tool will use this directly when a collection is provided, and manually remove collection tags when clearing.
**Alternative considered**: Exposing raw tag add/remove to the LLM. Rejected because it leaks the `collection:` prefix implementation detail and the LLM could create inconsistent state (multiple collections on one document).
### 2. New `engine.delete_document()` method for kb_delete
Add a simple `delete_document(doc_id)` to `mcp/engine.py` that calls `DELETE /api/v1/documents/{doc_id}`. This follows the same pattern as all other engine client methods.
### 3. Return confirmation with document metadata on delete
`kb_delete` will return the response from the engine API which includes `{"status": "deleted", "document_id": ..., "title": ...}`. This gives the LLM confirmation of what was deleted without needing a separate get call.
## Risks / Trade-offs
- **[Accidental deletion]** → The LLM could delete the wrong document. Mitigation: the tool requires an explicit `document_id`, and the response includes the title so the LLM can verify. No bulk delete is exposed.
- **[Collection cleared unexpectedly]** → Passing `collection=None` to `kb_set_collection` removes collection assignment. Mitigation: the parameter description will make this behavior explicit.
@@ -0,0 +1,25 @@
## Why
LLMs using the KB MCP server can create notes in collections and search by collection, but cannot assign existing documents to a collection or delete documents. This forces users to drop out to the HTTP API for routine document management. Both operations are fully supported at the database and HTTP API layers but aren't wired through to MCP tools.
## What Changes
- Add `kb_set_collection` MCP tool — assigns, changes, or removes the collection on an existing document by manipulating `collection:` prefixed tags via the existing `engine.update_tags()` method.
- Add `kb_delete` MCP tool — deletes a document by ID, calling the existing `DELETE /api/v1/documents/{doc_id}` endpoint via a new `engine.delete_document()` method.
## Capabilities
### New Capabilities
- `mcp-document-management`: MCP tools for modifying and deleting existing documents (kb_set_collection, kb_delete).
### Modified Capabilities
_(none — the engine API endpoints already exist; this change only adds MCP tool wrappers)_
## Impact
- **MCP server** (`mcp/server.py`): Two new tool registrations.
- **MCP engine client** (`mcp/engine.py`): One new method (`delete_document`). The `update_tags` method already exists and will be reused.
- **Engine API**: No changes — `DELETE /api/v1/documents/{doc_id}` and `PUT /api/v1/documents/{doc_id}/tags` already exist.
- **Breaking changes**: None. Additive only.
@@ -0,0 +1,61 @@
## ADDED Requirements
### Requirement: Set collection on existing document via MCP
The MCP server SHALL expose a `kb_set_collection` tool that assigns or changes the collection of an existing document. The tool SHALL accept a `document_id` (required) and `collection` (optional string). When `collection` is provided, the tool SHALL ensure the document belongs to exactly that collection by removing any existing `collection:*` tags and adding the new one. When `collection` is omitted or null, the tool SHALL remove all `collection:*` tags from the document, leaving it unassigned.
The tool SHALL return the updated document with the `collection` field and cleaned tags (collection tags stripped), consistent with other MCP tool responses.
#### Scenario: Assign untagged document to a collection
- **WHEN** `kb_set_collection` is called with `document_id=42` and `collection="workspace"`
- **THEN** the document SHALL have the tag `collection:workspace` added
- **AND** the response SHALL include `"collection": "workspace"`
#### Scenario: Change document from one collection to another
- **WHEN** `kb_set_collection` is called with `document_id=42` and `collection="memory"` on a document currently in collection "documents"
- **THEN** the tag `collection:documents` SHALL be removed and `collection:memory` SHALL be added
- **AND** the response SHALL include `"collection": "memory"`
#### Scenario: Remove document from all collections
- **WHEN** `kb_set_collection` is called with `document_id=42` and no `collection` parameter
- **THEN** all `collection:*` tags SHALL be removed from the document
- **AND** the response SHALL include `"collection": null`
#### Scenario: Document not found
- **WHEN** `kb_set_collection` is called with a `document_id` that does not exist
- **THEN** the tool SHALL return an error response indicating the document was not found
### Requirement: Delete document via MCP
The MCP server SHALL expose a `kb_delete` tool that permanently deletes a document from the knowledge base. The tool SHALL accept a `document_id` (required integer). Deletion SHALL remove the document, its chunks, embeddings, tags, and any stored file on disk.
The tool SHALL return a confirmation response including the deleted document's ID and title.
#### Scenario: Successful deletion
- **WHEN** `kb_delete` is called with `document_id=42`
- **THEN** the document, its chunks, embeddings, tag associations, and stored file SHALL be deleted
- **AND** the response SHALL include `"status": "deleted"`, the `document_id`, and the document `title`
#### Scenario: Document not found
- **WHEN** `kb_delete` is called with a `document_id` that does not exist
- **THEN** the tool SHALL return an error response indicating the document was not found
### Requirement: Engine client delete method
The MCP engine client (`mcp/engine.py`) SHALL provide a `delete_document(doc_id)` method that sends a `DELETE` request to `/api/v1/documents/{doc_id}` and returns the JSON response. The method SHALL raise on non-2xx status codes, consistent with other engine client methods.
#### Scenario: Successful engine client delete call
- **WHEN** `delete_document(42)` is called and the engine API returns 200
- **THEN** the method SHALL return the parsed JSON response
#### Scenario: Engine client delete for missing document
- **WHEN** `delete_document(999)` is called and the engine API returns 404
- **THEN** the method SHALL raise an `httpx.HTTPStatusError`
@@ -0,0 +1,12 @@
## 1. Engine Client
- [x] 1.1 Add `delete_document(doc_id)` method to `mcp/engine.py`
## 2. MCP Tools
- [x] 2.1 Add `kb_set_collection` tool to `mcp/server.py`
- [x] 2.2 Add `kb_delete` tool to `mcp/server.py`
## 3. Verification
- [x] 3.1 Test kb_set_collection and kb_delete against running engine