Notion

by awkoy

92 stars
2.9k downloads
Not rated
GitHub

About

Enables AI systems to create, update, and manage Notion pages and blocks through a Node.js bridge to the Notion API, supporting efficient batch operations for documentation and knowledge base maintenance.

Details

Author
awkoy
Repository
awkoy/notion-mcp-server
GitHub stars
92
Downloads
2,903
License
MIT License
Categories
Productivity, Other, Project Management, Developer Tools, Design, Workplace, File Management, AI, Search, Frontend, Knowledge Base, Infrastructure, API

- Two-tool surfacenotion_execute (do it) + notion_describe (learn the shape). The whole API is one schema deep.
- Universal batch envelope — every mutating op accepts { items: [...], atomic?, idempotency_key?, concurrency? } with per-item validation and results.
- Atomic batches with best-effort rollbackatomic: true aborts on first failure and archives anything created earlier in the batch.
- Idempotency keys — same (operation, idempotency_key) returns the cached result for 5 minutes. Safe to retry on flaky networks.
- Rate-limit + retry baked in — token-bucket limiter (3 req/s default, NOTION_RATE_LIMIT to change) with exponential backoff on 429/5xx/timeouts, honoring Retry-After.
- Self-healing validation errors — failures return { schema, example, fix } so the model corrects bad payloads in one round-trip.
- Markdown everywherecreate_page / append_blocks / update_block / comment bodies accept a markdown string (full GFM: headings 1–4, lists, nested to-dos, blockquotes, fenced code with language detection, images, dividers, inline formatting), plus full round-trip via get_page_markdown / update_page_markdown.
- Notion templatescreate_page can apply a data source's template (template: { type: "template_id" | "default" }), with list_data_source_templates to discover template IDs.
- Database views — list/get/query/create/update/delete views; query_view runs a view's stored filters/sorts and returns hydrated rows.
- Typed where filter shorthandquery_database takes {Status: {equals: "Done"}, AND: [...]} and compiles it to Notion filter JSON (raw filter still accepted for edge cases).
- Slim responses + flattened rows — noisy fields dropped by default, query_database rows flattened to name → primitive maps, compact JSON wire format (~30% smaller). verbose: true opts out per call.
- File uploads — single-part and multi-part (5 MB chunks) transparently; MIME inferred from filename.
- Opt-in auto-paginationpaginate: true on search_pages / list_comments / query_database walks next_cursor for you (default cap ≈ 1000 items).
- HTTP(S) proxy support — standard HTTPS_PROXY / HTTP_PROXY env vars for corporate networks.
- Access controlNOTION_READ_ONLY one-switch read-only mode plus per-operation allow/block lists.

Setting up with Highlight

This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:

  1. Download and install Highlight from highlightai.com/download
  2. Navigate to the plugins tab and select "Add Custom Plugin"
  3. Configure the plugin with the settings below
    Plugin Name Notion
    Command (node, npx, python, etc.) npx
    Arguments
    • Argument 1 -y
    • Argument 2 notion-mcp-server
    Environment
    • NOTION_TOKEN ntn_paste_your_token_here

    Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.

  4. Enable "Start Automatically" if you want the plugin to start when Highlight launches

From the repository

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.)

Notion developer portal — the Personal access tokens page with the + New token button in the top right

Step 2 — add the server to your client.

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

| | Personal Access Token (recommended) | Internal Integration (scoped) |
| --- | --- | --- |
| Where | app.notion.com/developers/tokens+ New token | app.notion.com/developers/connections+ New connection |
| Scope | Everything you can see | Only pages where you clicked • • • → Connect → \<integration\> |
| Friction | None | Per-page Connect step for every page/database |
| Use when | Default: personal + team workspaces, prototyping | Admin 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.

<details>
<summary><b>PAT details: capabilities, expiry, revocation, admin-disabled fallback</b></summary>

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/tokensRevoke 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.

</details>

