Skip to main content
Glama
ItsikBin

onenote_mcp_server

by ItsikBin
README.md
# OneNote MCP Server

A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) 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.

1. Go to [https://entra.microsoft.com](https://entra.microsoft.com) and sign in.
2. Navigate to **Identity → Applications → App registrations** → **New registration**.
3. Fill in:
   - **Name**: `OneNote MCP Server` (or any name you prefer)
   - **Supported account types**: **Single tenant** is recommended for background-service access.
4. Click **Register**.
5. On the app overview page, copy:
   - **Application (client) ID** → this is your `ONENOTE_CLIENT_ID`
   - **Directory (tenant) ID** → this is your `ONENOTE_TENANT_ID`
6. Go to **Certificates & secrets** → **New client secret** and copy the secret value.
7. Go to **API permissions** → **Add a permission** → **Microsoft Graph** → **Application permissions**.
8. Add `Notes.ReadWrite.All`.
9. Click **Grant admin consent** for your tenant.

---

## Step 2 — Install the MCP Server

```bash
# 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:

```json
{
  "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": "service-account@yourtenant.com"
      }
    }
  }
}
```

> Replace `<YOUR_GITHUB_USERNAME>/onenote_mcp_server` with your actual GitHub repo path.
> The `prepare` script 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:

```json
{
  "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": "service-account@yourtenant.com"
      }
    }
  }
}
```

> **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:

```json
{
  "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.All` via the Graph `.default` scope
- **Client credentials flow** — the server authenticates headlessly in the background
- **Tokens never logged** — the `Authorization` header 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:

```json
{
  "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": "service-account@yourtenant.com"
      }
    }
  }
}
```

If your host expects `servers` instead of `mcpServers`, keep the same inner object and rename only the top-level key.

---

## Development

```bash
# 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.

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct resource (notebooks, sections, pages) and action (list, create, get, update). No overlapping purposes; list_sections and create_section are clearly differentiated by action.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: list_notebooks, list_sections, create_section, create_page, update_page, get_page. No mixed conventions or vague verbs.

Tool Count5/5

Six tools is well-scoped for OneNote management, covering the essential notebook/section/page hierarchy without unnecessary bloat or trivial additions.

Completeness4/5

The tool set covers the core lifecycle: read notebooks, list/create sections, and create/get/update pages. Minor gaps exist (no delete operations, no rename section), but the primary workflows are supported.

Maintenance

ActivityMaintained
ResponsivenessSyncing