Notion MCP Server avatar

Notion MCP Server

Pricing

Pay per usage

Go to Apify Store
Notion MCP Server

Notion MCP Server

Notion MCP Server for AI agents (Claude, GPT, Cursor). 20 Notion API operations: search pages, query databases, create content, manage blocks, comments, users. Model Context Protocol server with full CRUD support.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

CQ

CQ

Maintained by Community

Actor stats

0

Bookmarked

16

Total users

5

Monthly active users

3 days ago

Last modified

Share

A cloud-hosted Notion tool server for AI agents (Claude, GPT, Cursor). Perform 20 Notion API operations across pages, databases, blocks, comments, and users. Each run executes one operation and returns structured JSON.

Features

  • 20 Operations - Pages, databases, blocks, comments, and users
  • Demo Mode - Test the actor without a Notion token
  • URL or ID Input - Accepts Notion page/database/block URLs or raw IDs
  • Pagination - Cursor-based paging via startCursor / pageSize
  • Graceful Errors - Failed operations return a structured error object (with the Notion error code) instead of crashing the run

Quick Start

Demo Mode (No Setup)

demo is the default operation and needs no token:

{
"operation": "demo"
}

Search Your Workspace

{
"notionToken": "ntn_your_token_here",
"operation": "search",
"query": "Meeting Notes"
}

Setup

1. Create a Notion Integration

  1. Go to notion.so/profile/integrations
  2. Click New integration
  3. Name it (e.g., "Apify MCP")
  4. Copy the token (starts with ntn_ or secret_)

2. Share Pages with the Integration

For each page/database you want to access:

  1. Open the page in Notion
  2. Click ... menu -> Connections
  3. Select your integration

Without this step, requests to that page/database return object_not_found.

Input Parameters

ParameterTypeDefaultDescription
notionTokenstring (secret)-Notion integration token (ntn_ or secret_). Required for every operation except demo.
operationstring (enum)demoThe operation to perform (see Operations below).
querystring-Search query text (for search).
pageIdstring-Page ID or Notion URL.
databaseIdstring-Database ID or Notion URL.
blockIdstring-Block ID or Notion URL.
userIdstring-User ID (for get_user).
parentPageIdstring-Parent page for new pages/databases.
parentDatabaseIdstring-Parent database for new database entries.
titlestring-Title for new pages/databases.
propertiesstring (JSON)-JSON properties object for create/update.
childrenstring (JSON)-JSON array of block children to append.
filterstring (JSON)-JSON filter for search/query.
sortsstring (JSON)-JSON sort configuration.
richTextstring (JSON)-JSON rich-text array (for create_comment).
propertyIdstring-Property ID (for get_page_property).
discussionIdstring-Discussion ID (for replying with create_comment).
startCursorstring-Pagination cursor for the next page of results.
pageSizeinteger100Results per page (1-100).
archivedboolean-Archived flag for update operations.
iconstring (JSON)-JSON icon configuration.
coverstring (JSON)-JSON cover image configuration.
persistResultsbooleantrueSave the result to the default dataset.

Operations

Search & Discovery

OperationDescriptionRequired
demoReturn example output without a token-
searchFind pages/databases- (query optional)

Pages

OperationDescriptionRequired
get_pageGet page detailspageId
create_pageCreate a pageparentPageId or parentDatabaseId
update_pageUpdate page properties/icon/cover/archivedpageId
archive_pageArchive a pagepageId
get_page_propertyGet a single property valuepageId, propertyId

Databases

OperationDescriptionRequired
get_databaseGet database schemadatabaseId
query_databaseQuery database rowsdatabaseId
create_databaseCreate a databaseparentPageId
update_databaseUpdate a databasedatabaseId

Blocks

OperationDescriptionRequired
get_blockGet a blockblockId
get_block_childrenList a block's childrenblockId
append_block_childrenAppend child blocksblockId, children
update_blockUpdate/archive a blockblockId
delete_blockDelete a blockblockId

Comments & Users

OperationDescriptionRequired
get_commentsList comments on a blockblockId
create_commentAdd a commentpageId or discussionId, plus richText
list_usersList workspace users-
get_userGet user detailsuserId
get_bot_userGet the integration's bot user-

Examples

Search Pages

{
"notionToken": "ntn_xxx",
"operation": "search",
"query": "Project Plan"
}

Get Page by URL

{
"notionToken": "ntn_xxx",
"operation": "get_page",
"pageId": "https://notion.so/My-Page-abc123def456"
}

Query Database with Filter