| Env var | Required | Default | Meaning |
| --- | --- | --- | --- |
| 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; ID = last 32 chars) |
| NOTION_RATE_LIMIT | — | 3 | Requests/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 | — | all | Comma-separated allowlist of operations or group presets — see Restricting operations |
| NOTION_BLOCKED_OPERATIONS | — | — | Comma-separated blocklist (same vocabulary); wins over the allowlist |
| 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 |
| HTTPS_PROXY / HTTP_PROXY | — | — | Route Notion API traffic 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? Your env vars all still work unchanged. The only break is the tool surface (v1's five tools became notion_execute + notion_describe); modern clients rediscover tools automatically. Details: MIGRATION.md.


It serves MCP Streamable HTTP at POST/GET/DELETE /mcp (stateful sessions via the mcp-session-id header) plus an unauthenticated GET /health. It's single-tenant — every request acts as the one NOTION_TOKEN the process started with.

| env | default | meaning |
| --- | --- | --- |
| MCP_TRANSPORT | stdio | set to http to enable HTTP |
| PORT | 3000 | listen port (0 = OS-assigned) |
| HOST | 127.0.0.1 | bind address; set 0.0.0.0 to expose externally (only with MCP_AUTH_TOKEN) |
| MCP_AUTH_TOKEN | — | when set, every /mcp request must send Authorization: Bearer <token> |
| MCP_ALLOWED_HOSTS | localhost + bound host | comma-list for DNS-rebinding Host allowlist |
| MCP_ALLOWED_ORIGINS | localhost origins | comma-list for browser Origin allowlist |

> ⚠️ Whoever reaches /mcp acts as your NOTION_TOKEN. On loopback (the default) that's just local processes. Before binding a non-loopback HOST, set MCP_AUTH_TOKEN (the server warns if you don't) and/or front it with an authenticating reverse proxy.

Connect from clients that support headers (Claude Code, Cursor, VS Code):

bash
claude mcp add --transport http notion https://your-host/mcp \
--header "Authorization: Bearer <MCP_AUTH_TOKEN>"

Try it locally:

bash
curl http://127.0.0.1:3000/health

notion_execute

Run any operation with a payload. Supports both single and batch operations, where the payload can be a single object or an array of items for batch processing.

notion_describe

Returns the JSON Schema and a working example for one operation, useful for understanding the structure of the operation before making complex calls.

Claude Desktop / Cursor

Paste into your MCP client config file to install this server.

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

Linux

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

Macos

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

Windows

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

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

npm version
NPM Downloads
License
Model Context Protocol
notion-mcp-server on Smithery
Stars

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".
- 97% smaller tool footprint at connection. Two MCP tools (422 tokens) 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 85–95% 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.

<a href="https://glama.ai/mcp/servers/zrh07hteaa">
Notion MCP Server on Glama
</a>

⚡ 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.)

Notion developer portal — the Personal access tokens page with the + New token button in the top right

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

Install MCP Server

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)

Install in VS Code%22%2C%22password%22%3Atrue%7D%5D&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22notion-mcp-server%22%5D%2C%22env%22%3A%7B%22NOTION_TOKEN%22%3A%22%24%7Binput%3Anotion_token%7D%22%7D%7D)

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

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.

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_execute 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

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

🧭 Which Notion MCP should you use?

Three options exist. Honest guidance:

| | Best for | Auth | Headless / CI | Notes |
| --- | --- | --- | --- | --- |
| Notion hosted MCP (mcp.notion.com) | Interactive chat in claude.ai, ChatGPT, Cursor | OAuth (human must click) | ❌ | First-party, 18 markdown tools, some plan-gated |
| Official open-source server | — | Token | ✅ | Notion has soft-deprecated it (“may sunset this repository… issues and PRs not actively monitored”) |
| This server | Agents, automation, CI, self-hosting, token-sensitive workloads | Token (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.

<details>
<summary><b>Detailed comparison vs. the official open-source server</b></summary>

| Capability | Official Notion MCP (open source) | This server |
| --- | --- | --- |
| Tool surface | 24 tools (one per endpoint), 17,163 tokens loaded into context | 2 tools, 422 tokens — 97% less schema at connection |
| Operations covered | ~24 endpoints | 43 operations (plus a trash_page alias) across pages, blocks, databases, data sources, views, templates, comments, users, files |
| Batch mutations | Not documented | ✅ Universal { items: [...] } envelope; up to 10 in parallel |
| Atomic batches + rollback | Not documented | ✅ atomic: true aborts on first failure, best-effort archives entities created earlier |
| Idempotency | Not documented | ✅ idempotency_key — same key + op returns the cached result for 5 minutes |
| Rate-limit handling | 429s bubble up | ✅ Token-bucket limiter (3 req/s default) + exponential backoff, honors Retry-After |
| Response shapes | Raw Notion SDK JSON | Slim shapers drop noise by default; verbose: true opts out |
| Database queries | Raw properties bag per row | Flattened name → primitive map (all 20+ property types) |
| Wire format | Default SDK serialization | Compact JSON — ~30% smaller payloads |
| Markdown | Page-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 uploads | Not in the documented tool surface | ✅ Single- and multi-part (5 MB chunks), MIME inferred |
| Validation errors | Plain error string | Self-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_execute 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 — 2 schema blobs per conversation instead of ~24, no matter which of the 43 operations get called.
- Reading a 100-row database — flattened rows are typically 5–10× fewer tokens than the raw properties bag, with no information loss.

</details>

🪄 Complete walkthrough (no coding required)

<details>
<summary><b>Set up Claude Desktop + Notion in 5 minutes — assumes you've never seen a config file</b></summary>

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 integrationsPersonal 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.

The New personal access token dialog: enter a token name, pick the workspace it has access to, keep the Notion API capability checked, then press 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) → SettingsDeveloperEdit 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.

