OneNote MCP Server
A Model Context Protocol (MCP) server that connects GitHub Copilot (and other MCP-compatible AI tools) to Microsoft OneNote for Business via the Microsoft Graph API.
Features
| Tool | Description |
|---|---|
list_notebooks |
List all OneNote notebooks accessible to the configured service account |
list_sections |
List sections in a notebook |
create_section |
Create a new section in a notebook |
create_page |
Create a new page in a section (HTML content) |
update_page |
Update an existing page with patch commands |
get_page |
Retrieve a page's HTML content |
Prerequisites
- Node.js 18 or later
- A Microsoft 365 / Office 365 work or school account
- An Azure AD app registration with a client secret and application permissions (one-time setup, free, takes ~5 minutes)
Step 1 — Register an Azure AD App
This is a one-time setup. You need an Azure account that has access to your organisation's Azure AD.
- Go to https://entra.microsoft.com and sign in.
- Navigate to Identity → Applications → App registrations → New registration.
- Fill in:
- Name:
OneNote MCP Server(or any name you prefer) - Supported account types: Single tenant is recommended for background-service access.
- Name:
- Click Register.
- On the app overview page, copy:
- Application (client) ID → this is your
ONENOTE_CLIENT_ID - Directory (tenant) ID → this is your
ONENOTE_TENANT_ID
- Application (client) ID → this is your
- Go to Certificates & secrets → New client secret and copy the secret value.
- Go to API permissions → Add a permission → Microsoft Graph → Application permissions.
- Add
Notes.ReadWrite.All. - Click Grant admin consent for your tenant.
Step 2 — Install the MCP Server
# Clone or download this repository, then:
cd onenote-mcp-server
npm install
npm run build
Step 3 — Use from GitHub in any project (no local clone required)
After you push this repo to GitHub, you can reference it directly from MCP host configs:
{
"servers": {
"onenote": {
"command": "npx",
"args": ["-y", "github:<YOUR_GITHUB_USERNAME>/onenote_mcp_server"],
"env": {
"ONENOTE_CLIENT_ID": "your-client-id-from-step-1",
"ONENOTE_TENANT_ID": "your-tenant-id",
"ONENOTE_CLIENT_SECRET": "your-client-secret",
"ONENOTE_USER_PRINCIPAL_NAME": "[email protected]"
}
}
}
}
Replace
<YOUR_GITHUB_USERNAME>/onenote_mcp_serverwith your actual GitHub repo path.Thepreparescript builds TypeScript automatically when the package is installed from GitHub.
Step 4 — Configure GitHub Copilot Desktop
Option A: Workspace configuration (recommended for team sharing)
Edit .vscode/mcp.json in this project (already provided) and fill in your values:
{
"servers": {
"onenote": {
"command": "node",
"args": ["/absolute/path/to/onenote-mcp-server/build/index.js"],
"env": {
"ONENOTE_CLIENT_ID": "your-client-id-from-step-1",
"ONENOTE_TENANT_ID": "your-tenant-id",
"ONENOTE_CLIENT_SECRET": "your-client-secret",
"ONENOTE_USER_PRINCIPAL_NAME": "[email protected]"
}
}
}
}
Windows path example:
"C:\\Users\\you\\onenote-mcp-server\\build\\index.js"
Option B: User-level configuration (applies to all your workspaces)
In VS Code, open the Command Palette (Ctrl+Shift+P) → MCP: Open User Configuration, then add:
{
"servers": {
"onenote": {
"command": "node",
"args": ["/absolute/path/to/onenote-mcp-server/build/index.js"],
"env": {
"ONENOTE_CLIENT_ID": "your-client-id",
"ONENOTE_TENANT_ID": "your-tenant-id"
}
}
}
}
Step 5 — Start Using the Server
The server authenticates automatically with the configured app registration and accesses OneNote for the user principal name you set in ONENOTE_USER_PRINCIPAL_NAME.
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
ONENOTE_CLIENT_ID |
✅ Yes | — | Azure AD Application (client) ID |
ONENOTE_TENANT_ID |
✅ Yes | — | Tenant ID for the Entra app registration |
ONENOTE_CLIENT_SECRET |
✅ Yes | — | Client secret value for the app registration |
ONENOTE_USER_PRINCIPAL_NAME |
✅ Yes | — | User principal name whose OneNote notebooks the service accesses |
ONENOTE_LOG_LEVEL |
No | error |
Log verbosity: debug, info, warn, error |
Usage Examples
Once configured, you can ask Copilot things like:
- "List all my OneNote notebooks"
- "Show me the sections in my Work notebook"
- "Create a section called 'Meeting Notes' in my Project notebook"
- "Create a OneNote page titled 'Sprint Planning' with a bullet list of our team goals"
- "Get the content of page [ID] so I can update it"
- "Add a new paragraph to the end of page [ID]"
Token Cache Location
After the service first authenticates, the token cache is stored here (never committed to git):
| Platform | Location |
|---|---|
| Windows | %APPDATA%\onenote-mcp-server\token-cache.json |
| macOS | ~/Library/Application Support/onenote-mcp-server/token-cache.json |
| Linux | ~/.local/share/onenote-mcp-server/token-cache.json |
The cache file is restricted to owner-only permissions (chmod 600 on Unix). To force re-authentication, delete this file.
Security
- Confidential client app — client secrets are required and kept in environment variables
- Application permissions —
Notes.ReadWrite.Allvia the Graph.defaultscope - Client credentials flow — the server authenticates headlessly in the background
- Tokens never logged — the
Authorizationheader and token values are never written to logs - Input validation — all resource IDs are validated against a safe-ID pattern before URL interpolation
- HTML sanitisation — script tags, event handlers, and dangerous URI schemes are stripped from page content
- Atomic cache writes — token cache is written via temp file + rename to prevent corruption
Scopes and Permissions
The server requests Notes.ReadWrite.All as an application permission, which covers:
- Reading notebooks, sections, and pages for the configured user principal name
- Creating notebooks, sections, and pages
- Updating pages
Admin consent is required for the app permission.
Troubleshooting
"ONENOTE_CLIENT_ID environment variable is not set" → Make sure ONENOTE_CLIENT_ID is set in your mcp.json env block.
"ONENOTE_CLIENT_SECRET environment variable is not set" → Make sure the client secret value is set in your mcp.json env block.
"ONENOTE_USER_PRINCIPAL_NAME environment variable is not set" → Make sure the service account UPN is set in your mcp.json env block.
"Graph API error: 403" → The app registration is missing Notes.ReadWrite.All, admin consent was not granted, or the configured user principal name cannot access the requested notebook.
"Graph API error: 401" → Delete the token cache file (listed above under "Token Cache Location") and re-authenticate.
"Request timed out" → Network issue connecting to graph.microsoft.com. Check your proxy/firewall settings.
Use with other MCP hosts (Claude Desktop / Cursor / others)
Any MCP host that supports stdio can use this server with the same command/env pattern:
{
"mcpServers": {
"onenote": {
"command": "npx",
"args": ["-y", "github:<YOUR_GITHUB_USERNAME>/onenote_mcp_server"],
"env": {
"ONENOTE_CLIENT_ID": "your-client-id",
"ONENOTE_TENANT_ID": "your-tenant-id",
"ONENOTE_CLIENT_SECRET": "your-client-secret",
"ONENOTE_USER_PRINCIPAL_NAME": "[email protected]"
}
}
}
}
If your host expects servers instead of mcpServers, keep the same inner object and rename only the top-level key.
Development
# Run without building (uses tsx)
npm run dev
# Build TypeScript
npm run build
# Start the built server
npm start
API Reference
All operations use the Microsoft Graph API v1.0 endpoints:
| Operation | Endpoint |
|---|---|
| List notebooks | GET /users/{userPrincipalName}/onenote/notebooks |
| List sections | GET /users/{userPrincipalName}/onenote/notebooks/{id}/sections |
| Create section | POST /users/{userPrincipalName}/onenote/notebooks/{id}/sections |
| Create page | POST /users/{userPrincipalName}/onenote/sections/{id}/pages |
| Update page | PATCH /users/{userPrincipalName}/onenote/pages/{id}/content |
| Get page | GET /users/{userPrincipalName}/onenote/pages/{id}/content |
Note: The server uses application permissions to access OneNote for the configured user principal name. Admin consent is required.