| name | notion-mcp |
| description | Use when MCP server for Notion databases. Query pages, manage databases, and automate Notion workflows via standardized protocol. |
| domain | mcp |
| author | oyi77 |
| license | Apache-2.0 |
| subdomain | mcp |
| tags | ["mcp","mcp-server","model-context-protocol","notion","tool-integration"] |
| version | 1.0.0 |
Notion Mcp
When to Use
Trigger phrases:
- "notion mcp"
- "Help me with notion mcp"
Use cases:
- Give AI coding agents read/write access to project databases, sprint backlogs, and documentation
- Automate meeting-note processing — extract action items and create Notion database records
- Build a personal knowledge base where an AI agent reads, classifies, and cross-references Notion pages
- Sync Notion databases with external sources (GitHub issues, Google Calendar, email inboxes)
- Generate weekly reports by querying multiple databases and aggregating results via MCP tool chains
When NOT to use:
- For tasks outside this skill's scope
When NOT to Use
- When a simpler HTTP client would suffice
- For internal tools that do not need cross-platform compatibility
- When the tool is used by a single agent in a single context
- When you only need one-time bulk export — use Notion's native export instead
- When the data is ephemeral and doesn't need structured tool discovery
Overview
Notion Mcp gives AI agents structured read/write access to Notion workspaces through the official Notion API. It wraps database queries, page creation, block appending, search, and property updates into MCP tools that any MCP-compatible client (Claude, Cursor, VS Code) can invoke directly. The server uses @notionhq/client (Node.js) or notion-client (Python) for all Notion API operations, with JSON Schema input validation for type-safe parameter passing.
Architecture
- Server — MCP-compliant server exposing tools and resources
- Transport — stdio or HTTP transport layer
- Tools — Callable functions with JSON Schema definitions
- Resources — Readable data sources with URI-based access
Setup
Prerequisites
- Notion Integration — Create one at notion.so/my-integrations: pick a workspace, copy the "Internal Integration Secret".
- Workspace Access — Open the target database or page in Notion, click Share → Invite → enter the integration name.
Installation
npm install @modelcontextprotocol/sdk @notionhq/client
pip install mcp notion-client
Environment
export NOTION_API_KEY=ntn_your_integration_secret_here
MCP Client Registration
Add to your claude_desktop_config.json or equivalent:
{
"mcpServers": {
"notion": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-notion"],
"env": {
"NOTION_API_KEY": "ntn_your_integration_secret_here"
}
}
}
}
Configuration
NOTION_API_KEY (required) — Internal Integration Secret from notion.so/my-integrations
- Database/Page sharing — Each target object must be explicitly shared with the integration; the API returns 404 for unshared objects
- Rate-limit handling — Default 3 requests/second per integration. The SDK retries automatically, but bulk operations may need a throttling wrapper
- Property schema — Before writing filters or updates, call
retrieve_database to discover column types (title, rich_text, select, status, date, multi_select, etc.)
- Transport — Prefer stdio for local agent use; SSE (Server-Sent Events) for remote server deployment behind a reverse proxy
- Tool naming — Use
snake_case and avoid generic names (search → search_workspace)
Integration
- Compatible with Claude, Cursor, and other MCP clients
- Supports streaming responses for large payloads
- Handles errors with standard MCP error codes
Anti-Rationalization Table
| Rationalization | Reality |
|---|
| "I can just use the Notion API directly" | MCP handles auth, structured tool discovery, and client-agnostic invocation. Your tool works in any MCP host without integration-specific code. |
| "Building a server is overkill for one query" | Even a single tool benefits from JSON Schema input validation, consistent error formatting, and documented arguments. |
| "Database schema changes will break everything" | The MCP input schema catches property mismatches at invocation time. Version your tools with v1/v2 handlers for backward compatibility. |
| "MCP is just a wrapper" | MCP enables cross-platform tool sharing. It is infrastructure, not overhead. |
from mcp.server.fastmcp import FastMCP
from notion_client import Client
server = FastMCP("notion-mcp-server")
notion = Client(auth="ntn_your_integration_secret")
@server.tool()
def query_database(database_id: str, status_filter: str = "") -> str:
"""Query a Notion database, optionally filtering by Status."""
filter_params = {}
if status_filter:
filter_params["filter"] = {
"property": "Status",
"select": {"equals": status_filter},
}
results = notion.databases.query(
database_id=database_id, **filter_params
)
pages = [
{
"id": p["id"],
"title": "".join(
t["plain_text"]
for t in p["properties"].get("Name", {}).get("title", [])
),
"url": p["url"],
}
for p in results["results"]
]
return str(pages)
@server.tool()
def create_todo(database_id: str, title: str, assignee: str = ) -> :
properties = {: {: [{: {: title}}]}}
assignee:
properties[] = {: [{: {: assignee}}]}
page = notion.pages.create(
parent={: database_id}, properties=properties
)
__name__ == :
server.run()
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { Client } from "@notionhq/client";
const notion = new Client({ auth: process.env.NOTION_API_KEY! });
const server = new Server(
{ name: "notion-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } },
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "query_database",
description: "Query a Notion database",
inputSchema: {
type: "object",
properties: {
database_id: { type: "string", description: },
: { : , : },
},
: [],
},
},
{
: ,
: ,
: {
: ,
: {
: { : },
: { : },
: { : },
},
: [, ],
},
},
],
}));
server.(, (request) => {
{ name, : args } = request.;
(name === ) {
{ database_id, status_filter } = args ;
response = notion..({
database_id,
: status_filter
? { : , : { : status_filter } }
: ,
});
{
: [{ : , : .(response.) }],
};
}
(name === ) {
{ database_id, title, assignee } = args ;
: <, > = {
: { : [{ : { : title } }] },
};
(assignee) {
properties. = { : [{ : { : assignee } }] };
}
page = notion..({
: { database_id },
properties,
});
{ : [{ : , : page. }] };
}
();
});
transport = ();
server.(transport);
Common Issues
- 401 Unauthorized — The integration secret is invalid or not set as
NOTION_API_KEY. Verify at notion.so/my-integrations.
- 404 Object Not Found — The database/page ID is wrong, or the integration doesn't have access. Share the target with the integration via the Share menu.
- 429 Rate Limited — Notion enforces 3 requests/second per integration. The SDK handles retry-after automatically; for bulk pipelines add a queuing wrapper.
- Empty Results — The filter property name doesn't match the database schema. Call
retrieve_database first to inspect column names and types.
- Property Type Mismatch — A filter uses the wrong type (e.g.
select vs status). Use retrieve_database to discover the exact type for each property.
- MCP Client Disconnected — The server process crashed or the transport config is invalid. Check the MCP client logs and verify the config JSON is valid.
Process
- Integration setup — Create a Notion integration at notion.so/my-integrations, copy the secret, and share target pages/databases with the integration by name.
- Server configuration — Install the MCP server package and
@notionhq/client, set NOTION_API_KEY, register the server in your MCP client configuration file (e.g. claude_desktop_config.json).
- Tool inventory — Identify which Notion operations your workflow needs: query databases, create pages, append block children (paragraphs, headings, to-do lists), update page properties, and search the workspace.
- Test with real workspace data — Execute each tool against actual Notion databases and pages. Verify property types match schemas, filters return correct subsets, and pagination works for datasets over 100 records.
- Workflow integration — Chain tool calls in the MCP client to build automation pipelines: query → filter → create page with properties → append block content → update status. Add error handling for rate limits and missing properties.
Verification
Monetization
- Custom Notion MCP server for enterprise teams — Build and deploy private MCP servers giving AI agents secure access to company Notion workspaces. Charge per-seat licensing ($50-200/seat/mo) or a flat monthly retainer ($2K-5K/mo).
- Notion automation consulting — Offer setup services: integrating Notion with MCP-powered AI agents, designing database schemas for automation, and building custom workflow pipelines (CRM sync, content publishing, project tracking).
- Template marketplace — Create and sell pre-configured MCP tool bundles for common Notion workflows: meeting-notes-to-tasks, email-to-database, research-to-knowledge-base. Package as one-click server configs ($50-200 per bundle).
- Hosted Notion MCP gateway — Build a SaaS platform that handles auth, multi-workspace management, rate-limit queuing, and provides a dashboard for monitoring tool usage and API consumption. Charge by API call volume or flat monthly fee.
- Content pipeline service — Sell automated publishing workflows where an AI agent drafts, reviews, and publishes documentation or blog posts directly into Notion databases via MCP tools. Recurring retainer model ($1K-3K/mo).