Search, query, and paginate OneNote content with OData filters and client-side search patterns.
Use when building search features, querying pages across notebooks, or handling large result sets.
Trigger with "onenote search", "onenote query pages", "onenote pagination", "find onenote content".
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Search, query, and paginate OneNote content with OData filters and client-side search patterns.
Use when building search features, querying pages across notebooks, or handling large result sets.
Trigger with "onenote search", "onenote query pages", "onenote pagination", "find onenote content".
allowed-tools
Read, Write, Edit, Bash(npm:*), Bash(pip:*), Grep
version
1.6.0
license
MIT
author
Jeremy Longshore <jeremy@intentsolutions.io>
tags
["saas","onenote","microsoft"]
compatibility
Designed for Claude Code
OneNote — Search, Query, and Pagination
Overview
OneNote's dedicated search endpoint was deprecated in April 2024. The replacement — OData $filter queries on page listings — cannot search page body content, cannot search across all notebooks in a single call, and sometimes returns deleted pages in results. Pagination via @odata.nextLink is unreliable: the link is sometimes omitted even when more results exist. This skill provides production-tested patterns for content discovery, cross-notebook queries, and safe pagination with guard rails.
Key pain points addressed:
The $search parameter on /me/onenote/pages is deprecated — use $filter on metadata fields only
No single endpoint searches across all notebooks — you must iterate notebooks and their sections
Deleted pages continue appearing in GET /sections/{id}/pages results for up to 30 minutes
@odata.nextLink may be absent even when $top items were returned (Graph bug with OneNote)
Prerequisites
Azure app registration with delegated permissions: Notes.Read or Notes.ReadWrite
App-only auth deprecated March 31, 2025 — use delegated auth only
Warning:$search was deprecated April 2024. Using it returns 400 Bad Request on most tenants. Use $filter with contains() on title, or implement client-side search on fetched content.
Step 2 — Cross-Notebook Search Pattern
There is no single Graph endpoint that searches page content across all notebooks. You must iterate:
Performance: This approach makes N+M API calls (N notebooks + M total sections). For users with many notebooks, cache the notebook/section structure and only fetch pages from recently modified sections.
Step 3 — Client-Side Full-Text Search
Since $filter only works on metadata, search page body content client-side after fetching:
The @odata.nextLink from OneNote endpoints is sometimes missing even when more results exist. Always implement a safety limit:
interfacePaginatedResult<T> {
items: T[];
totalFetched: number;
hitSafetyLimit: boolean;
}
asyncfunction paginateAll<T>(
client: Client,
initialUrl: string,
maxPages: number = 20, // Safety limit: prevent runaway paginationpageSize: number = 100
): Promise<PaginatedResult<T>> {
constitems: T[] = [];
leturl: string | null = `${initialUrl}${initialUrl.includes("?") ? "&" : "?"}$top=${pageSize}`;
let pagesConsumed = 0;
while (url && pagesConsumed < maxPages) {
const response = await client.api(url).get();
const batch = response.value ?? [];
items.push(...batch);
pagesConsumed++;
// Guard: if we got fewer items than $top, we're at the end// even if @odata.nextLink is present (Graph bug)if (batch.length < pageSize) break;
url = response["@odata.nextLink"] ?? null;
// Guard: if no nextLink but we got exactly $top items,// the API may have dropped the link — try manual offsetif (!url && batch.length === pageSize) {
console.warn("Missing @odata.nextLink — attempting manual $skip");
const skip = items.length;
url = `${initialUrl}${initialUrl.includes("?") ? "&" : "?"}$top=${pageSize}&$skip=${skip}`;
}
}
return {
items,
totalFetched: items.length,
hitSafetyLimit: pagesConsumed >= maxPages,
};
}
Step 5 — Filter Deleted Pages from Results
Deleted pages can appear in list results for up to 30 minutes. Filter them before displaying:
asyncfunctiongetActivePages(client: Client, sectionId: string) {
const result = awaitpaginateAll(
client,
`/me/onenote/sections/${sectionId}/pages?$select=id,title,lastModifiedDateTime,createdDateTime&$orderby=lastModifiedDateTime desc`
);
// Deleted pages have null title and a lastModifiedDateTime// very close to their deletion timeconst activePages = result.items.filter((page: any) => {
if (!page.title) returnfalse; // Deleted pages often have null titlesreturntrue;
});
// Additional verification: try to GET content for suspicious pages// A 404 on content means the page is deletedreturn activePages;
}
Step 6 — Python Async Pagination
from msgraph import GraphServiceClient
asyncdefpaginate_pages(client: GraphServiceClient, section_id: str, max_pages: int = 20):
"""Paginate through all pages in a section with safety limits."""
all_pages = []
pages_fetched = 0
result = await client.me.onenote.sections.by_onenote_section_id(
section_id
).pages.get()
while result and pages_fetched < max_pages:
all_pages.extend(result.value or [])
pages_fetched += 1ifnot result.odata_next_link:
break# Follow @odata.nextLink
result = await client.me.onenote.sections.by_onenote_section_id(
section_id
).pages.with_url(result.odata_next_link).get()
return all_pages
Output
Search and query operations return:
Page listing: JSON array with id, title, createdDateTime, lastModifiedDateTime, parentSection
Page content: XHTML stream (must be buffered and parsed)
Pagination:@odata.nextLink URL (when present) or @odata.count (when $count=true is specified)