index-upsert
Create or update notes under a specific key, enabling indexing, tagging, and metadata management. Supports full-text search and knowledge graph generation for efficient note retrieval and concept relationships.
Instructions
Create or update a note under a key. Returns the note id.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| backup | No | ||
| content | Yes | ||
| id | No | Optional note id to update | |
| key | Yes | ||
| metadata | No | ||
| tags | No |
Implementation Reference
- src/mcp.ts:38-60 (registration)Registration of the 'index-upsert' tool in the tools array, including name, description, and input schema definition.{ name: 'index-upsert', description: 'Create or update a note under a key. Returns the note id.', inputSchema: { type: 'object', properties: { id: { type: 'number', description: 'Optional note id to update' }, key: { type: 'string' }, content: { type: 'string' }, tags: { type: 'array', items: { type: 'string' } }, metadata: { type: 'object' }, backup: { type: 'object', properties: { enabled: { type: 'boolean' }, dir: { type: 'string' }, }, }, }, required: ['key', 'content'], additionalProperties: true, }, },
- src/mcp.ts:1219-1227 (handler)MCP tool handler for 'index-upsert': parses arguments using UpsertSchema, calls db.upsert(), optionally creates backup, and returns the note ID.case 'index-upsert': { const parsed = UpsertSchema.parse(args); const id = db.upsert(parsed); if (parsed.backup?.enabled) { const file = writeBackup(db.exportAll(), parsed.backup.dir); return { content: [{ type: 'text', text: JSON.stringify({ id, backup: file }) }] }; } return { content: [{ type: 'text', text: JSON.stringify({ id }) }] }; }
- src/types.ts:27-30 (schema)Zod schema definition for input validation of the upsert operation, extending NoteSchema with optional id and backup.export const UpsertSchema = NoteSchema.extend({ id: z.number().int().positive().optional(), backup: BackupOptionsSchema.optional(), });
- src/db.ts:86-115 (handler)Core implementation of upsert in NotesDB (SQLite backend): handles update if id provided, insert otherwise, with JSON serialization for tags/metadata and timestamps.upsert(note: Note & { id?: number }): number { logger.debug({ note }, 'Upserting note'); if (note.id) { const stmt = this.db.prepare( `UPDATE notes SET key=@key, content=@content, tags=@tags, metadata=@metadata, updated_at=datetime('now') WHERE id=@id` ); const info = stmt.run({ id: note.id, key: note.key, content: note.content, tags: JSON.stringify(note.tags ?? []), metadata: JSON.stringify(note.metadata ?? {}), }); if (info.changes === 0) { throw new Error(`Note with id ${note.id} not found`); } return note.id; } else { const stmt = this.db.prepare( `INSERT INTO notes (key, content, tags, metadata) VALUES (@key, @content, @tags, @metadata)` ); const info = stmt.run({ key: note.key, content: note.content, tags: JSON.stringify(note.tags ?? []), metadata: JSON.stringify(note.metadata ?? {}), }); return Number(info.lastInsertRowid); } }
- src/store.lite.ts:46-79 (helper)Fallback in-memory upsert implementation in LiteNotesStore: updates or adds to array, updates MiniSearch index, persists to JSON.upsert(note: Note & { id?: number }): number { const now = new Date().toISOString(); if (note.id) { const idx = this.notes.findIndex((n) => n.id === note.id); if (idx === -1) throw new Error(`Note with id ${note.id} not found`); const updated: Note = { ...this.notes[idx], key: note.key, content: note.content, tags: note.tags ?? [], metadata: note.metadata ?? {}, updated_at: now, }; this.notes[idx] = updated; this.ms.replace(updated); this.persist(); return updated.id!; } else { const id = this.nextId++; const created: Note = { id, key: note.key, content: note.content, tags: note.tags ?? [], metadata: note.metadata ?? {}, created_at: now, updated_at: now, }; this.notes.push(created); this.ms.add(created); this.persist(); return id; } }