/**
* OneNote tool handlers for Microsoft Graph API
*/
import { getGraphClient } from '../../graph/client.js';
import { ENDPOINTS } from '../../config/endpoints.js';
import { createUserFriendlyError } from '../../graph/error-handler.js';
import {
OneNoteNotebook,
OneNoteSection,
OneNoteSectionGroup,
OneNotePage,
OneNotePagePreview,
OneNoteResponse,
ListNotebooksInput,
GetNotebookInput,
ListSectionsInput,
GetSectionInput,
ListPagesInput,
GetPageInput,
GetPageContentInput,
CreatePageInput,
UpdatePageInput,
SearchNotesInput,
} from './types.js';
// Helper to build OData query string
function buildQueryParams(options: Record<string, any>): Record<string, string> {
const params: Record<string, string> = {};
if (options.filter) params['$filter'] = options.filter;
if (options.orderby) params['$orderby'] = options.orderby;
if (options.select) params['$select'] = options.select;
if (options.expand) params['$expand'] = options.expand;
if (options.top) params['$top'] = options.top.toString();
if (options.skip) params['$skip'] = options.skip.toString();
if (options.count) params['$count'] = 'true';
if (options.search) params['$search'] = `"${options.search}"`;
return params;
}
// Handler 1: List Notebooks
export async function handleListNotebooks(args: ListNotebooksInput) {
try {
const client = getGraphClient();
const params = buildQueryParams({
filter: args.filter,
orderby: args.orderby || 'displayName',
top: args.top || 50,
expand: args.expand,
});
const response = await client.get<OneNoteResponse<OneNoteNotebook>>(
ENDPOINTS.ONENOTE.NOTEBOOKS,
params
);
if (response.success && response.data) {
const notebooks = (response.data as any).value || [];
return {
content: [{
type: 'text',
text: JSON.stringify({
count: notebooks.length,
notebooks: notebooks.map((nb: OneNoteNotebook) => ({
id: nb.id,
displayName: nb.displayName,
isDefault: nb.isDefault,
isShared: nb.isShared,
createdDateTime: nb.createdDateTime,
lastModifiedDateTime: nb.lastModifiedDateTime,
sectionsUrl: nb.sectionsUrl,
links: nb.links,
}))
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 2: Get Notebook
export async function handleGetNotebook(args: GetNotebookInput) {
try {
const client = getGraphClient();
const endpoint = ENDPOINTS.ONENOTE.NOTEBOOK.replace('{notebookId}', args.notebookId);
const params = args.expand ? { '$expand': args.expand } : {};
const response = await client.get<OneNoteNotebook>(endpoint, params);
if (response.success && response.data) {
return {
content: [{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 3: List Sections
export async function handleListSections(args: ListSectionsInput) {
try {
const client = getGraphClient();
let endpoint: string;
if (args.notebookId) {
endpoint = ENDPOINTS.ONENOTE.NOTEBOOK_SECTIONS.replace('{notebookId}', args.notebookId);
} else {
endpoint = ENDPOINTS.ONENOTE.SECTIONS;
}
const params = buildQueryParams({
filter: args.filter,
orderby: args.orderby || 'displayName',
top: args.top || 50,
});
const response = await client.get<OneNoteResponse<OneNoteSection>>(endpoint, params);
if (response.success && response.data) {
const sections = (response.data as any).value || [];
return {
content: [{
type: 'text',
text: JSON.stringify({
notebookId: args.notebookId || 'all',
count: sections.length,
sections: sections.map((sec: OneNoteSection) => ({
id: sec.id,
displayName: sec.displayName,
isDefault: sec.isDefault,
createdDateTime: sec.createdDateTime,
lastModifiedDateTime: sec.lastModifiedDateTime,
pagesUrl: sec.pagesUrl,
parentNotebook: sec.parentNotebook,
}))
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 4: Get Section
export async function handleGetSection(args: GetSectionInput) {
try {
const client = getGraphClient();
const endpoint = ENDPOINTS.ONENOTE.SECTION.replace('{sectionId}', args.sectionId);
const params = args.expand ? { '$expand': args.expand } : {};
const response = await client.get<OneNoteSection>(endpoint, params);
if (response.success && response.data) {
return {
content: [{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 5: List Pages
export async function handleListPages(args: ListPagesInput) {
try {
const client = getGraphClient();
let endpoint: string;
if (args.sectionId) {
endpoint = ENDPOINTS.ONENOTE.SECTION_PAGES.replace('{sectionId}', args.sectionId);
} else {
endpoint = ENDPOINTS.ONENOTE.PAGES;
}
const params = buildQueryParams({
filter: args.filter,
orderby: args.orderby || 'lastModifiedDateTime desc',
top: args.top || 20,
search: args.search,
});
const response = await client.get<OneNoteResponse<OneNotePage>>(endpoint, params);
if (response.success && response.data) {
const pages = (response.data as any).value || [];
return {
content: [{
type: 'text',
text: JSON.stringify({
sectionId: args.sectionId || 'all',
count: pages.length,
pages: pages.map((page: OneNotePage) => ({
id: page.id,
title: page.title,
level: page.level,
order: page.order,
createdDateTime: page.createdDateTime,
lastModifiedDateTime: page.lastModifiedDateTime,
contentUrl: page.contentUrl,
parentSection: page.parentSection,
links: page.links,
}))
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 6: Get Page
export async function handleGetPage(args: GetPageInput) {
try {
const client = getGraphClient();
const endpoint = ENDPOINTS.ONENOTE.PAGE.replace('{pageId}', args.pageId);
const params = args.expand ? { '$expand': args.expand } : {};
const response = await client.get<OneNotePage>(endpoint, params);
if (response.success && response.data) {
return {
content: [{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 7: Get Page Content (HTML)
export async function handleGetPageContent(args: GetPageContentInput) {
try {
const client = getGraphClient();
let endpoint = ENDPOINTS.ONENOTE.PAGE_CONTENT.replace('{pageId}', args.pageId);
if (args.includeIDs) {
endpoint += '?includeIDs=true';
}
// Get raw HTML content
const response = await client.getRaw(endpoint);
if (response.success && response.data) {
return {
content: [{
type: 'text',
text: JSON.stringify({
pageId: args.pageId,
contentType: 'text/html',
content: response.data
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 8: Get Page Preview
export async function handleGetPagePreview(args: GetPageInput) {
try {
const client = getGraphClient();
const endpoint = ENDPOINTS.ONENOTE.PAGE_PREVIEW.replace('{pageId}', args.pageId);
const response = await client.get<OneNotePagePreview>(endpoint);
if (response.success && response.data) {
return {
content: [{
type: 'text',
text: JSON.stringify(response.data, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 9: Create Page
export async function handleCreatePage(args: CreatePageInput) {
try {
const client = getGraphClient();
const endpoint = ENDPOINTS.ONENOTE.SECTION_PAGES.replace('{sectionId}', args.sectionId);
// Build HTML content with proper structure
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<title>${args.title}</title>
</head>
<body>
${args.htmlContent}
</body>
</html>`.trim();
const response = await client.postHtml<OneNotePage>(endpoint, htmlContent);
if (response.success && response.data) {
return {
content: [{
type: 'text',
text: JSON.stringify({
message: 'Page created successfully',
page: {
id: response.data.id,
title: response.data.title,
createdDateTime: response.data.createdDateTime,
contentUrl: response.data.contentUrl,
links: response.data.links,
}
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 10: Update Page (PATCH)
export async function handleUpdatePage(args: UpdatePageInput) {
try {
const client = getGraphClient();
const endpoint = ENDPOINTS.ONENOTE.PAGE_CONTENT.replace('{pageId}', args.pageId);
// PATCH request with JSON array of changes
const response = await client.patchJson<any>(endpoint, args.changes);
if (response.success) {
return {
content: [{
type: 'text',
text: JSON.stringify({
message: 'Page updated successfully',
pageId: args.pageId,
changesApplied: args.changes.length
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}
// Handler 11: Search Notes
export async function handleSearchNotes(args: SearchNotesInput) {
try {
const client = getGraphClient();
// Use pages endpoint with search
const params = buildQueryParams({
search: args.query,
filter: args.filter,
top: args.top || 25,
orderby: 'lastModifiedDateTime desc',
});
const response = await client.get<OneNoteResponse<OneNotePage>>(
ENDPOINTS.ONENOTE.PAGES,
params
);
if (response.success && response.data) {
const pages = (response.data as any).value || [];
return {
content: [{
type: 'text',
text: JSON.stringify({
query: args.query,
count: pages.length,
results: pages.map((page: OneNotePage) => ({
id: page.id,
title: page.title,
createdDateTime: page.createdDateTime,
lastModifiedDateTime: page.lastModifiedDateTime,
parentSection: page.parentSection,
parentNotebook: page.parentNotebook,
links: page.links,
}))
}, null, 2)
}]
};
}
return {
content: [{ type: 'text', text: JSON.stringify({ error: response.error }) }],
isError: true
};
} catch (error) {
return {
content: [{ type: 'text', text: JSON.stringify(createUserFriendlyError(error)) }],
isError: true
};
}
}