Notion MCP Server — Connect Claude, Cursor & VS Code to Notion

MCP serverWeb & browsing

This integration connects your AI to your Notion workspace, so it can work with your pages, databases, blocks, comments, and files. It signs in with a Notion access token and can also run unattended in CI pipelines and automated agents.

Unavailable. This server has no hosted endpoint yet, so Ahel can't serve it.

Add to setup to save this item as a reference. Ahel cannot run it, and signing in will not install it.

What your AI can do with it

  • Access your Notion pages
  • Use your Notion databases
  • Work with blocks, the pieces that make up page content
  • Work with comments on your pages
  • Handle files stored in Notion
  • Run unattended in CI pipelines and automated agents

Getting started

  1. Save this item in Your setup as a reference.
  2. Read the source or reference documentation for its setup requirements. Saving it here does not connect it to your AI.
  3. Check this page for availability before trying to install it through Ahel.

From the project's README

As published by awkoy/notion-mcp-server in README.md.

Give your AI full read/write access to Notion with one token and one paste. This is an agent-first Notion MCP server: your AI client (Claude Code, Claude Desktop, Cursor, VS Code, Cline, Zed — anything that speaks MCP) can create pages, query databases, append blocks, apply templates, comment, and upload files in natural language.

Three reasons it exists when Notion ships its own MCP:

  • Built for agents, not humans-in-the-loop. Notion's hosted MCP is OAuth-only — it cannot run headless. This server authenticates with a token, so it works in CI, cron jobs, background agents, and self-hosted deployments where nobody can click "Authorize".
  • 94% smaller tool footprint at connection. Three MCP tools (1,005 tokens, the operation menus included) instead of one schema per endpoint — the official open-source server loads 17,163 tokens of tool schemas before you do anything. Operation schemas load on demand via notion_describe, so even a typical multi-operation task stays 75–90% lighter. Measured, reproducible →
  • The operational stuff is built in. Batched mutations with atomic rollback, idempotency keys, automatic retry on rate limits, slim token-efficient responses, full markdown round-trip, and self-healing validation errors that let the model fix its own bad payloads in one turn.

⚡ Quick start

