notion-block-reader-mcp
v1.0.0
Published
A tiny, dependency-free, read-only Notion MCP server: extract every link URL in a page (including link_preview/embed/bookmark cards the official connectors hide), read raw blocks, and read page properties. No write tools.
Maintainers
Readme
notion-block-reader-mcp
A tiny, dependency-free, read-only Model Context Protocol server for Notion.
It surfaces what the official Notion connectors hide — the real target URLs of
link_preview / embed / bookmark cards (the rich preview blocks you get when
you paste a Discord/GitHub/Jira/etc. link), plus raw block reading and page
properties. It only issues GET requests, so it can never create, edit, or
delete anything in your workspace.
Why this exists
Notion's own MCP/markdown renderers return link-preview cards as opaque
"external object" blocks without the URL (their spec marks them "not supported
in the API yet"). But the Notion REST API does include the URL
({ "type": "link_preview", "link_preview": { "url": "…" } }). This server bridges
that gap with a few focused, read-only tools.
Tools
| Tool | What it does |
|------|--------------|
| notion_extract_links | Every link URL under a page/block — including link_preview/embed/bookmark cards and inline links. Recurses nested blocks. |
| notion_get_block_children | Direct child blocks of a page/block (compact: id, type, text, url). recursive: true to include nested. |
| notion_get_block | One raw block by ID (full JSON, incl. link_preview.url). |
| notion_get_page | A page's properties. |
Requirements
- Node 18+ or bun (uses the runtime's global
fetch; no install/build step). - A Notion internal integration token:
- Create one at https://www.notion.so/my-integrations → Internal → capability Read content.
- Copy the Internal Integration Secret (starts with
ntn_…). - Connect it to your data: open the page/database →
⋯→ Connections → add your integration (the token can only read pages it's been connected to).
Quick start (npx)
Add to your MCP client config (Claude Code / Cursor .mcp.json, Claude Desktop claude_desktop_config.json):
{
"mcpServers": {
"notion-block-reader": {
"command": "npx",
"args": ["-y", "notion-block-reader-mcp@latest"],
"env": { "NOTION_TOKEN": "your_notion_integration_token" }
}
}
}Restart the client, approve the server, and you're set.
Run directly
NOTION_TOKEN=your_token npx notion-block-reader-mcp
# or from a clone:
NOTION_TOKEN=your_token node index.mjs # or: bun index.mjsToken can also be passed as --config <token> instead of the env var.
Quick manual test
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{}}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| NOTION_TOKEN=your_token node index.mjsHow it works
MCP's stdio transport is newline-delimited JSON-RPC 2.0: the client launches
this process and exchanges one JSON message per line over stdin/stdout. The server
handles initialize, tools/list, and tools/call, mapping each tool to a Notion
REST GET. All logging goes to stderr so stdout stays a clean protocol stream.
Security
- Read-only: only
GETrequests. No create/update/delete, no comment writes. - The integration can only read pages/databases you've explicitly connected it to.
- Keep your token in the client config's
env, not in code. This repo contains no token.
License
MIT © Vorakorn Kosidphokin
