notion-mcp-server 1.0.1 → 2.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +383 -192
  2. package/build/config/index.js +3 -1
  3. package/build/dispatch/concurrency.js +15 -0
  4. package/build/dispatch/idempotency.js +38 -0
  5. package/build/dispatch/index.js +175 -0
  6. package/build/dispatch/rate-limit.js +56 -0
  7. package/build/dispatch/retry.js +97 -0
  8. package/build/index.js +1 -1
  9. package/build/markdown/parse.js +265 -0
  10. package/build/operations/blocks.js +331 -0
  11. package/build/operations/comments.js +191 -0
  12. package/build/operations/data-sources.js +85 -0
  13. package/build/operations/databases.js +345 -0
  14. package/build/operations/files.js +239 -0
  15. package/build/operations/index.js +19 -0
  16. package/build/operations/pages.js +486 -0
  17. package/build/operations/registry.js +16 -0
  18. package/build/operations/users.js +101 -0
  19. package/build/prompts/index.js +105 -0
  20. package/build/schema/blocks.js +19 -138
  21. package/build/schema/database.js +27 -111
  22. package/build/schema/emit.js +68 -0
  23. package/build/schema/file.js +1 -1
  24. package/build/schema/filter-dsl.js +333 -0
  25. package/build/schema/icon.js +1 -1
  26. package/build/schema/page-properties.js +17 -3
  27. package/build/schema/page.js +12 -125
  28. package/build/schema/refs.js +16 -0
  29. package/build/schema/rich-text.js +1 -1
  30. package/build/server/index.js +16 -3
  31. package/build/services/auth.js +19 -0
  32. package/build/services/notion.js +14 -17
  33. package/build/tools/index.js +119 -21
  34. package/build/utils/error.js +125 -86
  35. package/build/utils/handler.js +11 -0
  36. package/build/utils/learning-error.js +40 -0
  37. package/build/utils/notion-types.js +16 -0
  38. package/build/utils/paginate.js +35 -0
  39. package/build/utils/schema-slice.js +156 -0
  40. package/build/utils/slim.js +269 -0
  41. package/package.json +13 -7
  42. package/build/resources/imageList.js +0 -62
  43. package/build/resources/index.js +0 -1
  44. package/build/resources/predictionList.js +0 -43
  45. package/build/resources/svgList.js +0 -69
  46. package/build/schema/comments.js +0 -60
  47. package/build/schema/notion.js +0 -57
  48. package/build/schema/richText.js +0 -757
  49. package/build/schema/tools.js +0 -17
  50. package/build/schema/users.js +0 -39
  51. package/build/services/loggs.js +0 -13
  52. package/build/services/replicate.js +0 -23
  53. package/build/tools/appendBlockChildren.js +0 -25
  54. package/build/tools/batchAppendBlockChildren.js +0 -33
  55. package/build/tools/batchDeleteBlocks.js +0 -32
  56. package/build/tools/batchMixedOperations.js +0 -58
  57. package/build/tools/batchUpdateBlocks.js +0 -33
  58. package/build/tools/blocks.js +0 -34
  59. package/build/tools/comments.js +0 -81
  60. package/build/tools/createDatabase.js +0 -18
  61. package/build/tools/createPage.js +0 -18
  62. package/build/tools/createPrediction.js +0 -28
  63. package/build/tools/database.js +0 -16
  64. package/build/tools/deleteBlock.js +0 -24
  65. package/build/tools/formatRichText.js +0 -83
  66. package/build/tools/generateImage.js +0 -48
  67. package/build/tools/generateImageVariants.js +0 -105
  68. package/build/tools/generateMultipleImages.js +0 -60
  69. package/build/tools/generateSVG.js +0 -43
  70. package/build/tools/getPrediction.js +0 -22
  71. package/build/tools/pages.js +0 -22
  72. package/build/tools/predictionList.js +0 -30
  73. package/build/tools/queryDatabase.js +0 -22
  74. package/build/tools/retrieveBlock.js +0 -24
  75. package/build/tools/retrieveBlockChildren.js +0 -32
  76. package/build/tools/searchPage.js +0 -24
  77. package/build/tools/updateBlock.js +0 -25
  78. package/build/tools/updateDatabase.js +0 -18
  79. package/build/tools/updatePage.js +0 -40
  80. package/build/tools/updatePageProperties.js +0 -21
  81. package/build/tools/users.js +0 -75
  82. package/build/types/blocks.js +0 -12
  83. package/build/types/comments.js +0 -7
  84. package/build/types/database.js +0 -6
  85. package/build/types/notion.js +0 -1
  86. package/build/types/page.js +0 -8
  87. package/build/types/richText.js +0 -1
  88. package/build/types/tools.js +0 -1
  89. package/build/types/users.js +0 -6
  90. package/build/utils/blob.js +0 -5
  91. package/build/utils/image.js +0 -34
  92. package/build/utils/index.js +0 -1
  93. package/build/utils/richText.js +0 -174
  94. package/build/validation/blocks.js +0 -568
  95. package/build/validation/notion.js +0 -51
  96. package/build/validation/page.js +0 -262
  97. package/build/validation/richText.js +0 -744
  98. package/build/validation/tools.js +0 -16
  99. /package/build/{types/index.js → operations/types.js} +0 -0
package/README.md CHANGED
@@ -1,289 +1,480 @@
1
- # Notion MCP Server
1
+ # Notion MCP Server — Connect Claude, Cursor & ChatGPT to Notion via Model Context Protocol
2
2
 
