Add MCP server, note mutation endpoint, and updated_at tracking (v3.0.0)

New MCP server (mcp/) exposes kb operations as native MCP tools over
Streamable HTTP with Bearer token auth. Supports collections via tag
conventions, chunked file uploads, and agent-side search patterns.

Engine gains PATCH /api/v1/notes/{id} for in-place note updates with
transactional re-chunk/re-embed, and updated_at column on documents.

Go client adds updatenote command and Patch HTTP method.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 21:34:55 +01:00
parent adeba21712
commit e7136a4a20
32 changed files with 1679 additions and 8 deletions
@@ -0,0 +1,79 @@
# Engine API (Delta)
## ADDED Requirements
### Requirement: Note mutation endpoint
The engine SHALL provide a `PATCH /api/v1/notes/{id}` endpoint for updating existing notes in place. See the `note-mutation` spec for full details.
#### Scenario: Note update endpoint exists
- **WHEN** a client sends `PATCH /api/v1/notes/42` with body `{"text": "new content"}`
- **THEN** the engine SHALL process the update synchronously and return the updated document
---
### Requirement: Document updated_at tracking
The engine SHALL track when documents are modified via an `updated_at` column. This column SHALL be NULL for documents that have never been updated.
#### Scenario: New document has no updated_at
- **WHEN** a document is first ingested
- **THEN** `updated_at` SHALL be NULL and `created_at` SHALL be set to the ingestion timestamp
#### Scenario: Note update sets updated_at
- **WHEN** a note is updated via `PATCH /api/v1/notes/{id}`
- **THEN** `updated_at` SHALL be set to the current timestamp
#### Scenario: Tag change sets updated_at
- **WHEN** tags are modified via `PUT /api/v1/documents/{id}/tags`
- **THEN** `updated_at` SHALL be set to the current timestamp
#### Scenario: Schema migration for updated_at
- **WHEN** the engine starts against a v2 database without an `updated_at` column
- **THEN** the engine SHALL automatically add `ALTER TABLE documents ADD COLUMN updated_at TEXT` and all existing documents SHALL have `updated_at = NULL`
## MODIFIED Requirements
### Requirement: Document management
The engine SHALL provide endpoints to list, inspect, remove, and download original files for ingested documents.
#### Scenario: List documents
- **WHEN** a client sends `GET /api/v1/documents`
- **THEN** the engine SHALL return a JSON array of documents with id, title, doc_type, tags, chunk_count, created_at, and updated_at
#### Scenario: List documents with filters
- **WHEN** a client sends `GET /api/v1/documents?type=pdf&tags=manual`
- **THEN** the engine SHALL return only documents matching all specified filters
#### Scenario: List documents sorted by most recent
- **WHEN** a client requests documents sorted by date
- **THEN** the engine SHALL use `COALESCE(updated_at, created_at)` for ordering, so un-mutated documents sort by creation time and mutated documents sort by their last update
#### Scenario: Get document details
- **WHEN** a client sends `GET /api/v1/documents/{id}`
- **THEN** the engine SHALL return the full document record including all chunks, their text content, `updated_at`, and whether the original file is available (`has_file: true/false`)
#### Scenario: Download original file
- **WHEN** a client sends `GET /api/v1/documents/{id}/file`
- **THEN** the engine SHALL return the original file with appropriate Content-Type and `Content-Disposition: attachment; filename="{original_filename}"` headers, or HTTP 404 if the file is not available
#### Scenario: Remove a document
- **WHEN** a client sends `DELETE /api/v1/documents/{id}`
- **THEN** the engine SHALL delete the document, all its chunks, associated embeddings, tag associations, and the stored original file from disk, and return HTTP 200 with a confirmation
#### Scenario: Remove non-existent document
- **WHEN** a client sends `DELETE /api/v1/documents/{id}` with a non-existent ID
- **THEN** the engine SHALL return HTTP 404
### Requirement: Engine status and reindex
The engine SHALL provide status information and support re-embedding all chunks. The `version` field in the status response SHALL always be present and SHALL reflect the engine's release version as read from the `VERSION` file. This field is the contract used by clients for compatibility checking.
#### Scenario: Get engine status
- **WHEN** a client sends `GET /api/v1/status`
- **THEN** the engine SHALL return JSON with `version` (string, from VERSION file), model_name, embedding_dim, GPU device info, database stats (document count by type, total chunks, DB size), and queue stats (queued/processing job count)
#### Scenario: Trigger reindex
- **WHEN** a client sends `POST /api/v1/reindex`
- **THEN** the engine SHALL re-embed all existing chunks using the `enriched_text` column and the currently loaded model, and return progress information. This operation SHALL NOT block search queries.