Local OneNote MCP
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Local OneNote MCP
A local Microsoft OneNote MCP server for Windows. It controls the OneNote desktop app directly through the local OneNote COM API—requiring no Azure, Microsoft Graph, API keys, or online OAuth.
Design & Architecture
Local-Only Boundary: Every operation executes directly through the local OneNote desktop installation. No data leaves your computer.
COM-First Engineering: No direct binary
.onefile manipulation. All writes and reads go through OneNote's own COM engine, so sync and integrity stay OneNote's job.Persistent, Injection-Free Bridge: One long-lived PowerShell process runs a fixed script and receives each request as a JSON line. User data is never interpolated into script text. Keeping the process (and its COM connection) alive makes a typical page read take tens of milliseconds instead of about a second.
Native Formatting: Markdown and HTML become native OneNote headings, bullet/numbered lists (nested), To Do checkboxes, tables and code blocks. Pages read back as plain text or Markdown, including the text OneNote recognised inside images (OCR).
Local Full-Text Index: Page text (with OCR) is cached per page and refreshed when OneNote reports the page changed, so searching thousands of pages takes well under a second once the index is built.
Design Note: PowerShell is used as the COM bridge because Python automation libraries (pywin32) cannot build a dispatch wrapper for
OneNote.Application, while PowerShell can call it directly.
Related MCP server: onenote-mcp
Requirements
Windows 10 / 11
Microsoft OneNote Desktop App (Traditional version; not the legacy Windows 10 UWP app)
Python 3.11+
Setup (local folder)
Clone the repository and create its virtual environment:
git clone https://github.com/Peteroooooooo/local-onenote-mcp cd local-onenote-mcp python -m venv .venv .\.venv\Scripts\python.exe -m pip install -e .The editable install means a
git pullor local edit takes effect the next time the MCP client starts the server.Point your MCP client at the folder's Python. Replace the path with your clone.
Claude Code / Claude Desktop (JSON):
{ "mcpServers": { "local-onenote": { "type": "stdio", "command": "C:\\path\\to\\local-onenote-mcp\\.venv\\Scripts\\python.exe", "args": ["-m", "local_onenote_mcp.server"], "env": { "LOCAL_ONENOTE_MCP_TIMEOUT": "90", "LOCAL_ONENOTE_MCP_MAX_TEXT_CHARS": "60000" } } } }Codex (TOML; use forward slashes or doubled backslashes):
[mcp_servers.local-onenote] type = "stdio" command = "C:/path/to/local-onenote-mcp/.venv/Scripts/python.exe" args = ["-m", "local_onenote_mcp.server"] startup_timeout_ms = 30000Check it:
.\.venv\Scripts\python.exe scripts\check_codex_config.py # Codex config points at this folder .\.venv\Scripts\python.exe scripts\e2e_onenote.py # full check in throwaway notebooks
Starting the server does not start OneNote. OneNote is contacted on the first tool call.
Markdown, HTML & Reading Formats
Write tools (create_page, append_to_page, edit_page, replace_page_body) accept content_format = plain, html, or markdown. Markdown is parsed with the bundled markdown-it-py (CommonMark plus tables and strikethrough). It becomes:
Markdown / HTML | In OneNote |
| OneNote Heading 1–6 styles |
| Native bullet / numbered lists with indentation |
| Native To Do tags you can tick in OneNote |
| OneNote quote style |
Tables | Native OneNote tables with a shaded header row |
Fenced code | OneNote code style, one line per paragraph, indentation kept |
| Inline formatting ( |
append_to_page places new text, an image (image_path) or an attached file (file_path) below the page's existing content unless you pass x/y.
get_page takes format = text or markdown and include_ocr (default true). Markdown read-back maps the same structures back (headings, lists, - [x] to-dos, tables, code fences, image OCR text as quotes). OneNote stores mixed Chinese/Latin text as separate font runs; the reader joins runs with the same formatting, so bold or italic text comes back as one **…** span. Handwriting that OneNote has recognised is read as text; other ink is marked [Handwriting: …]. To see such a page, view_page prints it to PDF in OneNote and returns each printed page as a JPEG image (about 1.3 s for a one-page note, 240 KB per image at the default 1000 px width). With callback_id it returns just that one image from the page.
Editing part of a page
edit_page changes single paragraphs and leaves everything else on the page alone: images, handwriting, attachments and other text blocks are not resubmitted. Take paragraph IDs from get_page(include_paragraphs=true), then send a list of operations that are applied together in one update:
[
{"op": "replace_text", "find": "2025", "replace": "2026"},
{"op": "set_text", "paragraph_id": "{…}{48}{B0}", "content": "**new** wording"},
{"op": "insert_after", "paragraph_id": "{…}{51}{B0}", "content": "- extra item\n- [ ] follow-up"},
{"op": "set_todo", "paragraph_id": "{…}{55}{B0}", "done": true},
{"op": "delete", "paragraph_id": "{…}{60}{B0}"},
{"op": "add_row", "paragraph_id": "{…}{70}{B0}", "cells": ["Gamma", "QA", "Planned"]}
]replace_textkeeps bold, links and other formatting around the match. A match may span formatting runs (OneNote splits每分钟 60 次into three); the replacement takes the formatting of the run where the match starts. Matches never cross paragraphs or line breaks.set_textkeeps the paragraph's bullet, number, to-do box and style.insert_after/insert_beforetake any amount of Markdown, HTML or plain text and reuse the page's own heading and To Do definitions.deleteremoves the paragraph and its indented children; a block left empty is removed. Given theobject_idof a whole text block, image, ink drawing or attachment (fromget_page(include_objects=true)), it removes that object.Table cells are paragraphs too:
get_page(include_paragraphs=true)gives each one itstable,rowandcolumn.set_textchanges a cell,add_rowadds a row after the row of the given cell (or at the end, given the table's own paragraph),delete_rowremoves the row of the given cell. Deleting the only paragraph of a cell empties it.
If one operation is invalid (for example an unknown paragraph ID), nothing is written.
Backups
Every destructive tool (edit_page, replace_page_body, submit_xml for pages, delete_item for the pages it deletes, restore_backup itself) first saves the page to %LOCALAPPDATA%\local-onenote-mcp\backups.sqlite3. list_backups shows them and restore_backup brings one back, either into the original page (mode="replace") or as a new page (mode="new_page", which also works after the page was deleted). The default, mode="auto", puts block backups back in place and restores whole pages as new pages.
The store stays small and bounded:
Images, ink and attachments are stored once. Each is kept by its SHA-256 hash; ten backups of a page with the same photo store the photo once. The page XML itself is zlib-compressed.
edit_pagesaves only the blocks it changes (backup kindblocks): the text block's XML, a few KB, without reading the page's images. If a changed block holds an image, ink or a file, the whole page is saved instead.Unchanged pages are not saved again. If the page is identical to its newest backup, that backup is reused.
Old backups are dropped automatically: at most 10 per page, none older than 30 days, and the whole file under 200 MB (oldest first; the newest backup is always kept). Images that no backup uses any more are deleted and the file shrinks.
Measured on 150 random pages of a real 4,800-page collection: the page text and structure take 5 KB per backup on average. Images and ink take the rest (about 0.8 MB per page on average, already compressed by their formats). Saving takes 44 ms (median), and saving unchanged pages again adds 0 bytes. Change the limits with the variables below, or set LOCAL_ONENOTE_MCP_BACKUP=0 to turn backups off.
Tool Directory
Each tool is annotated as read-only, writing, or destructive, so MCP clients can auto-approve reads and ask before deletes. Failures are returned as MCP tool errors (isError: true) with the reason.
1. Discovery & Reading
health_check: Server version, Python location, OneNote's special folders, text-index progress and backup storage.resolve_identifier: Turn an ID, path, or name into one live object. Withlink="onenote"or"web"it returns a link to the object (or to one paragraph withparagraph_id).list_hierarchy: Notebooks, sections and pages with full paths. With no arguments it lists notebooks and sections;start_identifierlists what is under one item;item_type(notebook,section_group,section,page) filters. Returns at mostmax_items(default 500) and reportstotal/truncated.get_page: Title and body as text or Markdown.include_paragraphs=truelists paragraph IDs foredit_page;include_objects=truelists outlines, images, ink and attachments withobject_idandcallback_id;include_xml=trueadds the raw page XML.view_page: Show the whole page as it looks in OneNote (handwriting, drawings, layout) as JPEG images, one per printed page; or one image from the page withcallback_id.get_binary_content: Download an image (callback_id) or attached file (file_name), as base64 or straight to a file withsave_to.search_pages: Pages containing every word of the query, ranked (title matches first, then number of occurrences in the body).modified_after/modified_beforefilter by edit date; with no query they list the pages edited in that window, newest first.
2. Creation & Edits
create_item: Create a notebook (kind="notebook",nameis a folder path), section or section group.open_notebook: Open an existing notebook folder.create_page: New page with Markdown, HTML or plain content.append_to_page: Add text, an image (image_path, optionalwidth/height) or an attached file (file_path,display_name). Give exactly one of them.edit_page: Change, insert, delete or tick single paragraphs, edit table cells and rows, and delete whole objects (see above).replace_page_body: Replace the whole body. Writes the new body first, then removes the old objects, so a failed write never empties the page.copy_page: Copy a page with its images, handwriting and attachments into any section.submit_xml: Send raw OneNote XML. A<one:Page>goes toUpdatePageContent(after a backup); anything else toUpdateHierarchy.list_backups,restore_backup
3. Moving & Organizing
move_page: Move a page to another section in any notebook, or reorder it inside its section (after_page_identifier,to_top, or end). Subpages move with it unlessinclude_subpages=false.level(1–3) makes it a subpage or promotes it, on its own or together with a move. A page moved to another section gets a new ID; the tool returns old and new IDs.move_section: Move a section or section group into a notebook or section group in any notebook, or reorder it among its siblings. IDs are kept. For local notebooks it waits until OneNote has moved the.onefile on disk, so the move survives closing the notebook.rename_item: Rename a page (its title), section or section group.merge_sections: Merge one section into another.delete_item: Delete a page, section or section group, to the recycle bin unlesspermanently=true. Pages are backed up first and always matched by ID, so a page with a duplicate title is never touched. Notebooks are closed withclose_notebook, not deleted.
All of these refuse to touch the recycle bin, and the section tools refuse name clashes and moving a group into itself.
4. File & App Control
publish_object: Export a notebook, section, or page to PDF, XPS, Word, MHT, HTML, EMF, or OneNote package files.navigate_to: Open an object (or a paragraph) in OneNote, or anonenote:link.sync_hierarchy,close_notebook
Identifier Resolution: identifiers are tried as
OneNote object ID (fastest; the only safe choice for pages, because page titles are often duplicated)
Hierarchy path (e.g.,
Personal/Quick Notes/My Section)Unique display name
How search works
search_pages with the default backend="auto":
If the local text index covers the pages in scope, it answers from the index: complete, includes image OCR, about 50 ms for 4,800 pages. Pages edited since they were indexed are re-read on the spot.
Otherwise it asks OneNote's own search index, and falls back to scanning page text (time-limited, reports
scan_complete) when that finds nothing.
The index fills itself in the background after the first tool call and keeps up by re-reading only pages whose lastModifiedTime changed. Progress is shown in health_check → text_index. backend="local_scan" forces the scan; backend="index" uses only OneNote's index.
The index is stored at %LOCALAPPDATA%\local-onenote-mcp\text-index.sqlite3 and contains the plain text of your pages. Delete the file to reset it, or set LOCAL_ONENOTE_MCP_INDEX=0 to keep it in memory only.
Environment Variables
Variable | Default | Meaning |
|
| Seconds before a single COM call is abandoned and the bridge restarted |
|
| Default cap on returned page text |
|
| Time budget for a text-scan search |
|
| How long a hierarchy listing is reused between tool calls (cleared after any write; |
|
|
|
| Custom location for the text index file | |
|
|
|
|
| Minimum gap between background passes that pick up edited pages |
|
|
|
| Custom location for the backup file | |
|
| Size limit of the backup file |
|
| Backups kept per page |
|
| Backups older than this are deleted |
Code Layout
File | Role |
| Entry point: registers the tools and serves MCP over stdio |
| Shared runtime (settings, OneNote connection, index, backups) and the |
| The PowerShell COM bridge; hierarchy cache, identifier resolution and page I/O on top of it |
| Parse hierarchy XML; build and inspect page XML; Markdown/HTML to OneNote; OneNote to text/Markdown |
| Paragraph-level page edits |
| Backup store; snapshots, copies and restores |
| Search ranking, date filters and the background text index |
| The MCP tools: |
Tests
# Unit tests (an in-memory fake stands in for OneNote; one bridge test starts PowerShell)
.\.venv\Scripts\python.exe -m pytest -q
# Full cycle in throwaway notebooks (temp folder, closed afterwards)
.\.venv\Scripts\python.exe scripts\e2e_onenote.pye2e_onenote.py runs 30 checks against the real OneNote app, including partial edits of text and tables, block and whole-page restores, view_page, copying a page with an image and an attachment, moving pages and sections between two notebooks, and confirming the result after closing and reopening them. It also exports its test page to PDF and prints the folder, so formatting can be checked by eye.
Limits & Boundaries
view_page renders through OneNote's PDF printer: some colour emoji print as outlines or plain symbols there, while the page itself keeps them.
OneNote sometimes answers "class not registered" for a moment while it rewrites notebook files; reads and hierarchy updates are retried once after 0.5 s.
This server relies on the Windows COM API, so it runs only on Windows, for the signed-in local user, with the OneNote desktop app installed. COM calls are serialized through one bridge process; a tool call waits for at most one background-index page read. OneNote's own search index can lag behind very recent edits, which is why search_pages falls back to a text scan.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Google Keep-style notes app with an MCP server for AI agents to read/write notes.
MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
Hosted MCP server for Obsidian Sync vaults: read, search, edit notes. Not affiliated with Obsidian.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceA local MCP server that lets AI assistants read and edit OneNote pages on Windows via COM automation, without cloud authentication.2MIT
- AlicenseNot gradedqualityCmaintenanceA secure MCP server for Microsoft OneNote via the Graph API, enabling listing/reading notebooks, sections, and pages, with optional gated write tools. Read-only by default and deployable to Azure Container Apps.47 npmMIT
- AlicenseAqualityCmaintenanceMCP server that connects AI tools to Microsoft OneNote for Business via the Microsoft Graph API, enabling listing, creating, and updating notebooks, sections, and pages.6MIT
- AlicenseAqualityCmaintenanceAn MCP server that lets you talk to your OneNote notebooks, enabling search, reading, creating, and managing pages, sections, and notebooks via natural language. It connects directly to Microsoft Graph from your own computer, so your notes and credentials never leave your machine.13MIT