3
3
  ![License](https://img.shields.io/badge/license-MIT-green)
4
4
  ![TypeScript](https://img.shields.io/badge/TypeScript-4.9+-blue)
5
5
  ![Model Context Protocol](https://img.shields.io/badge/MCP-Enabled-purple)
6
- [![smithery badge](https://smithery.ai/badge/@awkoy/notion-mcp-server)](https://smithery.ai/server/@awkoy/notion-mcp-server)
6
+ [![notion-mcp-server on Smithery](https://smithery.ai/badge/@awkoy/notion-mcp-server)](https://smithery.ai/server/@awkoy/notion-mcp-server)
7
7
  ![NPM Downloads](https://img.shields.io/npm/dw/notion-mcp-server)
8
8
  ![Stars](https://img.shields.io/github/stars/awkoy/notion-mcp-server)
9
9
 
10
- **Notion MCP Server** is a Model Context Protocol (MCP) server implementation that enables AI assistants to interact with Notion's API. This production-ready server provides a complete set of tools and endpoints for reading, creating, and modifying Notion content through natural language interactions.
10
+ An agent-first **Notion MCP server** (Model Context Protocol) that connects Claude, Cursor, ChatGPT, Claude Desktop, Cline, Zed and other MCP-compatible AI clients to Notion. Sign in once with your Notion **Personal Access Token (PAT)** — no per-page sharing dance, no extra integration to set up. Your AI sees the Notion pages you authorize the token for (typically your whole workspace) and can create pages, query databases, append blocks, leave comments, and upload files in natural language.
11
11
 
12
- > 🚧 **Active Development**: Database support is now available! Comments and user management tools have been added. If you find this project useful, please consider giving it a star - it helps me know that this work is valuable to the community and motivates further development.
12
+ > **v2.4 built for AI agents, not REST clients.** Two MCP tools instead of 36 endpoints, batched mutations, idempotency keys, automatic retries on Notion rate limits, self-healing validation errors (now path-sliced to <1KB), slim token-efficient responses, and a markdown shortcut so the model can write a whole page in one call.
13
13
 
14
14
  <a href="https://glama.ai/mcp/servers/zrh07hteaa">
15
- <img width="380" height="200" src="https://glama.ai/mcp/servers/zrh07hteaa/badge" />
15
+ <img width="380" height="200" src="https://glama.ai/mcp/servers/zrh07hteaa/badge" alt="Notion MCP Server on Glama" />
16
16
  </a>
17
17
 
18
18
  ## 📑 Table of Contents
19
19
 
20
- - [Getting Started & Integration](#-getting-started--integration)
21
- - [Setup Process](#setup-process)
22
- - [Cursor Integration](#cursor-integration)
23
- - [Claude Desktop Integration](#claude-desktop-integration)
24
- - [Features](#-features)
25
- - [Documentation](#-documentation)
26
- - [Available Tools](#available-tools)
27
- - [Available Resources](#available-resources)
20
+ - [5-minute install (no coding required)](#-5-minute-install-no-coding-required)
21
+ - [Why this server? (vs. the official Notion MCP)](#-why-this-server-vs-the-official-notion-mcp)
22
+ - [Developer install](#-developer-install)
23
+ - [Authentication: PAT (recommended) vs. Internal Integration](#authentication-pat-recommended-vs-internal-integration)
24
+ - [Get a Personal Access Token — full walkthrough](#get-a-personal-access-token--full-walkthrough)
25
+ - [Backward compatibility from v1.x](#backward-compatibility-from-v1x)
26
+ - [Claude Code / Cursor / Claude Desktop](#claude-code--cursor--claude-desktop)
27
+ - [Docker / Podman / OrbStack](#docker--podman--orbstack)
28
+ - [Optional `NOTION_PAGE_ID`](#optional-notion_page_id)
29
+ - [Features: what this Notion MCP server does](#-features-what-this-notion-mcp-server-does)
30
+ - [MCP tools for Notion (`notion_execute` & `notion_describe`)](#-mcp-tools-for-notion-notion_execute--notion_describe)
31
+ - [`notion_execute`](#notion_execute)
32
+ - [`notion_describe`](#notion_describe)
33
+ - [Operations menu (35 ops, plus one alias)](#operations-menu-35-ops-plus-one-alias)
28
34
  - [Development](#-development)
29
- - [Technical Details](#-technical-details)
30
- - [Troubleshooting](#-troubleshooting)
35
+ - [Technical details: how the Notion MCP server is built](#-technical-details-how-the-notion-mcp-server-is-built)
36
+ - [Troubleshooting the Notion MCP server](#-troubleshooting-the-notion-mcp-server)
37
+ - [FAQ: Notion MCP server](#-faq-notion-mcp-server)
31
38
  - [Contributing](#-contributing)
32
39
  - [License](#-license)
33
40
 
34
- ## 🚀 Getting Started & Integration
41
+ ---
35
42
 
36
- ### Setup Process
43
+ ## 🪄 5-minute install (no coding required)
37
44
 
38
- 1. **Obtain a Notion API Key**
39
- - Create an integration at [Notion Developers](https://www.notion.so/my-integrations)
40
- - Copy your API key
41
-
42
- 2. **Enable Integration for Your Pages**
43
- - Select an existing page or create a new one in Notion
44
- - Click the "..." menu in the top right corner
45
- - Go to "Connections"
46
- - Find and enable your integration from the list
47
-
48
- ![Notion Page Connection](page_connection.png)
45
+ You don't need to know what a terminal is. If you can copy text and paste it into two boxes, you can finish this.
49
46
 
50
- 3. **Choose Your Integration Method**
51
- - Follow one of the integration options below based on your preferred MCP client
47
+ ### What you'll get
48
+ After setup, you can tell Claude things like:
52
49
 
53
- 4. **Ask Your AI Assistant to Interact with Notion**
54
- - "Create a new page with today's tasks"
55
- - "Update my meeting notes in Notion"
56
- - "Add bullet points to my meeting notes page"
57
- - "Create a new database for tracking projects"
58
- - "Add new entries to my task database"
59
- - "Add a comment to my project page"
60
- - "Show me all comments on this document"
61
- - "List all users in my workspace"
62
- - "Get information about a specific user"
50
+ - *"Make a page in my Personal workspace called 'Q3 plan' and add a checklist of these five items."*
51
+ - *"Find every page in my Tasks database where Status is 'Doing' and tell me which are overdue."*
52
+ - *"Comment on yesterday's meeting notes with a one-paragraph summary."*
63
53
 
64
- ### Cursor Integration
54
+ Claude reads and writes Notion directly — no copy/paste, no browser tabs.
65
55
 
66
- #### Method 1: Using mcp.json
56
+ ### What you'll need
57
+ 1. A Notion account.
58
+ 2. The [Claude Desktop app](https://claude.ai/download) installed. (Cursor and Claude Code work too — see [Developer install](#-developer-install).)
59
+ 3. About 5 minutes.
67
60
 
68
- 1. Create or edit the `.cursor/mcp.json` file in your project directory:
61
+ ### Step 1 Get your Notion Personal Access Token
62
+
63
+ A Personal Access Token (PAT) is like a key that lets the AI act as **you** inside Notion. It can see every page **you** can see — no per-page setup.
64
+
65
+ 1. Open the Notion developer portal: **[notion.so/profile/integrations](https://www.notion.so/profile/integrations)** (while logged into Notion). Same page if you go through the app: **Settings → Connections → Develop or manage integrations**.
66
+ 2. Open the **Personal access tokens** tab → click **+ New personal access token**.
67
+ 3. Give it a name like `Claude`, pick the **workspace** the token should act in, leave the default capabilities checked, and click **Create token**.
68
+ 4. **Copy** the token — Notion shows the full value **only once**. It starts with `ntn_`. Treat it like a password.
69
+
70
+ > PATs **expire 1 year after creation**. Set a calendar reminder to rotate before then, or auth will start failing.
71
+ >
72
+ > Don't see a "Personal access tokens" tab? Your workspace admin may have disabled them — use the [Internal Integration alternative](#authentication-pat-recommended-vs-internal-integration).
73
+ >
74
+ > Need more detail (rotation, revocation, what a PAT can/can't do)? See the [full PAT walkthrough](#get-a-personal-access-token--full-walkthrough) further down. Official reference: [Notion PAT guide](https://developers.notion.com/guides/get-started/personal-access-tokens).
75
+
76
+ ### Step 2 — Tell Claude Desktop where the server lives
77
+
78
+ 1. Open Claude Desktop → click **Claude** (top-left menu on Mac, or the hamburger menu on Windows) → **Settings** → **Developer** → **Edit Config**.
79
+ 2. A file called `claude_desktop_config.json` opens in a text editor. **Don't panic at the curly braces** — it's just text. We're going to swap all of it out.
80
+ 3. **Select all** the text in that file (`Cmd+A` on Mac, `Ctrl+A` on Windows), **delete it**, then paste the block below.
69
81
 
70
82
  ```json
71
83
  {
72
84
  "mcpServers": {
73
- "notion-mcp-server": {
74
- "command": "env NOTION_TOKEN=YOUR_KEY NOTION_PAGE_ID=YOUR_PAGE_ID npx",
75
- "args": ["-y", "notion-mcp-server"]
85
+ "notion": {
86
+ "command": "npx",
87
+ "args": ["-y", "github:awkoy/notion-mcp-server"],
88
+ "env": {
89
+ "NOTION_TOKEN": "ntn_paste_your_token_here"
90
+ }
76
91
  }
77
92
  }
78
93
  }
79
94
  ```
80
95
 
81
- 2. Replace `YOUR_KEY` and `YOUR_PAGE_ID` with your actual Notion API key and page ID
82
- 3. Restart Cursor to apply the changes
96
+ > **What is this block?** It tells Claude Desktop how to launch the Notion connector. `npx` is a small tool that downloads and runs the connector automatically the first time — you don't install anything separately, it happens in the background (the first run may take 30–60 seconds while it builds). `env` is where your Notion token goes. Leave every quote mark and bracket exactly as shown; the only thing you change is the token.
83
97
 
84
- #### Method 2: Manual Mode
98
+ 4. Replace `ntn_paste_your_token_here` with the token you copied in Step 1 — **leave the quotation marks around it**.
99
+ 5. **Save** the file (`Cmd+S` / `Ctrl+S`).
100
+ 6. **Quit Claude Desktop completely** (Mac: `Cmd+Q`, not just closing the window — Windows: right-click the tray icon → Quit) and reopen it.
85
101
 
86
- 1. Open Cursor and go to Settings
87
- 2. Navigate to the "MCP" or "Model Context Protocol" section
88
- 3. Click "Add Server" or equivalent
89
- 4. Enter the following command in the appropriate field:
102
+ ### Step 2b Did it work?
90
103
 
104
+ After Claude Desktop reopens, start a new chat and type **`/`** in the message box. You should see `notion_execute` and `notion_describe` appear in the slash-command list. If they don't, the connection didn't take — go back to **Settings → Developer → Edit Config**, check there's no typo in the token (it must stay between the quotation marks), and confirm you fully quit and reopened Claude Desktop. Common pitfalls are also covered in [Troubleshooting](#-troubleshooting-the-notion-mcp-server).
105
+
106
+ ### Step 3 — Try it
107
+
108
+ In a new Claude chat, type:
109
+
110
+ > *"Use Notion to make a new page called 'Hello from Claude' under my workspace and add a checklist of three things I want to try today."*
111
+
112
+ You should see Claude call the `notion_execute` tool and report back with a page link. Click it — your new page is live in Notion.
113
+
114
+ That's it. If something doesn't work, the most common fix is in [Troubleshooting](#-troubleshooting-the-notion-mcp-server) below — usually a token typo or Claude Desktop not being fully quit and reopened. The rest of this README covers Docker, Cursor, Claude Code, and self-hosting for developers.
115
+
116
+ ---
117
+
118
+ ## ⚡ Why this server? (vs. the official Notion MCP)
119
+
120
+ There's a [first-party Notion MCP server](https://github.com/makenotion/notion-mcp-server). It works for simple one-off calls. For agent workloads — repeated queries, bulk mutations, long context windows — it gets expensive fast: one MCP tool per endpoint, no batching, no idempotency, raw response shapes. Those choices add up to real token cost and real latency.
121
+
122
+ This server is designed from the agent's side of the protocol.
123
+
124
+ | Capability | Official Notion MCP | **This server (designed for agents)** |
125
+ | --- | --- | --- |
126
+ | **Tool surface** | 22 tools (one per endpoint) loaded into context | **2 tools** (`notion_execute`, `notion_describe`) — the LLM loads ~90% less schema |
127
+ | **Operations covered** | ~22 endpoints | **35 operations** (plus a `trash_page` alias of `archive_page`) across pages, blocks, databases, data sources, comments, users, files |
128
+ | **Primary auth** | Internal Integration token + per-page "Connect" sharing | **Personal Access Token (PAT)** — uses the pages you've authorized for the token, zero per-page Connect step |
129
+ | **Batch mutations** | Not documented | ✅ Universal `{ items: [...] }` envelope; runs up to **10 in parallel** |
130
+ | **Atomic batches + rollback** | Not documented | ✅ `atomic: true` aborts on first failure, best-effort archives entities created earlier |
131
+ | **Idempotency** | Not documented | ✅ `idempotency_key` — same key + same op returns the cached result for 5 minutes |
132
+ | **Rate-limit handling** | Not documented (429s bubble up) | ✅ Shared token-bucket limiter (3 req/s default, configurable via `NOTION_RATE_LIMIT`) + exponential backoff on 429/5xx/timeouts, honors `Retry-After` |
133
+ | **Response shapes** | Raw Notion SDK JSON | **Slim shapers by default** — drops `archived: false`, `created_time`, `last_edited_time`, `in_trash: false`, empty descriptions, etc. `verbose: true` to opt out |
134
+ | **Database queries** | Raw `properties` bag per row | **Flattened** name → primitive map (title, rich_text, number, select, multi_select, status, date, people, files, checkbox, url, email, phone_number, formula, relation, rollup, unique_id, verification, created_by, last_edited_by, timestamps) |
135
+ | **Wire format** | Default SDK serialization | **Compact (un-indented) JSON** — ~30% smaller payloads vs. indented output, identical to parse |
136
+ | **Markdown input** | Page-level markdown editing supported | ✅ `markdown` shortcut on `create_page` / `append_blocks` / `update_block`, full markdown round-trip via `get_page_markdown` / `update_page_markdown`, plus markdown comment bodies — full GFM (paragraphs, headings 1–4, lists, to-dos with nested children, blockquotes, fenced code with language detection, images, dividers, inline bold/italic/strike/code/links) |
137
+ | **File uploads** | Not in the documented tool surface | ✅ `upload_file` handles single-part and multi-part (5 MB chunks) transparently; MIME inferred from filename; rejects `application/octet-stream` |
138
+ | **Validation errors** | Plain error string | **Self-healing**: `{ code, message, path, issues, schema, example, fix }` — agent corrects bad payloads in one round-trip without calling describe |
139
+ | **Notion API version** | Not pinned in client config | Pinned to `2025-09-03` (the modern data-sources line) |
140
+
141
+ ### Real-world impact
142
+
143
+ - **Renaming 50 pages.** Without a batch envelope, the agent issues 50 separate `update-page` MCP calls — each one re-loading the tool schema and serialized through the agent's reasoning loop. With this server, the agent issues one `notion_execute` call with `{ items: [...], concurrency: 10 }`. Wall-clock improvement is roughly an order of magnitude on typical batch sizes; the bigger win is the tokens saved on prompt overhead.
144
+ - **Loading the tool list into the agent's context.** Official server: 22 schema blobs every conversation. This server: 2 schema blobs — and only those 2 ever appear in the agent's tool list, regardless of which of the 35 operations the agent ends up calling.
145
+ - **Reading a 100-row database.** Official server returns the raw Notion `properties` bag per row. This server flattens it; for a typical CRM table this is roughly **5–10× fewer tokens** without losing information.
146
+
147
+ ---
148
+
149
+ ## 🚀 Developer install
150
+
151
+ ### Authentication: PAT (recommended) vs. Internal Integration
152
+
153
+ There are two ways to authenticate. Both use the `NOTION_TOKEN` env var — only how you obtain the token differs.
154
+
155
+ | | **Personal Access Token** (recommended) | **Internal Integration** (legacy) |
156
+ | --- | --- | --- |
157
+ | Where you get it | [notion.so/profile/integrations](https://www.notion.so/profile/integrations) → **Personal access tokens** tab → **+ New personal access token** | [notion.so/profile/integrations/internal](https://www.notion.so/profile/integrations/internal) → **+ New connection** |
158
+ | Token prefix | `ntn_…` | `ntn_…` (new) or `secret_…` (older) |
159
+ | Scope | Everything **you** can see | Only pages where you've clicked **• • • → Connect → \<integration\>** |
160
+ | Setup friction | None — works immediately | Per-page Connect dance for every page or database the agent should touch |
161
+ | When to use | Default. Personal workspaces, team workspaces where you're authorized, prototyping. | When a workspace admin requires explicit per-resource scoping for compliance, or for shared production bots. |
162
+
163
+ The rest of this README assumes PAT. Swap in an integration secret if you prefer the scoped model — every command below is identical.
164
+
165
+ > 💡 **Heads-up:** most "object_not_found" errors are a wrong auth choice, not a bug. If your agent reports "Could not find page" on pages you can see in Notion, you're almost certainly using an Internal Integration token that hasn't been Connected to those pages — switch to a PAT.
166
+
167
+ ### Get a Personal Access Token — full walkthrough
168
+
169
+ [Step 1 of the 5-minute install](#step-1--get-your-notion-personal-access-token) covers the happy path. This section covers what surrounds it: capabilities, expiry, revocation, and the admin-disabled fallback.
170
+
171
+ > 📖 Official: [Notion PAT guide](https://developers.notion.com/guides/get-started/personal-access-tokens) · [Authorization overview](https://developers.notion.com/docs/authorization).
172
+
173
+ #### What a PAT can and can't do
174
+
175
+ | Can | Can't |
176
+ | --- | --- |
177
+ | Read every page you have access to | Access workspaces or pages you personally can't see |
178
+ | Create / update pages and databases in workspaces where you have edit rights | Bypass workspace permission rules |
179
+ | Add comments under your identity | Act as another user |
180
+ | Upload files via the File Upload API | Modify workspace-level admin settings |
181
+
182
+ A PAT is a **scope = your account**. If you lose edit access to a page, the PAT loses it too. Issue separate tokens to teammates — don't share one.
183
+
184
+ #### Expiry and rotation
185
+
186
+ **PATs expire 1 year after creation** ([Notion docs](https://developers.notion.com/guides/get-started/personal-access-tokens)). After expiry, every API call returns an auth error until you replace the token. Set a calendar reminder for ~11 months out.
187
+
188
+ #### Revoking a PAT
189
+
190
+ 1. Open **[notion.so/profile/integrations](https://www.notion.so/profile/integrations)** → **Personal access tokens** tab.
191
+ 2. Find the token by name → **• • • → Revoke**.
192
+ 3. Update `NOTION_TOKEN` in your MCP client config and restart the client.
193
+
194
+ Workspace admins can revoke any user's PATs from **Settings & members → Connections → All personal access tokens**. Revocation is immediate.
195
+
196
+ #### Workspace admin disabled PATs?
197
+
198
+ Some enterprise workspaces only allow scoped Internal Integrations. Two options:
199
+
200
+ 1. **Ask your admin to enable PATs** for your account.
201
+ 2. **Use the [Internal Integration](#authentication-pat-recommended-vs-internal-integration) path** — same `NOTION_TOKEN` env var; create it at **[notion.so/profile/integrations/internal](https://www.notion.so/profile/integrations/internal) → + New connection**, then click **• • • → Connect** on every page or database you want the agent to touch.
202
+
203
+ ### Backward compatibility from v1.x
204
+
205
+ If you ran a v1.x setup, **nothing in your environment needs to change**. Both env vars still work:
206
+
207
+ | Env var | Status in v2.4 | Notes |
208
+ | --- | --- | --- |
209
+ | `NOTION_TOKEN` | ✅ Required | Accepts **PATs** (`ntn_…`, recommended) and **Internal Integration secrets** (`secret_…` or `ntn_…`, legacy). Identical handling. |
210
+ | `NOTION_PAGE_ID` | ✅ Optional | Still works as the default parent page for `create_page` / `create_database` when no `parent` is passed. v2 added a clean `missing_parent` validation error instead of v1's crash when neither is provided. |
211
+ | `NOTION_RATE_LIMIT` | ✅ New, optional | Requests per second for the shared limiter. Defaults to `3` (Notion's documented per-integration limit). |
212
+ | `NOTION_DAILY_LOG_PAGE_ID` | ✅ Optional | Used only by the daily-log MCP prompt. Ignore if you don't call that prompt. |
213
+
214
+ The only v2 break is the **tool surface itself** — v1's `notion_pages`, `notion_blocks`, `notion_database`, `notion_comments`, `notion_users` are replaced by `notion_execute` and `notion_describe`. Modern MCP clients (Claude Code, Cursor, Claude Desktop) rediscover tools at startup, so they pick up the new surface automatically. If your client hard-codes the v1 tool names, see [MIGRATION.md](./MIGRATION.md) for the rename map.
215
+
216
+ A typical v1.x invocation continues to work unchanged:
217
+
218
+ ```bash
219
+ NOTION_TOKEN=secret_xxx NOTION_PAGE_ID=abc123... node build/index.js
91
220
  ```
92
- env NOTION_TOKEN=YOUR_KEY NOTION_PAGE_ID=YOUR_PAGE_ID npx -y notion-mcp-server
93
- ```
94
221
 
95
- 5. Replace `YOUR_KEY` and `YOUR_PAGE_ID` with your actual Notion API key and page ID
96
- 6. Save the settings and restart Cursor if necessary
222
+ ### Claude Code / Cursor / Claude Desktop
223
+
224
+ > ⚠️ **Heads-up while the v2 line stabilizes on npm.** The latest published `notion-mcp-server` on npm is **v1.x**; this repo is **v2.4**. Until v2 is published, the install snippets below pull from GitHub via `npx -y github:awkoy/notion-mcp-server` (npm builds from source on first run). Once v2 is on npm, you can swap that for plain `notion-mcp-server@^2`.
97
225
 
98
- ### Claude Desktop Integration
226
+ **Claude Code:**
99
227
 
100
- 1. Create or edit the `mcp.json` file in your configuration directory:
228
+ ```bash
229
+ claude mcp add notion -s user \
230
+ -e NOTION_TOKEN=ntn_paste_your_token_here \
231
+ -- npx -y github:awkoy/notion-mcp-server
232
+ ```
233
+
234
+ **Cursor** (`~/.cursor/mcp.json`) **or Claude Desktop** (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` · Windows: `%APPDATA%\Claude\claude_desktop_config.json`):
101
235
 
102
236
  ```json
103
237
  {
104
238
  "mcpServers": {
105
- "notion-mcp-server": {
239
+ "notion": {
106
240
  "command": "npx",
107
- "args": ["-y", "notion-mcp-server"],
241
+ "args": ["-y", "github:awkoy/notion-mcp-server"],
108
242
  "env": {
109
- "NOTION_TOKEN": "YOUR_KEY",
110
- "NOTION_PAGE_ID": "YOUR_PAGE_ID"
243
+ "NOTION_TOKEN": "ntn_paste_your_token_here"
111
244
  }
112
245
  }
113
246
  }
114
247
  }
115
248
  ```
116
249
 
117
- 2. Replace `YOUR_KEY` and `YOUR_PAGE_ID` with your actual Notion API key and page ID
118
- 3. Restart Claude Desktop to apply the changes
250
+ **Local build (no npx):**
119
251
 
120
- ## 🌟 Features
252
+ ```bash
253
+ git clone https://github.com/awkoy/notion-mcp-server.git
254
+ cd notion-mcp-server
255
+ npm install && npm run build
121
256
 
122
- - **📝 Notion Integration** - Interact with Notion databases, pages, and blocks
123
- - **🔌 Universal MCP Compatibility** - Works with all MCP clients including Cursor, Claude Desktop, Cline, and Zed
124
- - **🔍 Data Retrieval** - Fetch information from Notion pages, blocks, and databases
125
- - **✏️ Content Creation** - Create and update Notion pages and blocks
126
- - **📊 Block Management** - Append, update, and delete blocks within Notion pages
127
- - **💾 Database Operations** - Create, query, and update databases
128
- - **🔄 Batch Operations** - Perform multiple operations in a single request
129
- - **🗑️ Archive & Restore** - Archive and restore Notion pages
130
- - **🔎 Search Functionality** - Search Notion pages and databases by title
131
- - **💬 Comments Management** - Get, create, and reply to comments on pages and discussions
132
- - **👥 User Management** - Retrieve workspace users and user information
257
+ claude mcp add notion -s user \
258
+ -e NOTION_TOKEN=ntn_paste_your_token_here \
259
+ -- node "$(pwd)/build/index.js"
260
+ ```
133
261
 
134
- ## 📚 Documentation
262
+ ### Docker / Podman / OrbStack
135
263
 
136
- ### Available Tools
264
+ ```bash
265
+ claude mcp add notion -s user \
266
+ -e NOTION_TOKEN=ntn_paste_your_token_here \
267
+ -- docker run --rm -i -e NOTION_TOKEN ghcr.io/awkoy/notion-mcp-server:latest
268
+ ```
137
269
 
138
- The server provides the following tools for interacting with Notion:
270
+ The `-i` flag is required (stdio transport). `-e NOTION_TOKEN` (no `=value`) forwards the env var from the parent process.
139
271
 
140
- #### Page Operations
272
+ For Cursor / Claude Desktop:
141
273
 
142
- ##### `create_page`
143
- Create a new page in Notion with specified content
274
+ ```json
275
+ {
276
+ "mcpServers": {
277
+ "notion": {
278
+ "command": "docker",
279
+ "args": ["run", "--rm", "-i", "-e", "NOTION_TOKEN", "ghcr.io/awkoy/notion-mcp-server:latest"],
280
+ "env": { "NOTION_TOKEN": "ntn_paste_your_token_here" }
281
+ }
282
+ }
283
+ }
284
+ ```
144
285
 
145
- ##### `update_page_properties`
146
- Update the properties of an existing Notion page
286
+ The published image is OCI-compliant — **Podman**, **OrbStack**, **colima**, **Rancher Desktop**, **Finch**, and **nerdctl** all work with the same flags (substitute the runtime's CLI for `docker`). Docker Desktop is not required.
147
287
 
148
- ##### `archive_page`
149
- Archive (move to trash) a Notion page by ID
288
+ ### Optional `NOTION_PAGE_ID`
150
289
 
151
- ##### `restore_page`
152
- Restore a previously archived Notion page by ID
290
+ A default parent page for `create_page` / `create_database` when the caller doesn't pass one. Operations that need a parent and don't get one return a clear validation error instead of crashing.
153
291
 
154
- ##### `search_pages`
155
- Search for pages and databases in Notion by title
292
+ To find a page ID: open the page in Notion → **Share → Copy link**. The ID is the last 32 characters of the URL.
156
293
 
157
- #### Database Operations
294
+ ```bash
295
+ claude mcp add notion -s user \
296
+ -e NOTION_TOKEN=ntn_xxx \
297
+ -e NOTION_PAGE_ID=abc123... \
298
+ -- npx -y github:awkoy/notion-mcp-server
299
+ ```
158
300
 
159
- ##### `create_database`
160
- Create a new database in Notion with specified properties
301
+ ---
161
302
 
162
- ##### `query_database`
163
- Query a database in Notion with filters, sorts, and pagination
303
+ ## 🌟 Features: what this Notion MCP server does
164
304
 
165
- ##### `update_database`
166
- Update an existing database's properties, title, or description
305
+ - **Two-tool surface** — `notion_execute` (do it) + `notion_describe` (learn the shape). The whole API is one schema deep.
306
+ - **Universal batch envelope** — every mutating op accepts `{ items: [...], atomic?, idempotency_key?, concurrency? }`. Per-item validation, per-item results, summary counts.
307
+ - **Atomic batches with best-effort rollback** — `atomic: true` aborts on first failure and archives anything created earlier in the batch.
308
+ - **Idempotency keys** — same `(operation, idempotency_key)` returns the cached batch result for 5 minutes (max 512 entries). Safe to retry on flaky networks.
309
+ - **Rate-limit + retry baked in** — shared token-bucket limiter (3 req/s default, configurable via `NOTION_RATE_LIMIT`); transient SDK failures (429, 5xx, timeouts) auto-retry with exponential backoff and honor `Retry-After`.
310
+ - **Self-healing validation errors** — every failure returns `{ schema, example, fix }`. The model corrects bad payloads in one round-trip — no extra `notion_describe` call needed.
311
+ - **Markdown shortcut** — `create_page` / `append_blocks` / `update_block` / `update_page_markdown` / comment bodies accept a `markdown` string (full GFM: paragraphs, headings 1–4, lists, to-dos with nested children, blockquotes, fenced code with language normalization, dividers, images, inline bold/italic/strike/code/links).
312
+ - **Slim responses + flattened rows** — defaults drop noisy fields and the `query_database` rows flatten each property to a name → primitive map. `verbose: true` per call to get the raw SDK shape. Compact JSON wire format (~30% smaller payloads).
313
+ - **File uploads** — `upload_file` handles single-part and multi-part (5 MB chunks) transparently; auto-detects MIME from filename; rejects `application/octet-stream`.
314
+ - **Opt-in auto-pagination** — pass `paginate: true` on `search_pages`, `list_comments`, or `query_database` and the server walks `next_cursor` for you (capped by `page_limit`, default 10 pages ≈ 1000 items at `page_size: 100`). Other list ops return a single Notion page with `has_more` / `next_cursor`.
315
+ - **Typed `where` filter shorthand** — `query_database` accepts a `where` clause like `{Status: {equals: "Done"}, AND: [...]}` with operator objects (`eq`, `ne`, `gte`, `lte`, `contains`, `starts_with`, etc.); the server compiles it to Notion filter JSON. Pass raw Notion `filter` JSON for edge cases the shorthand can't express (the two fields are mutually exclusive).
316
+ - **Universal MCP compatibility** — Cursor, Claude Desktop, Claude Code, Cline, Zed, Continue, anything that speaks MCP stdio.
167
317
 
168
- #### Block Operations
318
+ ---
169
319
 
170
- ##### `retrieve_block`
171
- Retrieve a block from Notion by ID
320
+ ## 📚 MCP tools for Notion (`notion_execute` & `notion_describe`)
172
321
 
173
- ##### `retrieve_block_children`
174
- Retrieve the children of a block from Notion
322
+ The v2 server exposes exactly **two** MCP tools — your AI client only ever loads these two schemas, regardless of which of the 35 Notion operations you call.
175
323
 
176
- ##### `append_block_children`
177
- Append child blocks to a parent block in Notion
324
+ ### `notion_execute`
178
325
 
179
- ##### `update_block`
180
- Update a block's content in Notion
326
+ Run any Notion operation. Pass `{ operation, payload }` — payload is either a single object, or `{ items: [...] }` for batch mode.
181
327
 
182
- ##### `delete_block`
183
- Delete (move to trash) a block in Notion
328
+ **Single call:**
184
329
 
185
- #### Batch Operations
330
+ ```jsonc
331
+ {
332
+ "operation": "set_page_title",
333
+ "payload": { "page_id": "<page-id>", "title": "Q3 plan" }
334
+ }
335
+ ```
186
336
 
187
- ##### `batch_append_block_children`
188
- Append children to multiple blocks in a single operation
337
+ **Batch:**
189
338
 
190
- ##### `batch_update_blocks`
191
- Update multiple blocks in a single operation
339
+ ```jsonc
340
+ {
341
+ "operation": "set_page_title",
342
+ "payload": {
343
+ "items": [
344
+ { "page_id": "<p1>", "title": "First" },
345
+ { "page_id": "<p2>", "title": "Second" }
346
+ ],
347
+ "atomic": false,
348
+ "concurrency": 3,
349
+ "idempotency_key": "rename-pass-2025-05-26"
350
+ }
351
+ }
352
+ ```
192
353
 
193
- ##### `batch_delete_blocks`
194
- Delete multiple blocks in a single operation
354
+ **Markdown shortcut** (works in `create_page`, `append_blocks`, `update_block`, `update_page_markdown`):
195
355
 
196
- ##### `batch_mixed_operations`
197
- Perform a mix of append, update, and delete operations in a single request
356
+ ```jsonc
357
+ {
358
+ "operation": "create_page",
359
+ "payload": {
360
+ "parent": { "type": "page_id", "page_id": "<parent>" },
361
+ "title": "Notes",
362
+ "markdown": "# Heading\n\n- [ ] todo\n- [x] done\n\n```ts\nconst x = 1;\n```"
363
+ }
364
+ }
365
+ ```
198
366
 
199
- #### Comment Operations
367
+ **Self-healing errors:** if the payload doesn't validate, the response includes the full JSON Schema for that operation plus a working example, so the next call can be corrected without round-tripping through `notion_describe`.
200
368
 
201
- ##### `get_comments`
202
- Retrieve comments from a page or block with pagination support
369
+ ### `notion_describe`
203
370
 
204
- ##### `add_page_comment`
205
- Add a new comment to a Notion page
371
+ Return the JSON Schema + working example for a single operation. Use this when you want to see the shape of a complex op (filter expressions, mixed block batches, full database property definitions) before calling `notion_execute`.
206
372
 
207
- ##### `add_discussion_comment`
208
- Add a comment to an existing discussion thread
373
+ ```jsonc
374
+ { "operation": "query_database" }
375
+ ```
209
376
 
210
- #### User Operations
377
+ ### Operations menu (35 ops, plus one alias)
211
378
 
212
- ##### `get_list_users`
213
- Retrieve a paginated list of all users in the workspace
379
+ | Area | Operations |
380
+ | --- | --- |
381
+ | **Pages** | `create_page`, `get_page`, `set_page_title`, `set_page_property`, `set_page_properties`, `archive_page` (alias: `trash_page`), `restore_page`, `search_pages`, `move_page`, `get_page_markdown`, `update_page_markdown` |
382
+ | **Blocks** | `append_blocks`, `get_block`, `get_block_children`, `update_block`, `delete_block`, `batch_mixed_blocks` |
383
+ | **Databases** | `create_database`, `query_database`, `update_database` |
384
+ | **Data sources** | `list_data_sources`, `get_data_source`, `update_data_source` |
385
+ | **Comments** | `list_comments`, `add_page_comment`, `add_discussion_comment`, `get_comment`, `update_comment`, `delete_comment` |
386
+ | **Users** | `list_users`, `get_user`, `get_bot_user` |
387
+ | **Files** | `upload_file`, `list_file_uploads`, `get_file_upload` |
214
388
 
215
- ##### `get_user`
216
- Get detailed information about a specific user by ID
389
+ The authoritative list (with batchability) is also served as an MCP resource at `notion://operations` — useful as a one-shot cheat sheet for the LLM.
217
390
 
218
- ##### `get_bot_user`
219
- Retrieve the current bot user associated with the API token
391
+ ---
220
392
 
221
- ### Available Resources
393
+ ## 🛠 Development
222
394
 
223
- The server currently does not expose any resources, focusing instead on tool-based operations.
395
+ ```bash
396
+ git clone https://github.com/awkoy/notion-mcp-server.git
397
+ cd notion-mcp-server
398
+ npm install
224
399
 
225
- ## 🛠 Development
400
+ # Set NOTION_TOKEN (and optionally NOTION_PAGE_ID) in a .env file.
401
+ echo "NOTION_TOKEN=ntn_xxx" > .env
226
402
 
227
- 1. **Clone the Repository**
228
- ```
229
- git clone https://github.com/awkoy/notion-mcp-server.git
230
- cd notion-mcp-server
231
- ```
232
-
233
- 2. **Install Dependencies**
234
- ```
235
- npm install
236
- ```
237
-
238
- 3. **Set Up Environment Variables**
239
- - Create a `.env` file with:
240
- ```
241
- NOTION_TOKEN=your_notion_api_key
242
- NOTION_PAGE_ID=your_notion_page_id
243
- ```
244
-
245
- 4. **Build the Project**
246
- ```
247
- npm run build
248
- ```
249
-
250
- 5. **Run the Inspector**
251
- ```
252
- npm run inspector
253
- ```
254
-
255
- ## 🔧 Technical Details
256
-
257
- - Built using TypeScript and the MCP SDK (version 1.7.0+)
258
- - Uses the official Notion API client (@notionhq/client v2.3.0+)
259
- - Follows the Model Context Protocol specification
260
- - Implements tools for CRUD operations on Notion pages, blocks, and databases
261
- - Supports efficient batch operations for performance optimization
262
- - Validates input/output with Zod schemas
263
-
264
- ## ❓ Troubleshooting
265
-
266
- - **Common Issues**
267
- - **Authentication Errors**: Ensure your Notion token has the correct permissions and integration is enabled for your pages/databases
268
- - **Page Access Issues**: Make sure your integration has been added to the pages you're attempting to access
269
- - **Rate Limiting**: Notion API has rate limits - use batch operations to optimize requests
270
-
271
- - **Getting Help**
272
- - Create an issue on the [GitHub repository](https://github.com/awkoy/notion-mcp-server/issues)
273
- - Check the [Notion API documentation](https://developers.notion.com/reference/intro)
274
- - Visit the MCP community channels for assistance
403
+ npm run build # tsc -> build/
404
+ npm test # vitest smoke suite
405
+ npm run inspector # MCP inspector against the built binary
406
+ ```
275
407
 
276
- ## 🤝 Contributing
408
+ ---
277
409
 
278
- Contributions are welcome! Please feel free to submit a Pull Request.
410
+ ## 🔧 Technical details: how the Notion MCP server is built
279
411
 
280
- 1. Fork the repository
281
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
282
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
283
- 4. Push to the branch (`git push origin feature/amazing-feature`)
284
- 5. Open a Pull Request
412
+ - TypeScript + MCP SDK (`^1.29.0`)
413
+ - Notion SDK `@notionhq/client@^5.22.0`, pinned `Notion-Version: 2025-09-03`
414
+ - Zod 4 payload validation; emits draft-7 JSON Schema with `$defs` deduplication for error envelopes
415
+ - Markdown Notion blocks via the `remark` / `remark-gfm` pipeline
416
+ - Bounded-concurrency batch worker (default 3, max 10)
417
+ - Shared token-bucket rate limiter; `withRetry` wraps every dispatched call with exponential backoff on transient failures
418
+ - In-memory idempotency cache (5-minute TTL, 512 entries)
419
+ - Slim shapers per entity type (`slimPage`, `slimBlock`, `slimDatabase`, `slimDataSource`, `slimUser`, `slimComment`, `slimFileUpload`) with `verbose: true` opt-out
420
+ - Vitest smoke harness covering the markdown parser, slim shapers, schema emitter, dispatcher, batch partial success / atomic rollback / idempotency dedupe (`npm test`)
285
421
 
286
- ## 📄 License
422
+ ---
287
423
 
288
- This project is licensed under the MIT License - see the LICENSE file for details.
424
+ ## Troubleshooting the Notion MCP server
425
+
426
+ - **"object_not_found" / "Could not find ..."** — the integration token can only see pages explicitly shared with it. Switch to a PAT to skip per-page sharing.
427
+ - **"Notion auth failed" on every call** — the token was missing, revoked, or expired (PATs expire 1 year after creation). Check `NOTION_TOKEN` is set in your MCP client config, then open [notion.so/profile/integrations](https://www.notion.so/profile/integrations) → **Personal access tokens** and confirm yours is still listed and not past its expiry. If it expired, create a new one and update the env var.
428
+ - **"No parent page configured"** — pass `parent` in the call, or set `NOTION_PAGE_ID` to a default.
429
+ - **"multi_source_database" error from `query_database`** — your database has more than one data source. Call `list_data_sources` to get the IDs, then pass `data_source_id` instead of `database_id`.
430
+ - **Server logs "Notion auth check failed" on startup but tools still work** — the startup check is best-effort. If subsequent tool calls succeed, ignore the warning (Claude Code suppresses MCP stderr anyway).
431
+ - **Docker container exits immediately / "Connection closed"** — the `-i` flag is required so Docker keeps stdin open for the MCP stdio transport. `docker run --rm -i ...`, not `docker run --rm ...`.
432
+ - **Docker: "NOTION_TOKEN is not set" despite passing `-e`** — make sure the form is `-e NOTION_TOKEN` (forwards from parent env) or `-e NOTION_TOKEN=ntn_xxx` (inline value), not `-e NOTION_TOKEN ntn_xxx` (treated as two separate args).
433
+
434
+ ### Getting help
435
+
436
+ - [GitHub Issues](https://github.com/awkoy/notion-mcp-server/issues)
437
+ - [Notion API reference](https://developers.notion.com/reference/intro)
438
+ - [Model Context Protocol spec](https://modelcontextprotocol.io)
439
+
440
+ ---
441
+
442
+ ## 💬 FAQ: Notion MCP server
443
+
444
+ ### What is the Notion MCP server and how does it work?
445
+
446
+ The Notion MCP server is a Model Context Protocol (MCP) server that connects AI assistants — Claude, Cursor, ChatGPT, Claude Desktop, Cline, Zed, Continue, anything that speaks MCP — to your Notion workspace. It runs locally (or in Docker) and exposes two MCP tools (`notion_execute`, `notion_describe`) that the AI calls to read and write Notion. You authenticate once with a Notion Personal Access Token; everything else is natural language.
447
+
448
+ ### How do I connect Claude to Notion using MCP?
449
+
450
+ Follow the [5-minute install](#-5-minute-install-no-coding-required) above. The short version: get a Notion Personal Access Token at [notion.so/profile/integrations](https://www.notion.so/profile/integrations) → **Personal access tokens** tab → **+ New personal access token**, then paste it into Claude Desktop's `claude_desktop_config.json` (Settings → Developer → Edit Config). Quit and reopen Claude Desktop and you can ask it to create or read Notion pages directly.
451
+
452
+ ### What is a Notion Personal Access Token and how do I get one?
453
+
454
+ A Personal Access Token (PAT) is a key that lets an app act as **you** inside Notion. It can see every page you can see — no per-page "Connect" step required. Generate one at **[notion.so/profile/integrations](https://www.notion.so/profile/integrations) → Personal access tokens → + New personal access token**. The token starts with `ntn_…` and expires 1 year after creation. Treat it like a password; don't commit it to git or share it publicly. See the [full walkthrough](#get-a-personal-access-token--full-walkthrough) for capabilities, rotation, and admin restrictions, or the [official Notion guide](https://developers.notion.com/guides/get-started/personal-access-tokens).
455
+
456
+ ### What's the difference between this Notion MCP server and the official Notion MCP?
457
+
458
+ The official Notion MCP server exposes one MCP tool per REST endpoint (22 tools), uses an Internal Integration token (which requires per-page sharing in Notion's UI), and returns raw Notion JSON. This server exposes two tools that dispatch 36 named operations, defaults to a Personal Access Token (no per-page setup), batches mutations, retries on rate limits, and slims responses to cut token usage. See the [full comparison table](#-why-this-server-vs-the-official-notion-mcp).
459
+
460
+ ### Can I use this Notion MCP server with Cursor, ChatGPT, or Cline?
461
+
462
+ Yes. Anything that speaks the MCP stdio protocol works: Claude Desktop, Claude Code, Cursor, Cline, Zed, Continue, and self-hosted clients. Cursor uses `~/.cursor/mcp.json`; the config block is in the [Developer install](#-developer-install) section. ChatGPT support depends on the client you're using — any wrapper that supports MCP servers will work.
463
+
464
+ ### Is it safe to give an AI my Notion token?
465
+
466
+ The token is stored locally in your MCP client's config file and only sent to the Notion API (over HTTPS). It never leaves your machine except to talk to `api.notion.com`. The server itself is open source — you can read every line. That said, a PAT has the same access your account does, so don't paste it into untrusted clients, and revoke it at [notion.so/profile/integrations](https://www.notion.so/profile/integrations) → Personal access tokens if a laptop is lost.
467
+
468
+ ### Does this work with self-hosted or local-only LLMs?
469
+
470
+ Yes, as long as the LLM client supports MCP stdio (or you run a wrapper that bridges it). The server doesn't care what's on the other side of the protocol.
471
+
472
+ ---
473
+
474
+ ## 🤝 Contributing
475
+
476
+ PRs welcome. Fork → branch → commit → push → PR. Run `npm test` before submitting.
477
+
478
+ ## 📄 License
289
479
 
480
+ MIT — see [LICENSE](./LICENSE).