diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-04-13 12:29:57 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-04-13 12:31:10 +0000 |
| commit | e5bacda644ae8b421e9b056bcde4fd57548899c1 (patch) | |
| tree | 195112503b5b543350b6ee6654b1a0a47d4b9d66 /apps/mcp/src | |
| parent | 1f92ced36ec0af11ec0d10bee6aa2474b46462b6 (diff) | |
| download | karakeep-e5bacda644ae8b421e9b056bcde4fd57548899c1.tar.zst | |
fix(mcp): Reduce token usage of the MCP server
Diffstat (limited to 'apps/mcp/src')
| -rw-r--r-- | apps/mcp/src/bookmarks.ts | 129 | ||||
| -rw-r--r-- | apps/mcp/src/shared.ts | 7 |
2 files changed, 129 insertions, 7 deletions
diff --git a/apps/mcp/src/bookmarks.ts b/apps/mcp/src/bookmarks.ts index bcafba91..04e4480d 100644 --- a/apps/mcp/src/bookmarks.ts +++ b/apps/mcp/src/bookmarks.ts @@ -1,7 +1,89 @@ import { CallToolResult } from "@modelcontextprotocol/sdk/types"; import { z } from "zod"; -import { karakeepClient, mcpServer, toMcpToolError } from "./shared"; +import { KarakeepAPISchemas } from "@karakeep/sdk"; + +import { + karakeepClient, + mcpServer, + toMcpToolError, + turndownService, +} from "./shared"; + +interface CompactBookmark { + id: string; + createdAt: string; + title: string; + summary: string; + note: string; + content: + | { + type: "link"; + url: string; + description: string; + author: string; + publisher: string; + } + | { + type: "text"; + sourceUrl: string; + } + | { + type: "media"; + assetId: string; + assetType: string; + sourceUrl: string; + } + | { + type: "unknown"; + }; + tags: string[]; +} + +function compactBookmark( + bookmark: KarakeepAPISchemas["Bookmark"], +): CompactBookmark { + let content: CompactBookmark["content"]; + if (bookmark.content.type === "link") { + content = { + type: "link", + url: bookmark.content.url, + description: bookmark.content.description ?? "", + author: bookmark.content.author ?? "", + publisher: bookmark.content.publisher ?? "", + }; + } else if (bookmark.content.type === "text") { + content = { + type: "text", + sourceUrl: bookmark.content.sourceUrl ?? "", + }; + } else if (bookmark.content.type === "asset") { + content = { + type: "media", + assetId: bookmark.content.assetId, + assetType: bookmark.content.assetType, + sourceUrl: bookmark.content.sourceUrl ?? "", + }; + } else { + content = { + type: "unknown", + }; + } + + return { + id: bookmark.id, + createdAt: bookmark.createdAt, + title: bookmark.title + ? bookmark.title + : ((bookmark.content.type === "link" + ? bookmark.content.title + : undefined) ?? ""), + summary: bookmark.summary ?? "", + note: bookmark.note ?? "", + content, + tags: bookmark.tags.map((t) => t.name), + }; +} // Tools mcpServer.tool( @@ -44,7 +126,7 @@ machine learning is:fav`), return { content: res.data.bookmarks.map((bookmark) => ({ type: "text", - text: JSON.stringify(bookmark), + text: JSON.stringify(compactBookmark(bookmark)), })), }; }, @@ -71,7 +153,7 @@ mcpServer.tool( content: [ { type: "text", - text: JSON.stringify(res.data), + text: JSON.stringify(compactBookmark(res.data)), }, ], }; @@ -100,7 +182,7 @@ mcpServer.tool( content: [ { type: "text", - text: JSON.stringify(res.data), + text: JSON.stringify(compactBookmark(res.data)), }, ], }; @@ -129,7 +211,44 @@ mcpServer.tool( content: [ { type: "text", - text: JSON.stringify(res.data), + text: JSON.stringify(compactBookmark(res.data)), + }, + ], + }; + }, +); + +mcpServer.tool( + "get-bookmark-content", + `Get a bookmark content.`, + { + bookmarkId: z.string().describe(`The bookmarkId to get content for.`), + }, + async ({ bookmarkId }): Promise<CallToolResult> => { + const res = await karakeepClient.GET(`/bookmarks/{bookmarkId}`, { + params: { + path: { + bookmarkId, + }, + }, + }); + if (res.error) { + return toMcpToolError(res.error); + } + let content; + if (res.data.content.type === "link") { + const htmlContent = res.data.content.htmlContent; + content = turndownService.turndown(htmlContent); + } else if (res.data.content.type === "text") { + content = res.data.content.text; + } else if (res.data.content.type === "asset") { + content = ""; + } + return { + content: [ + { + type: "text", + text: content ?? "", }, ], }; diff --git a/apps/mcp/src/shared.ts b/apps/mcp/src/shared.ts index 69672769..2c553d17 100644 --- a/apps/mcp/src/shared.ts +++ b/apps/mcp/src/shared.ts @@ -1,12 +1,13 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { CallToolResult } from "@modelcontextprotocol/sdk/types"; +import TurndownService from "turndown"; -import { createHoarderClient } from "@karakeep/sdk"; +import { createKarakeepClient } from "@karakeep/sdk"; const addr = process.env.KARAKEEP_API_ADDR; const apiKey = process.env.KARAKEEP_API_KEY; -export const karakeepClient = createHoarderClient({ +export const karakeepClient = createKarakeepClient({ baseUrl: `${addr}/api/v1`, headers: { "Content-Type": "application/json", @@ -19,6 +20,8 @@ export const mcpServer = new McpServer({ version: "0.23.0", }); +export const turndownService = new TurndownService(); + export function toMcpToolError( error: { code: string; message: string } | undefined, ): CallToolResult { |
