Notion Remote MCP Server

Secure Notion interaction via OAuth 2.1 and PKCE

README.md

Notion Remote MCP Server (OAuth + PKCE)

Remote MCP server that connects to Notion via OAuth and exposes a practical, enterprise-friendly tool surface. It implements Streamable HTTP transport over POST /mcp, MCP-compatible OAuth endpoints, PKCE, token refresh, and encrypted token storage.

Quick Start (5 minutes)

  1. Create a Notion integration
  • Create a public integration in Notion.
  • Add the OAuth redirect URL: http://localhost:8787/oauth/callback
  • Enable capabilities (least-privilege):
    • Read content
    • Update content
    • Insert content
    • Read user info
  1. Configure env
cp .env.example .env

Generate an encryption key and HMAC secret:

node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"

Set:

  • TOKEN_ENC_KEY to the generated base64 key
  • STATE_SIGNING_KEY to another random secret
  • (Optional) TOKEN_ENC_KEY_FILE / STATE_SIGNING_KEY_FILE for file-based secrets (defaults under ./data/)
  • NOTION_CLIENT_ID / NOTION_CLIENT_SECRET
  • BASE_URL (if not localhost)
  • ALLOWED_REDIRECT_URIS for your MCP client
  • NOTION_VERSION (default: 2025-09-03)
  1. Run
npm install && npm run start

Server: http://localhost:8787

OAuth for MCP Clients

This server is an OAuth 2.1 Authorization Server for MCP clients and uses Notion OAuth behind the scenes.

Authorization URL:

GET /authorize?response_type=code&client_id=mcp-cli&redirect_uri=http://localhost:3000/callback&scope=notion.read%20notion.write&state=xyz&code_challenge=...&code_challenge_method=S256

Token endpoint:

POST /token (application/x-www-form-urlencoded)

Supported scopes:

  • notion.read
  • notion.write
  • notion.admin

Token refresh is supported via grant_type=refresh_token.

Dynamic client registration example:

curl -s http://localhost:8787/register \
  -H "Content-Type: application/json" \
  -d '{"client_name":"my-mcp-client","redirect_uris":["http://localhost:3000/callback"],"scope":"notion.read notion.write"}'

MCP Endpoint

  • POST /mcp (Streamable HTTP)
  • GET /mcp returns 405 (only POST is supported)

Headers:

  • Authorization: Bearer <access_token>
  • MCP-Protocol-Version: 2025-11-25 (optional; supported: 2025-11-25, 2025-06-18, 2025-03-26)
  • Accept: application/json, text/event-stream

OAuth metadata:

  • /.well-known/oauth-protected-resource
  • /.well-known/oauth-authorization-server
  • POST /register (dynamic client registration)

Tool Surface

All tools validate inputs with JSON Schema and return JSON-encoded results.

Tool Scope Purpose
notion.search notion.read Search pages/databases
notion.get_page notion.read Retrieve a page
notion.get_database notion.read Retrieve a database/data source
notion.query_database notion.read Query database/data source rows
notion.create_page notion.write Create a page
notion.update_page notion.write Update page properties
notion.append_block notion.write Append blocks
notion.list_users notion.admin Governance: list users
notion.whoami notion.admin Governance: integration identity

JSON Schemas

`notion.search`

Input:

{
  "type": "object",
  "properties": {
    "query": { "type": "string" },
    "filter": { "type": "object", "properties": { "object": { "type": "string", "enum": ["page", "database"] } }, "additionalProperties": false },
    "sort": { "type": "object", "properties": { "direction": { "type": "string", "enum": ["ascending", "descending"] }, "timestamp": { "type": "string", "enum": ["last_edited_time", "created_time"] } }, "additionalProperties": false },
    "page_size": { "type": "integer", "minimum": 1, "maximum": 100 },
    "start_cursor": { "type": "string" }
  },
  "additionalProperties": false
}

Output:

{
  "type": "object",
  "properties": {
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string" },
          "url": { "type": "string" },
          "title": { "type": "string" },
          "last_edited_time": { "type": "string" }
        },
        "required": ["id", "object", "url"]
      }
    },
    "next_cursor": { "type": ["string", "null"] },
    "has_more": { "type": "boolean" }
  },
  "required": ["results", "has_more"]
}
`notion.get_page`

Input:

{
  "type": "object",
  "properties": {
    "page_id": { "type": "string" },
    "include_properties": { "type": "boolean", "default": false }
  },
  "required": ["page_id"],
  "additionalProperties": false
}

Output:

{
  "type": "object",
  "properties": {
    "id": { "type": "string" },
    "url": { "type": "string" },
    "created_time": { "type": "string" },
    "last_edited_time": { "type": "string" },
    "archived": { "type": "boolean" },
    "title": { "type": "string" },
    "propertie

Tools 9

notion.searchSearch pages and databases in Notion
notion.get_pageRetrieve a specific Notion page
notion.get_databaseRetrieve a database or data source
notion.query_databaseQuery database rows
notion.create_pageCreate a new page in Notion
notion.update_pageUpdate properties of an existing page
notion.append_blockAppend blocks to a page
notion.list_usersList users in the workspace
notion.whoamiGet integration identity information

Environment Variables

TOKEN_ENC_KEYrequiredBase64 encoded encryption key for tokens
STATE_SIGNING_KEYrequiredSecret key for signing OAuth state
NOTION_CLIENT_IDrequiredNotion integration client ID
NOTION_CLIENT_SECRETrequiredNotion integration client secret

Try it

Search for my recent project meeting notes in Notion.
Query the 'Tasks' database to find all items assigned to me with status 'In Progress'.
Create a new page titled 'Weekly Summary' in my 'Work' database.
Append a new checklist item to the page with ID '12345'.
Who is the current integration user for this Notion connection?

Frequently Asked Questions

What are the key features of Notion Remote?

OAuth 2.1 authentication with PKCE support. Encrypted token storage for secure credential management. Streamable HTTP transport over POST /mcp. Comprehensive tool surface for reading and modifying Notion content. Dynamic client registration for MCP clients.

What can I use Notion Remote for?

Automating project management workflows by querying and updating Notion databases via Claude.. Building secure AI-powered assistants that interact with private Notion workspaces.. Managing Notion page content programmatically without exposing raw API keys.. Integrating Notion governance tasks like listing users directly into AI chat interfaces..

How do I install Notion Remote?

Install Notion Remote by running: npm install && npm run start

What MCP clients work with Notion Remote?

Notion Remote works with any MCP-compatible client including Claude Desktop, Claude Code, Cursor, and other editors with MCP support.

Turn this server into reusable context

Keep Notion Remote docs, env vars, and workflow notes in Conare so your agent carries them across sessions.

Open Conare