fix: MCP servers — broken INSERT into dropped type column, stale content refs

The previous schema sync (86f43c9) was incomplete — it renamed variables
but left the SQL statements writing to `type` and `content` columns that
no longer exist in the schema. Fresh installs crash on first node create.

nodeService.js:
- Remove `type` from INSERT/UPDATE, replace with `event_date`
- Fix `content` → `notes` in INSERT values and UPDATE SET clauses
- Add `sanitizeTitle()` and chunk fallback logic

sqlite-client.js:
- Remove `is_pinned` from CREATE TABLE
- Add `description` and `icon` to dimensions table

index.js:
- Add temporal filter fields to search schema
- Improved description prompts
- Dynamic date injection in instructions

server.js + stdio-server.js:
- Add content→notes mapping in update handlers
- Fix output returning `notes` instead of `content`
- Add extraction tool schemas and handlers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
“BeeRad”
2026-02-16 09:16:51 +11:00
co-authored by Claude Opus 4.6
parent 2f6518207d
commit 7c6197fc0d
5 changed files with 335 additions and 52 deletions
@@ -90,38 +90,61 @@ function getNodeById(id) {
};
}
/**
* Sanitize title — strip extraction artifacts.
*/
function sanitizeTitle(title) {
let clean = title.trim();
if (clean.startsWith('Title: ')) clean = clean.slice(7);
if (clean.endsWith(' / X')) clean = clean.slice(0, -4);
clean = clean.replace(/\s+/g, ' ');
return clean.slice(0, 160);
}
/**
* Create a new node.
*/
function createNode(nodeData) {
const {
title,
title: rawTitle,
description,
notes,
link,
type,
event_date,
dimensions = [],
chunk,
metadata = {}
} = nodeData;
const title = sanitizeTitle(rawTitle);
const now = new Date().toISOString();
const db = getDb();
// Build chunk fallback from available fields when no explicit chunk provided
let chunkToStore = chunk ?? null;
if (!chunkToStore || !chunkToStore.trim()) {
const fallbackParts = [title, description, notes].filter(Boolean);
const fallback = fallbackParts.join('\n\n').trim();
if (fallback) {
chunkToStore = fallback;
}
}
const nodeId = transaction(() => {
const stmt = db.prepare(`
INSERT INTO nodes (title, description, notes, link, type, metadata, chunk, created_at, updated_at)
INSERT INTO nodes (title, description, notes, link, event_date, metadata, chunk, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
const result = stmt.run(
title,
description ?? null,
content ?? null,
notes ?? null,
link ?? null,
type ?? null,
event_date ?? null,
JSON.stringify(metadata),
chunk ?? null,
chunkToStore,
now,
now
);
@@ -146,11 +169,11 @@ function createNode(nodeData) {
/**
* Update an existing node.
* Note: content is APPENDED by default (MCP tool behavior), not replaced.
* Note: notes is APPENDED by default (MCP tool behavior), not replaced.
*/
function updateNode(id, updates, options = {}) {
const { appendNotes = true } = options;
const { title, description, notes, link, type, dimensions, chunk, metadata } = updates;
const { title, description, notes, link, event_date, dimensions, chunk, metadata } = updates;
const now = new Date().toISOString();
const db = getDb();
@@ -172,23 +195,23 @@ function updateNode(id, updates, options = {}) {
setFields.push('description = ?');
params.push(description);
}
if (content !== undefined) {
if (notes !== undefined) {
if (appendNotes && existing.notes) {
// Append to existing content
setFields.push('content = ?');
params.push(existing.notes + '\n\n' + content);
// Append to existing notes
setFields.push('notes = ?');
params.push(existing.notes + '\n\n' + notes);
} else {
setFields.push('content = ?');
params.push(content);
setFields.push('notes = ?');
params.push(notes);
}
}
if (link !== undefined) {
setFields.push('link = ?');
params.push(link);
}
if (type !== undefined) {
setFields.push('type = ?');
params.push(type);
if (event_date !== undefined) {
setFields.push('event_date = ?');
params.push(event_date);
}
if (chunk !== undefined) {
setFields.push('chunk = ?');
@@ -60,8 +60,7 @@ function initDatabase() {
embedding BLOB,
embedding_updated_at TEXT,
embedding_text TEXT,
chunk_status TEXT DEFAULT 'not_chunked',
is_pinned INTEGER DEFAULT 0
chunk_status TEXT DEFAULT 'not_chunked'
);
CREATE TABLE IF NOT EXISTS edges (
@@ -71,7 +70,6 @@ function initDatabase() {
source TEXT,
created_at TEXT,
context TEXT,
FOREIGN KEY (from_node_id) REFERENCES nodes(id) ON DELETE CASCADE,
FOREIGN KEY (to_node_id) REFERENCES nodes(id) ON DELETE CASCADE
);
@@ -89,6 +87,8 @@ function initDatabase() {
CREATE TABLE IF NOT EXISTS dimensions (
name TEXT PRIMARY KEY,
description TEXT,
icon TEXT,
is_priority INTEGER DEFAULT 0,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);