OneNote MCP Server Implementation
This MCP server provides 14 tools for OneNote management with basic structure, but falls short of production quality due to incomplete schemas, missing parameter descriptions, and inconsistent documentation. Tool naming follows verb_noun convention (listNotebooks, getNotebook, createNotebook, deleteNotebook, listSections, createSection, getSection, deleteSection, listPages, searchPages, createPage, getPage, updatePage, deletePage), which is good. However, most tools lack comprehensive input parameter documentation. Output schemas are undocumented. Error handling is present at the class level (src/errors/index.ts defines custom error types) but tools do not return structured error guidance to the LLM. No tool annotations (readOnlyHint/destructiveHint/idempotentHint) are declared despite clear risk categories (READ_ONLY, WRITE, DESTRUCTIVE). Parameter schemas are defined but descriptions are minimal (e.g., 'Notebook ID', 'Page ID') and do not guide the LLM on format, constraints, or when to use each tool. The codebase shows validation logic (src/validation/index.ts) but this is server-side only; the tool definitions themselves do not communicate constraints to the LLM. No pagination parameters or result limits are visible in tool definitions for list/search operations, risking context window exhaustion on large result sets.
Create new notebook
Create new page
Create new section
Delete notebook
Delete page
Delete section
Get notebook by ID
Get page content
Minimal parameter descriptions across all tools. Parameters like 'id', 'query', 'content', 'sectionId' have extremely brief descriptions (e.g., 'Notebook ID', 'Page ID') that do not explain format, constraints, or why the parameter is needed. LLMs cannot infer whether an ID is a UUID, a numeric ID, or a display name without explicit documentation.
No output schemas documented for any tool. The code defines TypeScript interfaces (Notebook, Section, Page) but these are not exposed in the tool definitions. LLMs cannot plan downstream tool calls or know what fields to expect without explicit output documentation. For example, createNotebook likely returns a Notebook with id, name, createdTime, etc., but this is not declared to the LLM.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 38 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 19 | - | v1 |
Get section by ID
List all notebooks
List pages in a section
List sections in a notebook
Search pages across notebooks
Update page content
No pagination parameters or result limits visible in list/search tools (listNotebooks, listSections, listPages, searchPages). Microsoft Graph API responses can be large; without pagination, an agent calling listPages on a large section could retrieve hundreds or thousands of items, exhausting the context window. No page/offset/limit parameters or documentation of result caps are present.
Missing tool annotations for risk categorization. The server internally tags tools as READ_ONLY, WRITE, or DESTRUCTIVE, but these annotations are not declared in the MCP tool definitions via readOnlyHint, destructiveHint, or idempotentHint. The LLM cannot distinguish safe reads from risky deletes without these hints, increasing the risk of unintended destructive calls.
Weak error handling and recovery guidance. While the server defines custom error types (AuthenticationError, NotFoundError, ValidationError, RateLimitError, ServerError in src/errors/index.ts), the tool definitions do not communicate what errors users should expect or how to recover. Error responses lack actionable guidance (e.g., 'User not found. Try search_users() first').
No confirmation/dry-run pattern for destructive operations. Tools deleteNotebook, deleteSection, and deletePage allow permanent deletion without a confirmation or dry-run mode. An LLM error or misunderstanding could irreversibly delete user data. No pattern exists to prevent catastrophic mistakes.
Missing validation guidance in parameter descriptions. The server has server-side validation (src/validation/index.ts) that enforces name length limits (128 chars), UUID format for IDs, and HTML content checks, but these constraints are not documented in the tool parameter descriptions. LLMs cannot self-correct without explicit constraints in the description text.
Ambiguous naming between getPage and getSection/getNotebook. All three follow get_<resource> pattern, but it is unclear from names alone which returns what. The LLM must read descriptions to distinguish. Clearer names or more explicit descriptions are needed.