feat(llm/tools): split read_note into get_note and get_content_note

This commit is contained in:
Elian Doran
2026-04-03 18:42:00 +03:00
parent 98c70e662d
commit be724ec45f
3 changed files with 39 additions and 7 deletions

View File

@@ -2341,7 +2341,8 @@
"mcp_enabled_description": "Expose a Model Context Protocol (MCP) endpoint so that AI coding assistants (e.g. Claude Code, GitHub Copilot) can read and modify your notes. The endpoint is only accessible from localhost.",
"tools": {
"search_notes": "Search notes",
"read_note": "Read note",
"get_note": "Get note",
"get_note_content": "Get note content",
"update_note_content": "Update note content",
"append_to_note": "Append to note",
"create_note": "Create note",

View File

@@ -113,7 +113,8 @@ describe("mcp", () => {
const body = parseSseResponse(response.text);
const toolNames: string[] = body.result.tools.map((t: { name: string }) => t.name);
expect(toolNames).toContain("search_notes");
expect(toolNames).toContain("read_note");
expect(toolNames).toContain("get_note");
expect(toolNames).toContain("get_note_content");
expect(toolNames).toContain("create_note");
expect(toolNames).not.toContain("get_current_note");
});
@@ -142,10 +143,26 @@ describe("mcp", () => {
expect(content[0].text).toContain(noteId);
});
it("reads a note by ID", async () => {
it("gets note metadata by ID", async () => {
const response = await mcpPost(app)
.send(jsonRpc("tools/call", {
name: "read_note",
name: "get_note",
arguments: { noteId }
}))
.expect(200);
const body = parseSseResponse(response.text);
expect(body.result).toBeDefined();
const parsed = JSON.parse(body.result.content[0].text);
expect(parsed.noteId).toBe(noteId);
expect(parsed.type).toBeDefined();
expect(parsed.attributes).toBeDefined();
});
it("reads note content by ID", async () => {
const response = await mcpPost(app)
.send(jsonRpc("tools/call", {
name: "get_note_content",
arguments: { noteId }
}))
.expect(200);

View File

@@ -5,6 +5,7 @@
import { z } from "zod";
import becca from "../../../becca/becca.js";
import mappers from "../../../etapi/mappers.js";
import markdownExport from "../../export/markdown.js";
import markdownImport from "../../import/markdown.js";
import noteService from "../../notes.js";
@@ -84,7 +85,22 @@ export const noteTools = defineTools({
}
},
read_note: {
get_note: {
description: "Get a note's metadata by its ID. Returns title, type, mime, dates, parent/child relationships, and attributes. Does NOT return the note's content — use get_note_content for that.",
inputSchema: z.object({
noteId: z.string().describe("The ID of the note to retrieve")
}),
execute: async ({ noteId }) => {
const note = becca.getNote(noteId);
if (!note) {
return { error: "Note not found" };
}
return mappers.mapNoteToPojo(note);
}
},
get_note_content: {
description: "Read the full content of a note by its ID. Use search_notes first to find relevant note IDs. Text notes are returned as Markdown.",
inputSchema: z.object({
noteId: z.string().describe("The ID of the note to read")
@@ -100,8 +116,6 @@ export const noteTools = defineTools({
return {
noteId: note.noteId,
title: note.getTitleOrProtected(),
type: note.type,
content: getNoteContentForLlm(note)
};
}