Step 1 — get a Notion token (1 minute). Open app.notion.com/developers/tokens (the Personal access tokens page of Notion's developer portal) → + New token → name it, pick your workspace → Create token → copy the ntn_… value. That's it — a PAT sees everything you can see, no per-page sharing required. (Page missing or empty? Your admin disabled PATs — see auth alternatives.)

Step 2 — add the server to your client.

Claude Code

claude mcp add notion -s user \
  -e NOTION_TOKEN=ntn_paste_your_token_here \
  -- npx -y notion-mcp-server

Cursor

Click the badge (then replace YOUR_NOTION_TOKEN in the generated entry), or add to ~/.cursor/mcp.json yourself:

{
  "mcpServers": {
    "notion": {
      "command": "npx",
      "args": ["-y", "notion-mcp-server"],
      "env": { "NOTION_TOKEN": "ntn_paste_your_token_here" }
    }
  }
}

VS Code (Copilot agent mode)

VS Code prompts for the token on install and stores it as a secret input.

Gemini CLI

gemini extensions install https://github.com/awkoy/notion-mcp-server

The repo ships a gemini-extension.json, so Gemini CLI installs it as an extension: it asks for your Notion token once (kept in your system keychain) and starts the server with npx.

Claude Desktop

Easiest: the one-click extension. Download notion-mcp-server.mcpb from the latest release, double-click it (or drag into Claude Desktop → Settings → Extensions), paste your Notion token when prompted — done. No config files, Node.js not required.

Or via the config file: Settings → Developer → Edit Config, then add:

{
  "mcpServers": {
    "notion": {
      "command": "npx",
      "args": ["-y", "notion-mcp-server"],
      "env": { "NOTION_TOKEN": "ntn_paste_your_token_here" }
    }
  }
}

Quit Claude Desktop fully (Cmd+Q / tray → Quit) and reopen. Never used a config file before? Follow the step-by-step walkthrough for non-developers — it assumes nothing.

Docker / Podman / OrbStack

claude mcp add notion -s user \
  -e NOTION_TOKEN=ntn_paste_your_token_here \
  -- docker run --rm -i -e NOTION_TOKEN ghcr.io/awkoy/notion-mcp-server:latest

The -i flag is required (stdio transport). The image is OCI-compliant — Podman, OrbStack, colima, Rancher Desktop, Finch, and nerdctl all work with the same flags. For a long-running HTTP container (and the health check that goes with it), see Remote / HTTP transport.

Step 3 — try it. In a new chat:

"Use Notion to make a page called 'Hello from my agent' and add a checklist of three things to try today."

Your AI calls notion_write and replies with a live page link.

💡 What your AI can do with it

  • "Find every row in my Tasks database where Status is 'Doing' and tell me which are overdue." — typed where filters, flattened rows
  • "Rename these 50 pages to the new convention." — one batched call, 10-way parallel, idempotent retry
  • "Create a page from my 'Weekly review' template and fill in this summary." — Notion templates support
  • "Rewrite that spec page: fix the headings and add a code sample." — full markdown round-trip (get_page_markdown → edit → update_page_markdown)
  • "Comment on yesterday's meeting notes with a one-paragraph summary."
  • "Upload this diagram to the design page." — single- and multi-part file uploads
  • "Look at the screenshot on that bug report and tell me what's wrong." — get_image hands the model the picture itself

Full capability list in Features; the complete operation catalog (47 ops) is in the Operations menu.

🧭 Which Notion MCP should you use?

Three options exist. Honest guidance:

Best forAuthHeadless / CINotes
Notion hosted MCP (mcp.notion.com)Interactive chat in claude.ai, ChatGPT, CursorOAuth (human must click; Notion says non-interactive auth is in the works)❌First-party, ~34 markdown tools (11 of them Custom Agent session tools that need Notion AI), some plan-gated
Official open-source server—Token✅Notion calls it deprecated and “no longer actively maintained”; the repo says it “may sunset” it and that issues and PRs are not actively monitored
This serverAgents, automation, CI, self-hosting, token-sensitive workloadsToken (PAT)✅Actively maintained, agent-first design below

If you just want to chat with your Notion in claude.ai's web UI, use Notion's hosted connector — it's one click. Use this server when your agent runs unattended, when context/token cost matters, or when you want batch/idempotent semantics and self-hosting.

CapabilityOfficial Notion MCP (open source)This server
Tool surface24 tools (one per endpoint), 17,163 tokens loaded into context3 tools, 1,005 tokens — 94% less schema at connection
Operations covered~24 endpoints47 operations (plus a trash_page alias) across pages, blocks, databases, data sources, views, templates, comments, users, files
Batch mutationsNot documented✅ Universal { items: [...] } envelope; up to 10 in parallel
Atomic batches + rollbackNot documented✅ atomic: true aborts on first failure, best-effort archives entities created earlier
IdempotencyNot documented✅ idempotency_key — same key + op returns the cached result for 5 minutes
Rate-limit handling429s bubble up✅ Token-bucket limiter (3 req/s default) + exponential backoff, honors Retry-After
Response shapesRaw Notion SDK JSONSlim shapers drop noise by default; verbose: true opts out
Database queriesRaw properties bag per rowFlattened name → primitive map (all 20+ property types)
Wire formatDefault SDK serializationCompact JSON — ~30% smaller payloads
MarkdownPage-level markdown tools✅ Markdown accepted by create_page / append_blocks / update_block / comments + full round-trip (get_page_markdown / update_page_markdown), full GFM
Templates—✅ create_page from a Notion template + list_data_source_templates discovery
File uploadsNot in the documented tool surface✅ Single- and multi-part (5 MB chunks), MIME inferred
Validation errorsPlain error stringSelf-healing: { code, message, path, issues, schema, example, fix } — corrected in one round-trip
Notion API version—Pinned 2026-03-11 (data sources, views, templates)

Real-world impact:

  • Renaming 50 pages — one notion_write call with { items: [...], concurrency: 10 } instead of 50 separate tool calls through the agent's reasoning loop: roughly an order of magnitude faster, and the prompt-token savings are the bigger win.
  • Tool list in context — 3 schema blobs per conversation instead of ~24, no matter which of the 47 operations get called; the operation menu ships inside them as enums, so the model never has to read a resource to learn what exists.
  • Reading a 100-row database — flattened rows are typically 5–10× fewer tokens than the raw properties bag, with no information loss.

🪄 Complete walkthrough (no coding required)

What you'll need

  1. A Notion account.
  2. The Claude Desktop app.
  3. About 5 minutes.

Step 1 — Get your Notion token

A Personal Access Token (PAT) is like a key that lets the AI act as you inside Notion — it sees every page you can see, with no per-page setup.

  1. Open app.notion.com/developers/tokens while logged into Notion — that's the Personal access tokens page of Notion's developer portal (also reachable from the app via Settings → Connections → Develop or manage integrations → Personal access tokens in the sidebar).

  2. Click + New token.

  3. Name it (e.g. Claude), pick the workspace, leave the default Notion API capability checked, click Create token.

  4. Copy the token now — Notion shows it only once. It starts with ntn_. Treat it like a password.

PATs expire 1 year after creation — set a reminder to rotate. No "Personal access tokens" tab? Your admin disabled them; use the Internal Integration alternative.

Step 2 — Tell Claude Desktop about the server

  1. Open Claude Desktop → Claude menu (top-left on Mac, hamburger on Windows) → Settings → Developer → Edit Config.
  2. A file named claude_desktop_config.json opens. Don't panic at the curly braces — it's just text.
  3. Select all (Cmd+A / Ctrl+A), delete, and paste:
{
  "mcpServers": {
    "notion": {
      "command": "npx",
      "args": ["-y", "notion-mcp-server"],
      "env": {
        "NOTION_TOKEN": "ntn_paste_your_token_here"
      }
    }
  }
}

This block tells Claude Desktop how to launch the connector. npx downloads and runs it automatically the first time. The only thing you change is the token.

  1. Replace ntn_paste_your_token_here with your token — keep the quotation marks.
  2. Save (Cmd+S / Ctrl+S).
  3. Quit Claude Desktop completely (Mac: Cmd+Q; Windows: tray icon → Quit) and reopen it.

Step 3 — Check and try

Type / in a new chat — you should see notion_read, notion_write and notion_describe in the list. Then ask:

"Use Notion to make a new page called 'Hello from Claude' and add a checklist of three things I want to try today."

Claude calls the tool and replies with a page link. If something's off, it's almost always a token typo or Claude Desktop not fully quit — see Troubleshooting.

🔧 Configuration

Authentication: PAT (recommended) vs. Internal Integration

Both use the same NOTION_TOKEN env var — only where you get the token differs.

Personal Access Token (recommended)Internal Integration (scoped)
Whereapp.notion.com/developers/tokens → + New tokenapp.notion.com/developers/connections → + New connection
ScopeEverything you can seeOnly pages where you clicked • • • → Connect → <integration>
FrictionNonePer-page Connect step for every page/database
Use whenDefault: personal + team workspaces, prototypingAdmin requires explicit per-resource scoping, or shared production bots

💡 Most object_not_found errors are a wrong auth choice, not a bug: an Internal Integration token that was never Connected to the page. Switch to a PAT.

Can: read every page you have access to; create/update pages and databases where you have edit rights; comment as you; upload files. Can't: access pages you can't see; bypass workspace permissions; act as another user; change admin settings. A PAT's scope = your account — if you lose access to a page, so does the PAT. Issue separate tokens per teammate.

Expiry: PATs expire 1 year after creation (Notion docs); set a reminder for ~11 months.

Revoking: app.notion.com/developers/tokens → Revoke next to the token (immediate). Workspace admins can revoke anyone's from Settings & members → Connections → All personal access tokens.

Admin disabled PATs? Ask them to enable, or create an Internal Integration at app.notion.com/developers/connections (+ New connection) and • • • → Connect it to every page the agent should touch — same NOTION_TOKEN env var.

Official reference: PAT guide · Authorization overview.

Environment variables

Env varRequiredDefaultMeaning
NOTION_TOKEN✅—PAT (ntn_…, recommended) or Internal Integration secret (secret_… / ntn_…)
NOTION_PAGE_ID——Default parent for create_page / create_database when no parent is passed (page → Share → Copy link; the whole URL or the bare 32-char id both work)
NOTION_RATE_LIMIT—3Requests/second for the shared limiter (Notion's documented per-integration limit)
NOTION_READ_ONLY——true/1/yes disables every write operation in one switch
NOTION_ALLOWED_OPERATIONS—allComma-separated allowlist of operations or group presets — see Restricting operations
NOTION_BLOCKED_OPERATIONS——Comma-separated blocklist (same vocabulary); wins over the allowlist
NOTION_CONFIRM_DESTRUCTIVE——true/1 makes every destructive operation ask you to confirm first, through MCP elicitation — see Restricting operations
NOTION_UPLOAD_ROOT——Confine upload_file's path source to one directory. Unset, a path source can read any file the server process can — set this if a model composes the path. Relative paths resolve inside it; symlinks are resolved before the check, so they can't point out — see Files
NOTION_FILE_URLS—fullref replaces Notion's signed file URLs (~1,650 chars, valid for an hour) in slim responses with short notion-file: refs that get_file_url / get_image resolve on demand — see Files
HTTPS_PROXY / HTTP_PROXY——Route all outbound traffic — Notion API calls and the downloads in get_image / upload_file's url source — through an HTTP(S) proxy (standard env vars, lowercase also accepted)
NOTION_DAILY_LOG_PAGE_ID——Only used by the daily-log MCP prompt

HTTP-transport variables (MCP_TRANSPORT, PORT, HOST, MCP_AUTH_TOKEN, …) are covered in Remote / HTTP transport.

Upgrading from v1.x or v2.x? Your env vars all still work unchanged. The only break is the tool surface (v1's five tools, then v2's notion_execute, became notion_read + notion_write; notion_describe is unchanged); modern clients rediscover tools automatically. Details: MIGRATION.md.

Restricting operations

Limit what an agent can do with NOTION_ALLOWED_OPERATIONS (allowlist) and/or NOTION_BLOCKED_OPERATIONS (blocklist) — each a comma-separated list of group presets or exact operation names.

PresetExpands to
readevery non-mutating operation
writeevery mutating operation
destructiveoperations whose purpose is removal (archive_page/trash_page, delete_block, batch_mixed_blocks, delete_comment, delete_view)
pages blocks databases data_sources views comments users filesevery operation in that family (read and write)

Read-only deployment (most common):

{ "env": { "NOTION_TOKEN": "ntn_xxx", "NOTION_ALLOWED_OPERATIONS": "read" } }

Everything except destructive ops:

{ "env": { "NOTION_BLOCKED_OPERATIONS": "destructive" } }

Mix presets and individual ops:

{ "env": { "NOTION_ALLOWED_OPERATIONS": "read,append_blocks,add_page_comment" } }

Rules: case-insensitive; unknown tokens ignored with a warning; blocklist wins; an allowlist that resolves to zero operations disables everything (fail-closed). Disabled operations disappear from the tools' operation enums, from notion_describe and from the notion://operations menu, so a call naming one fails validation before it runs; when no write operation is enabled (NOTION_READ_ONLY, or an allowlist of reads) notion_write is not advertised at all.

On startup the server logs one line to stderr summarizing what resolved — check it first if the config doesn't behave as expected:

Operation access: 22/48 enabled (allow=read; block=(none))

Confirm instead of block. NOTION_CONFIRM_DESTRUCTIVE=true keeps destructive operations enabled but makes notion_write ask you before running one, through MCP elicitation: a yes/no dialog in your client that names the operation and its target — the page, database, data source or block title when one retrieve can fetch it (bounded to 5 s), otherwise the id; for a batch, how many items. Restores (restore_page, delete_database / delete_data_source with in_trash: false) and a batch_mixed_blocks call with no delete entry do not prompt, and a blocked operation is still rejected with operation_not_allowed before anyone is asked. Decline, cancel or answer no and the call returns confirmation_declined; the server instructions tell the model not to retry it and to ask you instead. A client that has not declared the elicitation capability gets confirmation_unavailable rather than a silent run — use a client that supports elicitation, unset the variable, or block destructive operations outright with NOTION_BLOCKED_OPERATIONS=destructive.

DomainReadWrite
pagessearch_pages get_page get_page_markdowncreate_page set_page_title set_page_property set_page_properties update_page_markdown move_page restore_page archive_page† trash_page†
blocksget_block get_block_childrenappend_blocks update_block delete_block† batch_mixed_blocks†
databasesquery_databasecreate_database update_database delete_database†
data_sourceslist_data_sources get_data_source list_data_source_templatesupdate_data_source delete_data_source†
viewslist_views get_view query_viewcreate_view update_view delete_view†
commentslist_comments get_commentadd_page_comment add_discussion_comment update_comment delete_comment†
userslist_users get_user get_bot_user get_self—
fileslist_file_uploads get_file_upload get_file_url get_imageupload_file

† = also in the destructive group.

Limitations (control is per-operation, not per-parameter): update_page_markdown is a write op that can replace a page body, and blocking destructive does not disable it. For a guaranteed no-mutation deployment use NOTION_ALLOWED_OPERATIONS=read or NOTION_READ_ONLY=true. MCP prompts may still mention disabled operations, but execution is rejected.

Files

Uploads. upload_file takes its bytes as base64, a public url, or a local path the server reads directly. A path source can read any file the server process can, so when a model composes the path set NOTION_UPLOAD_ROOT to confine it: relative paths resolve inside the root, and symlinks are resolved before the check so they cannot point out of it.

File URLs. Notion mints a fresh signed S3 URL for every hosted file on every read — about 1,650 characters (~500 tokens), valid for an hour, different each time, and easy for a small model to mangle. NOTION_FILE_URLS=ref replaces them in the slim responses (get_page, search_pages, query_database, query_view, get_block, get_block_children, …) with short, stable refs:

RefNames
notion-file:block/<block-id>The file in an image block
notion-file:page/<page-id>/<property>/<index>One entry of a page's files property (property name URL-encoded)

Two read operations turn a ref back into content. Both re-read the object through the Notion API, so a ref stays valid for as long as the file does:

Shortened here. Read the whole README on GitHub.

Signals

GitHub stars
173
Forks
38
Last commit
Oct 2026
Weekly downloads
4k
Weekly_downloads
4k weekly_downloads

Ahel review

  • S4info
    community integration, published by awkoy, not notion

Automated review, not a security audit. Ruleset v1.

Advanced
Delivery
notion-mcp-server MCP server → your Ahel connector (mcp.ahel.ai) → your AI.
Item type
mcp-server
Key
io-github-awkoy-notion-mcp-server
Source
github.com/awkoy/notion-mcp-server