ldraney-notion-mcp 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: ldraney-notion-mcp
3
+ Version: 0.1.1
4
+ Summary: MCP server wrapping the Notion Python SDK (v2025-09-03)
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: mcp>=1.0
9
+ Requires-Dist: ldraney-notion-sdk>=0.1.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=7.0; extra == "dev"
12
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
13
+
14
+ # notion-mcp
15
+
16
+ MCP (Model Context Protocol) server that wraps [`ldraney/notion-sdk`](https://github.com/ldraney/notion-sdk) — a Python SDK for the Notion API v2025-09-03.
17
+
18
+ ## Overview
19
+
20
+ This project exposes the full Notion Python SDK as MCP tools, allowing AI assistants (Claude, etc.) to interact with Notion workspaces through a standardized tool interface.
21
+
22
+ ## SDK Coverage
23
+
24
+ Every method in `notion-sdk` maps to an MCP tool, organized by module:
25
+
26
+ ### Pages
27
+ | Tool | SDK Method | Notion Endpoint |
28
+ |---|---|---|
29
+ | `create_page` | `create_page()` | `POST /v1/pages` |
30
+ | `get_page` | `get_page()` | `GET /v1/pages/{id}` |
31
+ | `update_page` | `update_page()` | `PATCH /v1/pages/{id}` |
32
+ | `archive_page` | `archive_page()` | `PATCH /v1/pages/{id}` |
33
+ | `move_page` | `move_page()` | `POST /v1/pages/{id}/move` |
34
+
35
+ ### Databases
36
+ | Tool | SDK Method | Notion Endpoint |
37
+ |---|---|---|
38
+ | `create_database` | `create_database()` | `POST /v1/databases` |
39
+ | `get_database` | `get_database()` | `GET /v1/databases/{id}` |
40
+ | `update_database` | `update_database()` | `PATCH /v1/databases/{id}` |
41
+ | `archive_database` | `archive_database()` | `PATCH /v1/databases/{id}` |
42
+ | `query_database` | `query_database()` | auto-resolves data source, then `POST /v1/data_sources/{id}/query` |
43
+
44
+ ### Data Sources
45
+ | Tool | SDK Method | Notion Endpoint |
46
+ |---|---|---|
47
+ | `get_data_source` | `get_data_source()` | `GET /v1/data_sources/{id}` |
48
+ | `update_data_source` | `update_data_source()` | `PATCH /v1/data_sources/{id}` |
49
+ | `query_data_source` | `query_data_source()` | `POST /v1/data_sources/{id}/query` |
50
+ | `list_data_source_templates` | `list_data_source_templates()` | `GET /v1/data_sources/{id}/templates` |
51
+
52
+ ### Blocks
53
+ | Tool | SDK Method | Notion Endpoint |
54
+ |---|---|---|
55
+ | `get_block` | `get_block()` | `GET /v1/blocks/{id}` |
56
+ | `get_block_children` | `get_block_children()` | `GET /v1/blocks/{id}/children` |
57
+ | `append_block_children` | `append_block_children()` | `PATCH /v1/blocks/{id}/children` |
58
+ | `update_block` | `update_block()` | `PATCH /v1/blocks/{id}` |
59
+ | `delete_block` | `delete_block()` | `DELETE /v1/blocks/{id}` |
60
+
61
+ ### Users
62
+ | Tool | SDK Method | Notion Endpoint |
63
+ |---|---|---|
64
+ | `get_users` | `get_users()` | `GET /v1/users` |
65
+ | `get_self` | `get_self()` | `GET /v1/users/me` |
66
+
67
+ ### Comments
68
+ | Tool | SDK Method | Notion Endpoint |
69
+ |---|---|---|
70
+ | `create_comment` | `create_comment()` | `POST /v1/comments` |
71
+ | `get_comments` | `get_comments()` | `GET /v1/comments` |
72
+
73
+ ### Search
74
+ | Tool | SDK Method | Notion Endpoint |
75
+ |---|---|---|
76
+ | `search` | `search()` | `POST /v1/search` |
77
+
78
+ **24 tools total** covering the complete Notion API v2025-09-03 surface.
79
+
80
+ ## Architecture
81
+
82
+ ```
83
+ notion-mcp/
84
+ ├── src/
85
+ │ └── notion_mcp/
86
+ │ ├── server.py # MCP server entry point
87
+ │ ├── tools/
88
+ │ │ ├── pages.py # Page tools
89
+ │ │ ├── databases.py # Database & data source tools
90
+ │ │ ├── blocks.py # Block tools
91
+ │ │ ├── users.py # User tools
92
+ │ │ ├── comments.py # Comment tools
93
+ │ │ └── search.py # Search tools
94
+ │ └── ...
95
+ ├── tests/
96
+ ├── pyproject.toml
97
+ └── README.md
98
+ ```
99
+
100
+ Each tool module mirrors the SDK's mixin structure, keeping a clean 1:1 mapping.
101
+
102
+ ## Prerequisites
103
+
104
+ - Python >= 3.10
105
+ - A Notion integration API key (`NOTION_API_KEY`)
106
+ - [`notion-sdk`](https://github.com/ldraney/notion-sdk) (installed as a dependency)
107
+
108
+ ## Setup
109
+
110
+ ```bash
111
+ # Clone
112
+ git clone https://github.com/ldraney/notion-mcp.git
113
+ cd notion-mcp
114
+
115
+ # Install
116
+ pip install -e .
117
+
118
+ # Configure
119
+ export NOTION_API_KEY="ntn_..."
120
+ ```
121
+
122
+ ## Usage
123
+
124
+ ### With Claude Code
125
+
126
+ Add to your Claude Code MCP config (`~/.claude/settings.json` or project settings):
127
+
128
+ ```json
129
+ {
130
+ "mcpServers": {
131
+ "notion": {
132
+ "command": "python",
133
+ "args": ["-m", "notion_mcp"],
134
+ "env": {
135
+ "NOTION_API_KEY": "ntn_..."
136
+ }
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ ### Standalone
143
+
144
+ ```bash
145
+ python -m notion_mcp
146
+ ```
147
+
148
+ ## Related
149
+
150
+ - [`ldraney/notion-sdk`](https://github.com/ldraney/notion-sdk) — The underlying Python SDK this server wraps
@@ -0,0 +1,137 @@
1
+ # notion-mcp
2
+
3
+ MCP (Model Context Protocol) server that wraps [`ldraney/notion-sdk`](https://github.com/ldraney/notion-sdk) — a Python SDK for the Notion API v2025-09-03.
4
+
5
+ ## Overview
6
+
7
+ This project exposes the full Notion Python SDK as MCP tools, allowing AI assistants (Claude, etc.) to interact with Notion workspaces through a standardized tool interface.
8
+
9
+ ## SDK Coverage
10
+
11
+ Every method in `notion-sdk` maps to an MCP tool, organized by module:
12
+
13
+ ### Pages
14
+ | Tool | SDK Method | Notion Endpoint |
15
+ |---|---|---|
16
+ | `create_page` | `create_page()` | `POST /v1/pages` |
17
+ | `get_page` | `get_page()` | `GET /v1/pages/{id}` |
18
+ | `update_page` | `update_page()` | `PATCH /v1/pages/{id}` |
19
+ | `archive_page` | `archive_page()` | `PATCH /v1/pages/{id}` |
20
+ | `move_page` | `move_page()` | `POST /v1/pages/{id}/move` |
21
+
22
+ ### Databases
23
+ | Tool | SDK Method | Notion Endpoint |
24
+ |---|---|---|
25
+ | `create_database` | `create_database()` | `POST /v1/databases` |
26
+ | `get_database` | `get_database()` | `GET /v1/databases/{id}` |
27
+ | `update_database` | `update_database()` | `PATCH /v1/databases/{id}` |
28
+ | `archive_database` | `archive_database()` | `PATCH /v1/databases/{id}` |
29
+ | `query_database` | `query_database()` | auto-resolves data source, then `POST /v1/data_sources/{id}/query` |
30
+
31
+ ### Data Sources
32
+ | Tool | SDK Method | Notion Endpoint |
33
+ |---|---|---|
34
+ | `get_data_source` | `get_data_source()` | `GET /v1/data_sources/{id}` |
35
+ | `update_data_source` | `update_data_source()` | `PATCH /v1/data_sources/{id}` |
36
+ | `query_data_source` | `query_data_source()` | `POST /v1/data_sources/{id}/query` |
37
+ | `list_data_source_templates` | `list_data_source_templates()` | `GET /v1/data_sources/{id}/templates` |
38
+
39
+ ### Blocks
40
+ | Tool | SDK Method | Notion Endpoint |
41
+ |---|---|---|
42
+ | `get_block` | `get_block()` | `GET /v1/blocks/{id}` |
43
+ | `get_block_children` | `get_block_children()` | `GET /v1/blocks/{id}/children` |
44
+ | `append_block_children` | `append_block_children()` | `PATCH /v1/blocks/{id}/children` |
45
+ | `update_block` | `update_block()` | `PATCH /v1/blocks/{id}` |
46
+ | `delete_block` | `delete_block()` | `DELETE /v1/blocks/{id}` |
47
+
48
+ ### Users
49
+ | Tool | SDK Method | Notion Endpoint |
50
+ |---|---|---|
51
+ | `get_users` | `get_users()` | `GET /v1/users` |
52
+ | `get_self` | `get_self()` | `GET /v1/users/me` |
53
+
54
+ ### Comments
55
+ | Tool | SDK Method | Notion Endpoint |
56
+ |---|---|---|
57
+ | `create_comment` | `create_comment()` | `POST /v1/comments` |
58
+ | `get_comments` | `get_comments()` | `GET /v1/comments` |
59
+
60
+ ### Search
61
+ | Tool | SDK Method | Notion Endpoint |
62
+ |---|---|---|
63
+ | `search` | `search()` | `POST /v1/search` |
64
+
65
+ **24 tools total** covering the complete Notion API v2025-09-03 surface.
66
+
67
+ ## Architecture
68
+
69
+ ```
70
+ notion-mcp/
71
+ ├── src/
72
+ │ └── notion_mcp/
73
+ │ ├── server.py # MCP server entry point
74
+ │ ├── tools/
75
+ │ │ ├── pages.py # Page tools
76
+ │ │ ├── databases.py # Database & data source tools
77
+ │ │ ├── blocks.py # Block tools
78
+ │ │ ├── users.py # User tools
79
+ │ │ ├── comments.py # Comment tools
80
+ │ │ └── search.py # Search tools
81
+ │ └── ...
82
+ ├── tests/
83
+ ├── pyproject.toml
84
+ └── README.md
85
+ ```
86
+
87
+ Each tool module mirrors the SDK's mixin structure, keeping a clean 1:1 mapping.
88
+
89
+ ## Prerequisites
90
+
91
+ - Python >= 3.10
92
+ - A Notion integration API key (`NOTION_API_KEY`)
93
+ - [`notion-sdk`](https://github.com/ldraney/notion-sdk) (installed as a dependency)
94
+
95
+ ## Setup
96
+
97
+ ```bash
98
+ # Clone
99
+ git clone https://github.com/ldraney/notion-mcp.git
100
+ cd notion-mcp
101
+
102
+ # Install
103
+ pip install -e .
104
+
105
+ # Configure
106
+ export NOTION_API_KEY="ntn_..."
107
+ ```
108
+
109
+ ## Usage
110
+
111
+ ### With Claude Code
112
+
113
+ Add to your Claude Code MCP config (`~/.claude/settings.json` or project settings):
114
+
115
+ ```json
116
+ {
117
+ "mcpServers": {
118
+ "notion": {
119
+ "command": "python",
120
+ "args": ["-m", "notion_mcp"],
121
+ "env": {
122
+ "NOTION_API_KEY": "ntn_..."
123
+ }
124
+ }
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Standalone
130
+
131
+ ```bash
132
+ python -m notion_mcp
133
+ ```
134
+
135
+ ## Related
136
+
137
+ - [`ldraney/notion-sdk`](https://github.com/ldraney/notion-sdk) — The underlying Python SDK this server wraps
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ldraney-notion-mcp"
7
+ version = "0.1.1"
8
+ description = "MCP server wrapping the Notion Python SDK (v2025-09-03)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "MIT"}
12
+ dependencies = [
13
+ "mcp>=1.0",
14
+ "ldraney-notion-sdk>=0.1.0",
15
+ ]
16
+
17
+ [project.optional-dependencies]
18
+ dev = [
19
+ "pytest>=7.0",
20
+ "pytest-asyncio>=0.21",
21
+ ]
22
+
23
+ [tool.setuptools.packages.find]
24
+ where = ["src"]
25
+
26
+ [tool.pytest.ini_options]
27
+ testpaths = ["tests"]
28
+ asyncio_mode = "auto"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: ldraney-notion-mcp
3
+ Version: 0.1.1
4
+ Summary: MCP server wrapping the Notion Python SDK (v2025-09-03)
5
+ License: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: mcp>=1.0
9
+ Requires-Dist: ldraney-notion-sdk>=0.1.0
10
+ Provides-Extra: dev
11
+ Requires-Dist: pytest>=7.0; extra == "dev"
12
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
13
+
14
+ # notion-mcp
15
+
16
+ MCP (Model Context Protocol) server that wraps [`ldraney/notion-sdk`](https://github.com/ldraney/notion-sdk) — a Python SDK for the Notion API v2025-09-03.
17
+
18
+ ## Overview
19
+
20
+ This project exposes the full Notion Python SDK as MCP tools, allowing AI assistants (Claude, etc.) to interact with Notion workspaces through a standardized tool interface.
21
+
22
+ ## SDK Coverage
23
+
24
+ Every method in `notion-sdk` maps to an MCP tool, organized by module:
25
+
26
+ ### Pages
27
+ | Tool | SDK Method | Notion Endpoint |
28
+ |---|---|---|
29
+ | `create_page` | `create_page()` | `POST /v1/pages` |
30
+ | `get_page` | `get_page()` | `GET /v1/pages/{id}` |
31
+ | `update_page` | `update_page()` | `PATCH /v1/pages/{id}` |
32
+ | `archive_page` | `archive_page()` | `PATCH /v1/pages/{id}` |
33
+ | `move_page` | `move_page()` | `POST /v1/pages/{id}/move` |
34
+
35
+ ### Databases
36
+ | Tool | SDK Method | Notion Endpoint |
37
+ |---|---|---|
38
+ | `create_database` | `create_database()` | `POST /v1/databases` |
39
+ | `get_database` | `get_database()` | `GET /v1/databases/{id}` |
40
+ | `update_database` | `update_database()` | `PATCH /v1/databases/{id}` |
41
+ | `archive_database` | `archive_database()` | `PATCH /v1/databases/{id}` |
42
+ | `query_database` | `query_database()` | auto-resolves data source, then `POST /v1/data_sources/{id}/query` |
43
+
44
+ ### Data Sources
45
+ | Tool | SDK Method | Notion Endpoint |
46
+ |---|---|---|
47
+ | `get_data_source` | `get_data_source()` | `GET /v1/data_sources/{id}` |
48
+ | `update_data_source` | `update_data_source()` | `PATCH /v1/data_sources/{id}` |
49
+ | `query_data_source` | `query_data_source()` | `POST /v1/data_sources/{id}/query` |
50
+ | `list_data_source_templates` | `list_data_source_templates()` | `GET /v1/data_sources/{id}/templates` |
51
+
52
+ ### Blocks
53
+ | Tool | SDK Method | Notion Endpoint |
54
+ |---|---|---|
55
+ | `get_block` | `get_block()` | `GET /v1/blocks/{id}` |
56
+ | `get_block_children` | `get_block_children()` | `GET /v1/blocks/{id}/children` |
57
+ | `append_block_children` | `append_block_children()` | `PATCH /v1/blocks/{id}/children` |
58
+ | `update_block` | `update_block()` | `PATCH /v1/blocks/{id}` |
59
+ | `delete_block` | `delete_block()` | `DELETE /v1/blocks/{id}` |
60
+
61
+ ### Users
62
+ | Tool | SDK Method | Notion Endpoint |
63
+ |---|---|---|
64
+ | `get_users` | `get_users()` | `GET /v1/users` |
65
+ | `get_self` | `get_self()` | `GET /v1/users/me` |
66
+
67
+ ### Comments
68
+ | Tool | SDK Method | Notion Endpoint |
69
+ |---|---|---|
70
+ | `create_comment` | `create_comment()` | `POST /v1/comments` |
71
+ | `get_comments` | `get_comments()` | `GET /v1/comments` |
72
+
73
+ ### Search
74
+ | Tool | SDK Method | Notion Endpoint |
75
+ |---|---|---|
76
+ | `search` | `search()` | `POST /v1/search` |
77
+
78
+ **24 tools total** covering the complete Notion API v2025-09-03 surface.
79
+
80
+ ## Architecture
81
+
82
+ ```
83
+ notion-mcp/
84
+ ├── src/
85
+ │ └── notion_mcp/
86
+ │ ├── server.py # MCP server entry point
87
+ │ ├── tools/
88
+ │ │ ├── pages.py # Page tools
89
+ │ │ ├── databases.py # Database & data source tools
90
+ │ │ ├── blocks.py # Block tools
91
+ │ │ ├── users.py # User tools
92
+ │ │ ├── comments.py # Comment tools
93
+ │ │ └── search.py # Search tools
94
+ │ └── ...
95
+ ├── tests/
96
+ ├── pyproject.toml
97
+ └── README.md
98
+ ```
99
+
100
+ Each tool module mirrors the SDK's mixin structure, keeping a clean 1:1 mapping.
101
+
102
+ ## Prerequisites
103
+
104
+ - Python >= 3.10
105
+ - A Notion integration API key (`NOTION_API_KEY`)
106
+ - [`notion-sdk`](https://github.com/ldraney/notion-sdk) (installed as a dependency)
107
+
108
+ ## Setup
109
+
110
+ ```bash
111
+ # Clone
112
+ git clone https://github.com/ldraney/notion-mcp.git
113
+ cd notion-mcp
114
+
115
+ # Install
116
+ pip install -e .
117
+
118
+ # Configure
119
+ export NOTION_API_KEY="ntn_..."
120
+ ```
121
+
122
+ ## Usage
123
+
124
+ ### With Claude Code
125
+
126
+ Add to your Claude Code MCP config (`~/.claude/settings.json` or project settings):
127
+
128
+ ```json
129
+ {
130
+ "mcpServers": {
131
+ "notion": {
132
+ "command": "python",
133
+ "args": ["-m", "notion_mcp"],
134
+ "env": {
135
+ "NOTION_API_KEY": "ntn_..."
136
+ }
137
+ }
138
+ }
139
+ }
140
+ ```
141
+
142
+ ### Standalone
143
+
144
+ ```bash
145
+ python -m notion_mcp
146
+ ```
147
+
148
+ ## Related
149
+
150
+ - [`ldraney/notion-sdk`](https://github.com/ldraney/notion-sdk) — The underlying Python SDK this server wraps
@@ -0,0 +1,18 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/ldraney_notion_mcp.egg-info/PKG-INFO
4
+ src/ldraney_notion_mcp.egg-info/SOURCES.txt
5
+ src/ldraney_notion_mcp.egg-info/dependency_links.txt
6
+ src/ldraney_notion_mcp.egg-info/requires.txt
7
+ src/ldraney_notion_mcp.egg-info/top_level.txt
8
+ src/notion_mcp/__init__.py
9
+ src/notion_mcp/__main__.py
10
+ src/notion_mcp/server.py
11
+ src/notion_mcp/tools/__init__.py
12
+ src/notion_mcp/tools/blocks.py
13
+ src/notion_mcp/tools/comments.py
14
+ src/notion_mcp/tools/databases.py
15
+ src/notion_mcp/tools/pages.py
16
+ src/notion_mcp/tools/search.py
17
+ src/notion_mcp/tools/users.py
18
+ tests/test_tools.py
@@ -0,0 +1,6 @@
1
+ mcp>=1.0
2
+ ldraney-notion-sdk>=0.1.0
3
+
4
+ [dev]
5
+ pytest>=7.0
6
+ pytest-asyncio>=0.21
@@ -0,0 +1,5 @@
1
+ """notion-mcp: MCP server wrapping the Notion Python SDK."""
2
+
3
+ from .server import mcp
4
+
5
+ __all__ = ["mcp"]
@@ -0,0 +1,5 @@
1
+ """Allow running as `python -m notion_mcp`."""
2
+
3
+ from .server import mcp
4
+
5
+ mcp.run()
@@ -0,0 +1,74 @@
1
+ """MCP server entry point — FastMCP app and NotionClient lifecycle."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import Any
7
+
8
+ import httpx
9
+ from mcp.server.fastmcp import FastMCP
10
+ from notion_sdk import NotionClient
11
+
12
+ mcp = FastMCP("notion")
13
+
14
+ # ---------------------------------------------------------------------------
15
+ # Shared client instance
16
+ # ---------------------------------------------------------------------------
17
+
18
+ _client: NotionClient | None = None
19
+
20
+
21
+ def get_client() -> NotionClient:
22
+ """Return the shared NotionClient, creating it on first call.
23
+
24
+ The client reads NOTION_API_KEY from the environment (via the SDK).
25
+ """
26
+ global _client
27
+ if _client is None:
28
+ _client = NotionClient()
29
+ return _client
30
+
31
+
32
+ # ---------------------------------------------------------------------------
33
+ # Helpers
34
+ # ---------------------------------------------------------------------------
35
+
36
+
37
+ def _parse_json(value: str | dict | list | None, name: str) -> Any:
38
+ """Parse a JSON string into a Python object, or pass through if already parsed."""
39
+ if value is None:
40
+ return None
41
+ if isinstance(value, (dict, list)):
42
+ return value
43
+ try:
44
+ return json.loads(value)
45
+ except json.JSONDecodeError as exc:
46
+ raise ValueError(f"Invalid JSON for parameter '{name}': {exc}") from exc
47
+
48
+
49
+ def _error_response(exc: Exception) -> str:
50
+ """Format an exception into a user-friendly error string."""
51
+ if isinstance(exc, httpx.HTTPStatusError):
52
+ try:
53
+ body = exc.response.json()
54
+ except Exception:
55
+ body = exc.response.text
56
+ return json.dumps(
57
+ {
58
+ "error": True,
59
+ "status_code": exc.response.status_code,
60
+ "message": str(exc),
61
+ "details": body,
62
+ },
63
+ indent=2,
64
+ )
65
+ return json.dumps({"error": True, "message": str(exc)}, indent=2)
66
+
67
+
68
+ # ---------------------------------------------------------------------------
69
+ # Register tool modules — each module calls @mcp.tool() at import time
70
+ # ---------------------------------------------------------------------------
71
+
72
+ from .tools import register_all_tools # noqa: E402
73
+
74
+ register_all_tools()
@@ -0,0 +1,13 @@
1
+ """Tool registration — imports every tool module so @mcp.tool() decorators fire."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def register_all_tools() -> None:
7
+ """Import all tool modules, which register tools via the module-level @mcp.tool() decorators."""
8
+ from . import pages # noqa: F401
9
+ from . import databases # noqa: F401
10
+ from . import blocks # noqa: F401
11
+ from . import users # noqa: F401
12
+ from . import comments # noqa: F401
13
+ from . import search # noqa: F401