4. Replace ntn_paste_your_token_here with your token — keep the quotation marks.
5. Save (Cmd+S / Ctrl+S).
6. 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_execute 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.

</details>

🔧 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) |
| --- | --- | --- |
| Where | app.notion.com/developers/tokens+ New token | app.notion.com/developers/connections+ New connection |
| Scope | Everything you can see | Only pages where you clicked • • • → Connect → \<integration\> |
| Friction | None | Per-page Connect step for every page/database |
| Use when | Default: personal + team workspaces, prototyping | Admin 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.

<details>
<summary><b>PAT details: capabilities, expiry, revocation, admin-disabled fallback</b></summary>

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/tokensRevoke 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.

</details>

Environment variables

| Env var | Required | Default | Meaning |
| --- | --- | --- | --- |
| 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; ID = last 32 chars) |
| NOTION_RATE_LIMIT | — | 3 | Requests/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 | — | all | Comma-separated allowlist of operations or group presets — see Restricting operations |
| NOTION_BLOCKED_OPERATIONS | — | — | Comma-separated blocklist (same vocabulary); wins over the allowlist |
| 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 |
| HTTPS_PROXY / HTTP_PROXY | — | — | Route Notion API traffic 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? Your env vars all still work unchanged. The only break is the tool surface (v1's five tools became notion_execute + notion_describe); 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.

| Preset | Expands to |
| --- | --- |
| read | every non-mutating operation |
| write | every mutating operation |
| destructive | operations 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 files | every 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 notion_describe and the notion://operations menu, and notion_execute rejects them with operation_not_allowed.

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: 20/44 enabled (allow=read; block=(none))

<details>
<summary><b>Per-operation reference & limitations</b></summary>

| Domain | Read | Write |
| --- | --- | --- |
| pages | search_pages get_page get_page_markdown | create_page set_page_title set_page_property set_page_properties update_page_markdown move_page restore_page archive_pagetrash_page† |
| blocks | get_block get_block_children | append_blocks update_block delete_blockbatch_mixed_blocks† |
| databases | query_database | create_database update_database |
| data_sources | list_data_sources get_data_source list_data_source_templates | update_data_source |
| views | list_views get_view query_view | create_view update_view delete_view† |
| comments | list_comments get_comment | add_page_comment add_discussion_comment update_comment delete_comment† |
| users | list_users get_user get_bot_user get_self | — |
| files | list_file_uploads get_file_upload | upload_file |

† = also in the destructive group.

Limitations (control is per-operation, not per-parameter): a few write ops can remove content via a parameter — update_database / update_data_source accept in_trash, and update_page_markdown can replace a page body. Blocking destructive does not disable those. 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.

</details>

🌐 Remote / HTTP transport

By default the server speaks stdio (the local path above). To run it as a remote/hosted endpoint — web clients, networked agents, shared deployments — set MCP_TRANSPORT=http:

```bash
MCP_TRANSPORT=http PORT=3000 NOTION_TOKEN=ntn_xxx npx -y notion-mcp-server

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.