aboutsummaryrefslogtreecommitdiffstats
path: root/apps/mcp/src/bookmarks.ts
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2025-04-13 12:29:57 +0000
committerMohamed Bassem <me@mbassem.com>2025-04-13 12:31:10 +0000
commite5bacda644ae8b421e9b056bcde4fd57548899c1 (patch)
tree195112503b5b543350b6ee6654b1a0a47d4b9d66 /apps/mcp/src/bookmarks.ts
parent1f92ced36ec0af11ec0d10bee6aa2474b46462b6 (diff)
downloadkarakeep-e5bacda644ae8b421e9b056bcde4fd57548899c1.tar.zst
fix(mcp): Reduce token usage of the MCP server
Diffstat (limited to 'apps/mcp/src/bookmarks.ts')
-rw-r--r--apps/mcp/src/bookmarks.ts129
1 files changed, 124 insertions, 5 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 ?? "",
},
],
};