{"_id":"@atomiclabs97/onenote-mcp","_rev":"2-3f872dc0b807ad3e1c35fdfca5854405","name":"@atomiclabs97/onenote-mcp","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.1":{"name":"@atomiclabs97/onenote-mcp","version":"0.1.1","keywords":["mcp","model-context-protocol","onenote","microsoft-onenote","microsoft-graph","claude","cursor","ai","notes","anthropic"],"author":{"name":"Ahmad Al Mezaal"},"license":"MIT","_id":"@atomiclabs97/onenote-mcp@0.1.1","maintainers":[{"name":"atomiclabs97","email":"ahmad.hmazaal@gmail.com"}],"homepage":"https://github.com/ahmadAlMezaal/onenote-mcp#readme","bugs":{"url":"https://github.com/ahmadAlMezaal/onenote-mcp/issues"},"bin":{"onenote-mcp":"dist/cli.js"},"dist":{"shasum":"7beddc514800e2d8bf4ba285f99d9a9bbc12ec95","tarball":"https://registry.npmjs.org/@atomiclabs97/onenote-mcp/-/onenote-mcp-0.1.1.tgz","fileCount":104,"integrity":"sha512-UsSwtIoTFjv+rd7XcDFvlCvG8fiyezjiiDqlqaXGUDMfjJ9PzugBWIBp9yj8lypflcHFm5toHqmjRM2y7iLYeQ==","signatures":[{"sig":"MEYCIQCRm7dPHX1ThOc7oN2RkyLhj/AdDb2zTl7WnB4PLUf/4QIhAPpqlqyBvEgjhDTlBNkxWCD59jtklZqrkSueM0tHqJcf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@atomiclabs97%2fonenote-mcp@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":118247},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"gitHead":"5c45b58730e632e8edb356d82c9e980d30dbb055","scripts":{"dev":"tsc && tsc-alias && concurrently --kill-others-on-fail --names tsc,alias 'tsc --watch --preserveWatchOutput' 'tsc-alias --watch'","lint":"eslint .","test":"vitest run","build":"tsc && tsc-alias","smoke":"tsx scripts/smoke.ts","start":"node dist/cli.js","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit && tsc --noEmit -p tsconfig.scripts.json","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"atomiclabs97","email":"ahmad.hmazaal@gmail.com"},"repository":{"url":"git+https://github.com/ahmadAlMezaal/onenote-mcp.git","type":"git"},"_npmVersion":"10.8.2","description":"MCP server for Microsoft OneNote — read, search, create, and delete pages via Microsoft Graph.","directories":{},"_nodeVersion":"20.20.2","dependencies":{"zod":"^4.0.0","marked":"^14.1.3","turndown":"^7.2.0","@azure/msal-node":"^2.16.2","@modelcontextprotocol/sdk":"^1.0.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"yarn@1.22.22","devDependencies":{"tsx":"^4.19.2","eslint":"^9.14.0","vitest":"^2.1.4","tsc-alias":"^1.8.10","@eslint/js":"^9.14.0","typescript":"^5.6.3","@types/node":"^22.9.0","concurrently":"^9.0.1","@types/turndown":"^5.0.5","typescript-eslint":"^8.13.0"},"_npmOperationalInternal":{"tmp":"tmp/onenote-mcp_0.1.1_1778892812701_0.6078513710770264","host":"s3://npm-registry-packages-npm-production"},"deprecated":"Package no longer supported. Contact Support at https://www.npmjs.com/support for more info."}},"time":{"created":"2026-05-16T00:53:32.642Z","modified":"2026-07-21T16:26:52.271Z","0.1.1":"2026-05-16T00:53:32.837Z"},"bugs":{"url":"https://github.com/ahmadAlMezaal/onenote-mcp/issues"},"author":{"name":"Ahmad Al Mezaal"},"license":"MIT","homepage":"https://github.com/ahmadAlMezaal/onenote-mcp#readme","keywords":["mcp","model-context-protocol","onenote","microsoft-onenote","microsoft-graph","claude","cursor","ai","notes","anthropic"],"repository":{"url":"git+https://github.com/ahmadAlMezaal/onenote-mcp.git","type":"git"},"description":"MCP server for Microsoft OneNote — read, search, create, and delete pages via Microsoft Graph.","maintainers":[{"name":"atomiclabs97","email":"ahmad.hmazaal@gmail.com"}],"readme":"# @atomiclabs97/onenote-mcp\n\n[![npm version](https://img.shields.io/npm/v/@atomiclabs97/onenote-mcp.svg)](https://www.npmjs.com/package/@atomiclabs97/onenote-mcp)\n[![CI](https://github.com/ahmadAlMezaal/onenote-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/ahmadAlMezaal/onenote-mcp/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nAn [MCP](https://modelcontextprotocol.io) server for **Microsoft OneNote**. Bring your notebooks into Claude, Cursor, and any MCP-compatible client — list notebooks and sections, full-text search across pages, read individual pages, and create or delete pages from natural language. Authentication uses Microsoft's device-code flow against your own Entra ID app registration, so your data and credentials never leave your machine.\n\n> _Screenshot/demo coming soon — drop a GIF in `docs/images/demo.gif` and reference it here._\n\n---\n\n## Quick start\n\n### 1. Register a Microsoft Entra app\n\nThe server talks to Microsoft Graph using a Microsoft Entra (Azure AD) **app registration** that you own. This takes about 2 minutes.\n\n> Screenshots referenced below live in [`docs/images/`](docs/images/). They are placeholders today — contributions welcome.\n\n#### a. Create the registration\n\n1. Go to the [Microsoft Entra admin center → App registrations](https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) and click **+ New registration**.\n2. **Name**: anything (e.g. `onenote-mcp`).\n3. **Supported account types**: choose **\"Accounts in any organizational directory and personal Microsoft accounts\"** if you want both work and personal OneNote to work; otherwise pick what matches your tenant.\n4. **Redirect URI**: leave blank — the device-code flow doesn't need one.\n5. Click **Register**.\n\n   ![Register an application](docs/images/01-register.png)\n\n#### b. Add the API permissions\n\n1. In the new app's left nav, click **API permissions** → **+ Add a permission** → **Microsoft Graph** → **Delegated permissions**.\n2. Search for and check both:\n   - `Notes.ReadWrite`\n   - `offline_access`\n3. Click **Add permissions**. (No admin consent is required for personal Microsoft accounts. Work/school tenants may need an admin to grant consent for the directory.)\n\n   ![Add Notes.ReadWrite + offline_access](docs/images/02-permissions.png)\n\n#### c. Allow the public client flow\n\nThe device-code flow is a \"public client\" flow — it doesn't use a client secret.\n\n1. Go to **Authentication** in the left nav.\n2. Scroll to **Advanced settings** → **Allow public client flows** and toggle it **Yes**.\n3. Click **Save**.\n\n   ![Allow public client flows](docs/images/03-public-client.png)\n\n#### d. Grab the client ID\n\nBack on the app's **Overview** page, copy the **Application (client) ID**. You'll pass it to the server via the `ONENOTE_MCP_CLIENT_ID` environment variable.\n\n  ![Application (client) ID on the Overview page](docs/images/04-client-id.png)\n\n### 2. Sign in\n\n```sh\nONENOTE_MCP_CLIENT_ID=<your-app-client-id> npx @atomiclabs97/onenote-mcp login\n```\n\nThis prints a code and a URL like:\n\n```\nTo sign in, use a web browser to open https://microsoft.com/devicelogin\nand enter the code ABCD-1234 to authenticate.\n```\n\nOpen the URL, paste the code, sign in with the Microsoft account whose OneNote you want to access, and approve the requested permissions. The refresh token is then cached at `~/.config/onenote-mcp/tokens.json` (mode `600`) so the MCP server can run silently.\n\nTo sign out:\n\n```sh\nnpx @atomiclabs97/onenote-mcp logout\n```\n\n### 3. Wire it into your MCP client\n\n#### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"onenote\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@atomiclabs97/onenote-mcp\"],\n      \"env\": {\n        \"ONENOTE_MCP_CLIENT_ID\": \"your-app-client-id\"\n      }\n    }\n  }\n}\n```\n\nRestart Claude Desktop. The OneNote tools should appear in the tool picker.\n\n#### Cursor\n\nAdd to `~/.cursor/mcp.json`:\n\n```jsonc\n{\n  \"mcpServers\": {\n    \"onenote\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@atomiclabs97/onenote-mcp\"],\n      \"env\": {\n        \"ONENOTE_MCP_CLIENT_ID\": \"your-app-client-id\"\n      }\n    }\n  }\n}\n```\n\n#### Anything else\n\nAny MCP-compatible client that supports stdio servers will work. Run `npx @atomiclabs97/onenote-mcp` with `ONENOTE_MCP_CLIENT_ID` set in the environment.\n\n---\n\n## Tools\n\n| Tool             | Description                                                     | Key inputs                                       |\n| ---------------- | --------------------------------------------------------------- | ------------------------------------------------ |\n| `list_notebooks`       | Lists all OneNote notebooks for the signed-in user.             | _(none)_                                         |\n| `list_sections`        | Lists sections, optionally scoped to a single notebook.         | `notebookId?`                                    |\n| `list_section_groups`  | Lists section groups (folders), optionally scoped to a notebook. | `notebookId?`                                   |\n| `search_pages`         | Full-text search across pages (title + content).                | `query`, `limit?`                                |\n| `read_page`            | Returns page metadata + content (HTML or Markdown).             | `pageId`, `format?` (`html` \\| `markdown`)       |\n| `create_notebook`      | Creates a new top-level notebook.                               | `name`                                           |\n| `create_section`       | Creates a section inside a notebook or section group.           | `notebookId?` \\| `sectionGroupId?`, `name`       |\n| `create_section_group` | Creates a section group inside a notebook or another section group. | `notebookId?` \\| `sectionGroupId?`, `name`   |\n| `create_page`          | Creates a page in a section. Accepts Markdown (default) or HTML, plus optional binary attachments. | `sectionId`, `title`, `content`, `format?`, `attachments?` |\n| `update_page`          | Applies edits to a page: append/prepend/insert/replace/delete elements. | `pageId`, `operations[]`                 |\n| `delete_page`          | Permanently deletes a page. **Irreversible.**                   | `pageId`                                         |\n\n---\n\n## Configuration\n\n| Env var                    | Required | Description                                                                       |\n| -------------------------- | -------- | --------------------------------------------------------------------------------- |\n| `ONENOTE_MCP_CLIENT_ID`    | yes      | Application (client) ID of your Microsoft Entra app registration.                  |\n| `ONENOTE_MCP_TENANT_ID`    | no       | Tenant ID. Defaults to `common`, which works for both personal and work accounts. |\n| `XDG_CONFIG_HOME`          | no       | Override the config directory. Tokens are stored at `<dir>/onenote-mcp/tokens.json`. |\n\n---\n\n## Known limitations\n\n- **Attachments are sent in-memory.** `create_page` reads attachment files synchronously before posting; very large files (~150 MB+) may strain Node's heap. Streamed uploads are a future enhancement.\n- **`update_page` targets are raw `data-id` selectors.** To edit a specific element, read the page first and pull the `data-id` attribute out of the returned HTML. Higher-level selectors (e.g. \"the section under heading X\") are tracked for a follow-up.\n- **Search latency.** Microsoft Graph's `$search` against `/me/onenote/pages` can take a few seconds against large notebooks; the server retries on 429s with exponential backoff.\n\n---\n\n## Contributing\n\nPRs welcome. The codebase aims to stay small and focused.\n\n```sh\ngit clone https://github.com/ahmadAlMezaal/onenote-mcp\ncd onenote-mcp\nyarn install\nyarn build\nyarn test\n```\n\n- `yarn typecheck` — `tsc --noEmit` (covers `src/` + `scripts/`)\n- `yarn lint` — ESLint\n- `yarn test` — Vitest (unit tests, mocked Graph)\n- `yarn dev` — incremental rebuild on save (`tsc --watch` + `tsc-alias --watch`); `dist/` stays runnable\n\n> Use Yarn (Classic), not npm. The repo's lockfile is `yarn.lock` — `package-lock.json` should not be committed.\n\n### End-to-end smoke test\n\n`scripts/smoke.ts` exercises every shipped tool against a real OneNote account. It's not in CI — needs real credentials.\n\n```sh\n# One-time: register an Entra app (see Quick start above) and sign in\nONENOTE_MCP_CLIENT_ID=<your-client-id> yarn build\nONENOTE_MCP_CLIENT_ID=<your-client-id> node dist/cli.js login\n\n# Then run the smoke test\nONENOTE_MCP_CLIENT_ID=<your-client-id> yarn smoke\n```\n\nIt's idempotent: reuses (or creates) a notebook called **OneNote MCP Smoke Test**, walks through 12 steps covering auth, list/search/read/create/update/delete and the multipart attachment path, and cleans up the pages it creates. Sections and section groups are left behind for the next run.\n\nIf you're using an AI coding assistant (Claude Code, Cursor, etc.), see [`CLAUDE.md`](CLAUDE.md) for project conventions, the arrow-function rule, and the tool-authoring checklist.\n\nCommits follow [Conventional Commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `chore:`, etc.). CI runs typecheck + lint + tests on every push and PR.\n\n### Roadmap\n\n- [x] `update_page` — in-place edits via Graph's `PATCH` syntax\n- [x] `create_section` / `create_notebook`\n- [x] Image and attachment upload (multipart create_page)\n- [x] Section group support (list + create + section-in-group targeting)\n- [ ] Streamed attachment uploads (avoid in-memory buffering for large files)\n- [ ] Resource-style page browsing (alongside the tool surface)\n\n---\n\n## License\n\n[MIT](LICENSE) © Ahmad Al Mezaal\n","readmeFilename":"README.md"}