Notion MCP server guide
Overview
The official Notion remote MCP server provides access to your Notion workspace through the Notion API, allowing AI agents to search, read, create, and manage pages, databases, and other content in your Notion workspace.
This is a remote MCP server that uses the Auto-Discovered authorization method, meaning ToolHive discovers Notion's OAuth endpoints automatically. On the CLI and UI, this requires minimal configuration. On Kubernetes, it takes a one-time OAuth client registration and an embedded authorization server setup, described below.
Metadata
Expand to view the MCP server's metadata
Name: io.github.stacklok/notion-remote
Type: remote
Description: Notion's official remote MCP server for workspaces, pages, databases, and comments
Tier: Official
Status: Active
Transport: streamable-http
URL: https://mcp.notion.com/mcp
Repository URL:
Popularity: 0 stars
Last Updated: 2026-04-30T03:06:08Z
Tools:
- notion-search
- notion-fetch
- notion-create-pages
- notion-update-page
- notion-move-pages
- notion-duplicate-page
- notion-create-database
- notion-update-database
- notion-create-comment
- notion-get-comments
- notion-get-teams
- notion-get-users
- notion-get-user
- notion-get-self
Tags:
remote, notion, workspace, pages, databases, comments, oauth, productivity, collaboration
Custom Metadata:
author: Notion
homepage: https://developers.notion.com/docs/get-started-with-mcp
Example Command:
thv run notion-remote
Usage
- UI
- CLI
- Kubernetes
Select the notion-remote MCP server in the ToolHive registry.
The server is preconfigured with the following settings:
- Server URL:
https://mcp.notion.com/mcp - Transport: Streamable HTTP
- Authorization method: Auto-Discovered
In the Callback port field, enter the port that ToolHive should use to listen for the OAuth callback. This can be any available port on your machine.
When you install the server, ToolHive:
- Discovers the OAuth endpoints automatically
- Registers a new OAuth client with Notion
- Opens your browser for authentication
After you authorize access in your browser, the remote MCP server appears in your server list with a "Running" status.
Run the Notion remote MCP server with the default configuration:
thv run notion-remote
When you run the server, ToolHive:
- Discovers the OAuth endpoints automatically
- Registers a new OAuth client with Notion
- Opens your browser for authentication
Customize the OAuth callback port if the default port (8777) is unavailable:
thv run --remote-auth-callback-port 50051 notion-remote
After successful authentication, the server will be available to your configured MCP clients.
To restart the server (which triggers a new OAuth authentication flow):
thv restart notion-remote
The ToolHive operator deploys a proxy in front of Notion's hosted remote MCP
server using an MCPRemoteProxy resource with an
embedded authorization server.
The examples below use https://notion-mcp.example.com as a placeholder for
wherever you'll expose the proxy outside the cluster. Set up an Ingress or
Gateway route pointing at the proxy Service first (see
Connect clients to MCP servers)
and substitute your real hostname everywhere this placeholder appears. Notion
redirects the user's browser to this URL during authentication, so it must be
genuinely reachable over HTTPS, not just resolvable inside the cluster.
Notion's remote MCP server (mcp.notion.com) only supports Dynamic Client
Registration (RFC 7591) for third-party OAuth clients; there's no
dashboard-based app registration for it, unlike Notion's classic API
integrations. Once your hostname is live, register once to mint a persistent
client ID and secret:
curl -s -X POST https://mcp.notion.com/register \
-H "Content-Type: application/json" \
-d '{
"client_name": "my-toolhive-proxy",
"redirect_uris": ["https://notion-mcp.example.com/oauth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_post"
}'
Save the returned client_id and client_secret; they don't expire. The
redirect_uris value must exactly match the callback URL you configure below.
Generate a signing key and an HMAC key for the embedded authorization server, and store all three credentials as Secrets:
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out signing-key.pem
openssl rand -base64 32 > hmac-key.txt
kubectl create secret generic notion-auth-signing-key -n toolhive-system \
--from-file=signing-key=signing-key.pem
kubectl create secret generic notion-auth-hmac-key -n toolhive-system \
--from-literal=hmac-key="$(cat hmac-key.txt)"
kubectl create secret generic notion-client-secret -n toolhive-system \
--from-literal=client-secret=<YOUR_CLIENT_SECRET>
Create the embedded authorization server configuration, the OIDC config that validates its own issued tokens, and the remote proxy:
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPExternalAuthConfig
metadata:
name: notion-embedded-auth
namespace: toolhive-system
spec:
type: embeddedAuthServer
embeddedAuthServer:
issuer: 'https://notion-mcp.example.com'
signingKeySecretRefs:
- name: notion-auth-signing-key
key: signing-key
hmacSecretRefs:
- name: notion-auth-hmac-key
key: hmac-key
upstreamProviders:
- name: notion
type: oauth2
oauth2Config:
authorizationEndpoint: 'https://mcp.notion.com/authorize'
tokenEndpoint: 'https://mcp.notion.com/token'
clientId: '<YOUR_CLIENT_ID>'
clientSecretRef:
name: notion-client-secret
key: client-secret
redirectUri: 'https://notion-mcp.example.com/oauth/callback'
---
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPOIDCConfig
metadata:
name: notion-embedded-oidc
namespace: toolhive-system
spec:
type: inline
inline:
issuer: 'https://notion-mcp.example.com'
---
apiVersion: toolhive.stacklok.dev/v1beta1
kind: MCPRemoteProxy
metadata:
name: notion
namespace: toolhive-system
spec:
remoteUrl: https://mcp.notion.com/mcp
transport: streamable-http
proxyPort: 8080
authServerRef:
kind: MCPExternalAuthConfig
name: notion-embedded-auth
oidcConfigRef:
name: notion-embedded-oidc
audience: 'https://notion-mcp.example.com/mcp'
resourceUrl: 'https://notion-mcp.example.com/mcp'
audit:
enabled: true
issuer path-freeSet issuer on both the MCPExternalAuthConfig and MCPOIDCConfig to your
bare host, with no path. The embedded authorization server's OAuth endpoints
(/oauth/register, /oauth/authorize, /oauth/token, /oauth/callback) are
always served at the host root, regardless of any path in issuer. Adding a
path here (for example, matching your MCP resource path) makes discovery
advertise endpoints that nothing actually serves, and every authentication
attempt fails with a generic "authorization header required" error.
Also set redirectUri on the upstream provider explicitly to
<issuer>/oauth/callback, as shown above, instead of omitting it.
Default callback URL for upstream providers
documents the default as {resourceUrl}/oauth/callback, which works when
resourceUrl is a bare host. It breaks here because resourceUrl includes the
/mcp path: the callback route is only ever served at the host root, so the
computed default would land on a path nothing serves. Setting redirectUri
explicitly avoids relying on that default.
Apply the manifest to your Kubernetes cluster:
kubectl apply -f notion-proxy.yaml
Check the proxy status:
kubectl get mcpremoteproxy notion -n toolhive-system
Connect your MCP client to the proxy's URL. Each client authenticates once through the OAuth flow, redirecting through Notion, then reuses the token issued by the embedded authorization server. For production deployments, configure Redis-backed session storage so tokens survive pod restarts. See Horizontal scaling and Redis session storage.
Sample prompts
Here are some sample prompts you can use to interact with the Notion MCP server:
- "Search my Notion workspace for pages about 'project planning'"
- "Create a new page in my Notion workspace titled 'Meeting Notes' with today's date"
- "Find all database entries in my Task List database where status is 'To Do'"
- "Update the page titled 'Weekly Report' with a summary of this week's accomplishments"
- "List all pages in my 'Engineering' teamspace"
- "Create a new Notion database for tracking customer feedback with columns for name, date, and feedback text"
- "Add a comment to the page titled 'Q4 Planning' with my feedback"
- "Search for pages created by john@example.com in the last 30 days"
Recommended practices
- Scope your access: When authenticating, review the permissions requested and only grant access to the workspaces you need for your use case.
- Test with read operations: Start with search and fetch operations to familiarize yourself with the server's capabilities before making changes to your workspace.
- Use specific searches: Instead of broad workspace searches, narrow down results by searching within specific pages, databases, or teamspaces for better performance.
- Understand the data model: Notion has a specific hierarchy (workspaces, teamspaces, pages, databases, data sources). Understanding this structure helps craft more effective prompts.
- Be cautious with updates: The MCP server can modify and delete content in your Notion workspace. Always review changes before applying them to important pages or databases.
- Handle authentication errors: On the CLI or UI, restart the server to
trigger a new OAuth flow:
thv restart notion-remote. On Kubernetes, a proxy pod restart invalidates all sessions unless you've configured Redis-backed session storage, so every client must re-authenticate; with Redis-backed storage, only re-authenticate a client whose underlying Notion token was revoked or can't be refreshed.
Troubleshooting
OAuth authentication fails
If OAuth authentication fails or times out:
CLI or UI:
- Ensure the callback port is not blocked by a firewall
- Check that your browser allows pop-ups from ToolHive
- Try restarting the server with
thv restart notion-remote
Kubernetes: Your client authenticates against the embedded authorization server, which then completes a separate OAuth exchange with Notion using your registered client credentials. Check the proxy pod logs for errors from either leg of that flow:
kubectl logs -n toolhive-system -l app.kubernetes.io/instance=notion | grep -i oauth
The most common causes are a path segment in issuer or a redirectUri that
doesn't exactly match what you registered with Notion. See the note above.
Server shows "Running" but tools don't work
The server may have lost authentication.
CLI or UI: Restart the server to re-authenticate:
thv restart notion-remote
Kubernetes: Check whether the proxy pod restarted recently
(kubectl get pods -n toolhive-system). Without Redis-backed session storage, a
restart invalidates every session and all clients must re-authenticate. With
Redis-backed storage, this instead means the affected client's underlying Notion
token was revoked or couldn't be refreshed; re-authenticate from that client.
Can't find content in search results
- Notion search uses semantic search, which may return different results than exact keyword matching
- Try using more specific search terms or filtering by page, database, or teamspace
- Check that you have access to the content you're searching for (permissions may limit results)
Rate limits
Notion's API has rate limits. If you encounter rate limit errors:
- Reduce the frequency of requests
- Use more specific queries to reduce the amount of data retrieved
- Wait for the rate limit to reset (typically a few minutes)