kibela_get_note_content
Retrieves content and comments of a specific note by ID. Optionally includes image data URLs.
Instructions
Get content and comments of a specific note
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Note ID | |
| include_image_data | No | Whether to include image data URLs in the response |
Implementation Reference
- src/kibela.ts:60-75 (schema)Tool definition (schema) for kibela_get_note_content: defines name 'kibela_get_note_content', description 'Get content and comments of a specific note', and input schema requiring 'id' (string) with optional 'include_image_data' (boolean).
const GET_NOTE_CONTENT_TOOL: Tool = { name: "kibela_get_note_content", description: "Get content and comments of a specific note", inputSchema: { type: "object", properties: { id: { type: "string", description: "Note ID" }, include_image_data: { type: "boolean", description: "Whether to include image data URLs in the response", default: false, }, }, required: ["id"], }, }; - src/kibela.ts:342-412 (handler)Handler implementation for kibela_get_note_content: extracts 'id' and 'include_image_data' args, builds a GraphQL query (GetNote) that fetches note fields (id, title, content, contentHtml, etc.), author, groups, folders, comments, and optionally attachments with dataUrl. Sends request via GraphQL client and returns the note data as JSON.
case "kibela_get_note_content": { const id = args.id as string; const includeImageData = (args.include_image_data as boolean) || false; const attachmentsFragment = includeImageData ? `attachments(first: 3) { nodes { id name dataUrl mimeType } }` : ""; const operation = ` query GetNote($id: ID!) { note(id: $id) { id title content contentHtml contentUpdatedAt publishedAt url path isLikedByCurrentUser ${attachmentsFragment} author { id account realName } groups { id name } folders(first: 3) { nodes { id name fullName path } } comments(first: 3) { nodes { id content contentHtml author { account realName } createdAt } } } } `; const response = await client.request<NoteContentResponse>(operation, { id }); return { content: [ { type: "text", text: JSON.stringify(response.note, null, 2), }, ], }; } - src/kibela.ts:206-221 (registration)Registration of the tool in ListToolsRequestSchema handler: GET_NOTE_CONTENT_TOOL is included in the array of tools returned to the client.
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ SEARCH_NOTES_TOOL, GET_MY_NOTES_TOOL, GET_NOTE_CONTENT_TOOL, GET_GROUPS_TOOL, GET_GROUP_FOLDERS_TOOL, GET_GROUP_NOTES_TOOL, GET_FOLDER_NOTES_TOOL, GET_USERS_TOOL, LIKE_NOTE_TOOL, UNLIKE_NOTE_TOOL, GET_RECENTLY_VIEWED_NOTES_TOOL, GET_NOTE_FROM_PATH_TOOL, ], })); - src/kibela.ts:223-770 (registration)Registration in CallToolRequestSchema handler: the switch-case dispatches 'kibela_get_note_content' to its handler block (lines 342-412).
server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const { name, arguments: args = {} } = request.params; switch (name) { case "kibela_search_notes": { const { query, coediting, isArchived, sortBy, userIds, folderIds } = args as { query: string; coediting?: boolean; isArchived?: boolean; sortBy?: string; userIds?: string[]; folderIds?: string[]; }; const operation = ` query SearchNotes( $query: String!, $coediting: Boolean, $isArchived: Boolean, $sortBy: SearchSortKind, $userIds: [ID!], $folderIds: [ID!] ) { search( query: $query, first: 15, coediting: $coediting, isArchived: $isArchived, sortBy: $sortBy, userIds: $userIds, folderIds: $folderIds ) { edges { node { document { ... on Note { id title url contentUpdatedAt author { id account realName } groups { id name } } } } } } } `; const response = await client.request<SearchResponse>(operation, { query, coediting, isArchived, sortBy, userIds, folderIds, }); const notes = response.search.edges .filter((edge) => edge.node.document !== null) .map((edge) => edge.node.document); return { content: [ { type: "text", text: JSON.stringify(notes, null, 2), }, ], }; } case "kibela_get_my_notes": { const limit = (args.limit as number) || 15; const operation = ` query GetMyNotes($limit: Int!) { currentUser { latestNotes(first: $limit) { totalCount edges { node { id title url contentUpdatedAt author { id account realName } } } } } } `; const response = await client.request<NotesResponse>(operation, { limit }); const notes = response.currentUser.latestNotes.edges.map((edge) => edge.node); return { content: [ { type: "text", text: JSON.stringify(notes, null, 2), }, ], }; } case "kibela_get_note_content": { const id = args.id as string; const includeImageData = (args.include_image_data as boolean) || false; const attachmentsFragment = includeImageData ? `attachments(first: 3) { nodes { id name dataUrl mimeType } }` : ""; const operation = ` query GetNote($id: ID!) { note(id: $id) { id title content contentHtml contentUpdatedAt publishedAt url path isLikedByCurrentUser ${attachmentsFragment} author { id account realName } groups { id name } folders(first: 3) { nodes { id name fullName path } } comments(first: 3) { nodes { id content contentHtml author { account realName } createdAt } } } } `; const response = await client.request<NoteContentResponse>(operation, { id }); return { content: [ { type: "text", text: JSON.stringify(response.note, null, 2), }, ], }; } case "kibela_get_groups": { const operation = ` query GetGroups { groups(first: 10, ability: READABLE) { nodes { id name description isPrivate canBeManaged canBeJoinedBySelf isJoined } } } `; const response = await client.request<GroupResponse>(operation); return { content: [ { type: "text", text: JSON.stringify(response.groups.nodes, null, 2), }, ], }; } case "kibela_get_group_folders": { const { groupId, parentFolderId } = args as { groupId: string; parentFolderId?: string; }; const operation = ` query GetGroupFolders($groupId: ID!, $parentFolderId: ID) { group(id: $groupId) { folders(first: 30, active: true, parentFolderId: $parentFolderId) { nodes { id name fullName path canBeManaged parent { id name } notes(first: 10, active: true, orderBy: { field: CONTENT_UPDATED_AT, direction: DESC }) { nodes { id title contentUpdatedAt publishedAt author { account realName } } } } } } } `; const response = await client.request<GroupFoldersResponse>(operation, { groupId, parentFolderId, }); return { content: [ { type: "text", text: JSON.stringify(response.group.folders.nodes, null, 2), }, ], }; } case "kibela_get_group_notes": { const { groupId } = args as { groupId: string }; const operation = ` query GetGroupNotes($groupId: ID!) { group(id: $groupId) { notes(first: 10, active: true, onlyNotAttachedFolder: true, orderBy: { field: CONTENT_UPDATED_AT, direction: DESC }) { nodes { id title contentUpdatedAt publishedAt author { account realName } } } } } `; const response = await client.request<GroupNotesResponse>(operation, { groupId }); return { content: [ { type: "text", text: JSON.stringify(response.group.notes.nodes, null, 2), }, ], }; } case "kibela_get_folder_notes": { const { folderId, limit = 100 } = args as { folderId: string; limit?: number }; const operation = ` query GetFolderNotes($folderId: ID!, $limit: Int!) { folder(id: $folderId) { notes(first: $limit, active: true, orderBy: { field: CONTENT_UPDATED_AT, direction: DESC }) { nodes { id title contentUpdatedAt publishedAt author { account realName } } } } } `; const response = await client.request<FolderNotesResponse>(operation, { folderId, limit }); return { content: [ { type: "text", text: JSON.stringify(response.folder.notes.nodes, null, 2), }, ], }; } case "kibela_get_users": { const operation = ` query GetUsers { users(first: 100) { nodes { id account realName } } } `; const response = await client.request<UsersResponse>(operation); return { content: [ { type: "text", text: JSON.stringify(response.users.nodes, null, 2), }, ], }; } case "kibela_like_note": { const noteId = args.noteId as string; const operation = ` mutation LikeNote($input: LikeInput!) { like(input: $input) { clientMutationId likers(first: 3) { nodes { id account realName } } } } `; const response = await client.request<LikeResponse>(operation, { input: { noteId }, }); return { content: [ { type: "text", text: JSON.stringify(response.like, null, 2), }, ], }; } case "kibela_unlike_note": { const noteId = args.noteId as string; const operation = ` mutation UnlikeNote($input: UnlikeInput!) { unlike(input: $input) { clientMutationId likers(first: 10) { nodes { id account realName } } } } `; const response = await client.request<UnlikeResponse>(operation, { input: { noteId }, }); return { content: [ { type: "text", text: JSON.stringify(response.unlike, null, 2), }, ], }; } case "kibela_get_recently_viewed_notes": { const limit = (args.limit as number) || 15; const operation = ` query GetRecentlyViewedNotes($limit: Int!) { noteBrowsingHistories(first: $limit) { nodes { note { id title url contentUpdatedAt author { id account realName } } } } } `; const response = await client.request<RecentlyViewedNotesResponse>(operation, { limit }); const notes = response.noteBrowsingHistories.nodes.map((node) => node.note); return { content: [ { type: "text", text: JSON.stringify(notes, null, 2), }, ], }; } case "kibela_get_note_from_path": { const rawPath = args.path as string; const includeImageData = (args.include_image_data as boolean) || false; // Extract path from URL if full URL is provided const path = rawPath.includes("kibe.la/notes/") ? `/notes/${rawPath.split("/notes/")[1]}` : rawPath; const attachmentsFragment = includeImageData ? `attachments(first: 3) { nodes { id name dataUrl mimeType } }` : ""; const operation = ` query GetNoteFromPath($path: String!) { noteFromPath(path: $path) { id title content contentHtml contentUpdatedAt publishedAt url path isLikedByCurrentUser ${attachmentsFragment} author { id account realName } groups { id name } folders(first: 3) { nodes { id name fullName path } } comments(first: 3) { nodes { id content contentHtml author { account realName } createdAt } } } } `; const response = await client.request<NoteFromPathResponse>(operation, { path }); return { content: [ { type: "text", text: JSON.stringify(response.noteFromPath, null, 2), }, ], }; } default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { console.error("Error:", error); return { content: [ { type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); - src/types.ts:89-95 (schema)Type definition NoteContentResponse used by the handler: specifies that the GraphQL response returns a 'note' combining KibelaNote fields with a 'comments' node containing NoteComment objects.
export interface NoteContentResponse { note: KibelaNote & { comments: { nodes: NoteComment[]; }; }; }