{
"notionToken": "ntn_xxx",
"operation": "query_database",
"databaseId": "abc123",
"filter": "{\"property\":\"Status\",\"select\":{\"equals\":\"Done\"}}"
}

Create Page with Content

{
"notionToken": "ntn_xxx",
"operation": "create_page",
"parentPageId": "parent-id",
"title": "New Page",
"children": "[{\"object\":\"block\",\"type\":\"paragraph\",\"paragraph\":{\"rich_text\":[{\"type\":\"text\",\"text\":{\"content\":\"Hello world!\"}}]}}]"
}

Output

Every run sets the result on the default key-value store under the OUTPUT key, and (when persistResults is true, the default) also pushes it as one item to the default dataset.

FieldTypeDescription
operationstringOperation performed
successbooleanWhether the operation succeeded
objectTypestringNotion object type returned (page, database, block, search_results, etc.)
objectIdstringPrimary object ID (when applicable)
contentobject/arrayReturned Notion data (for list/child operations)
resultCountintegerNumber of results (for list/search operations)
hasMorebooleanWhether more results are available
nextCursorstringCursor for the next page of results
processedAtstringISO timestamp when the operation completed
errorstringError message (only on failure)
errorCodestringNotion API error code (only on failure)

The demo operation additionally returns message, availableOperations, exampleOutput, and setupInstructions.

Success Response

{
"operation": "search",
"success": true,
"objectType": "search_results",
"content": [],
"resultCount": 10,
"hasMore": false
}

Error Response

Errors do not fail the run - they resolve to an object with success: false:

{
"operation": "get_page",
"success": false,
"error": "[object_not_found] Could not find page",
"errorCode": "object_not_found"
}

Using with AI Agents / MCP

Each run of this actor performs one Notion operation and returns structured JSON, so the 20 operations act as the tools it serves. You can invoke it in three ways:

  • Apify API / client libraries - call the actor directly (see the JavaScript and Python examples below).
  • Apify MCP Server - any Apify actor can be surfaced as an MCP tool to MCP-compatible clients (Claude Desktop, Cursor, etc.) through Apify's MCP server. See the Apify MCP documentation at docs.apify.com for the current configuration; a typical Claude Desktop entry looks like:
{
"mcpServers": {
"apify": {
"command": "npx",
"args": ["-y", "@apify/actors-mcp-server", "--actors", "YOUR_USERNAME/notion-mcp-server"],
"env": { "APIFY_TOKEN": "your-apify-token" }
}
}
}

Replace YOUR_USERNAME/notion-mcp-server with this actor's full ID on the Apify platform.

Apify Client (JavaScript)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('YOUR_USERNAME/notion-mcp-server').call({
notionToken: 'ntn_xxx',
operation: 'search',
query: 'Meeting Notes'
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Apify Client (Python)

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("YOUR_USERNAME/notion-mcp-server").call(run_input={
"notionToken": "ntn_xxx",
"operation": "search",
"query": "Meeting Notes"
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items)

Limitations

  • Notion token required. Every operation except demo requires a Notion internal integration token.
  • Integration must be connected per resource. The integration has to be explicitly connected to each page/database (Notion ... -> Connections), or requests return object_not_found.
  • One operation per run. This is a request/response actor - each run executes a single operation. It is not a persistent or streaming MCP connection.
  • Notion rate limits. Notion enforces an average of ~3 requests/second. Use startCursor / pageSize (max 100 per page) to paginate large result sets.
  • Write capabilities depend on the integration. Create/update/archive/delete operations only work if the integration has the matching content capabilities enabled in Notion.
  • JSON-string inputs must be valid JSON. properties, filter, sorts, children, richText, icon, and cover are passed as JSON strings and must match the Notion API schema, or the run returns a validation error.
  • Scope. Coverage is limited to the 20 listed Notion API operations; file uploads, OAuth flows, and webhooks are not included.
  • Check success, not just run status. Notion API and network errors (including transient outages) are caught and returned as success: false with an error code, and the run still finishes successfully. Inspect the success field to detect failures.
  • Node.js >= 18 (provided by the actor's Docker image).

Pricing

This actor runs on the Apify platform, so you pay for the platform compute/usage it consumes; see the actor's Apify Store page for current pricing. Notion API usage under your own integration is free.

Troubleshooting

IssueSolution
"API token is invalid"Token must start with ntn_ or secret_. Regenerate at notion.so/profile/integrations
"Could not find object"Connect the integration to the page: ... -> Connections -> select your integration
Rate limitingNotion allows ~3 req/sec. Paginate with startCursor / pageSize for large datasets

Resources

License

MIT