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.
- ldraney_notion_mcp-0.1.1/PKG-INFO +150 -0
- ldraney_notion_mcp-0.1.1/README.md +137 -0
- ldraney_notion_mcp-0.1.1/pyproject.toml +28 -0
- ldraney_notion_mcp-0.1.1/setup.cfg +4 -0
- ldraney_notion_mcp-0.1.1/src/ldraney_notion_mcp.egg-info/PKG-INFO +150 -0
- ldraney_notion_mcp-0.1.1/src/ldraney_notion_mcp.egg-info/SOURCES.txt +18 -0
- ldraney_notion_mcp-0.1.1/src/ldraney_notion_mcp.egg-info/dependency_links.txt +1 -0
- ldraney_notion_mcp-0.1.1/src/ldraney_notion_mcp.egg-info/requires.txt +6 -0
- ldraney_notion_mcp-0.1.1/src/ldraney_notion_mcp.egg-info/top_level.txt +1 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/__init__.py +5 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/__main__.py +5 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/server.py +74 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/__init__.py +13 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/blocks.py +100 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/comments.py +61 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/databases.py +236 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/pages.py +121 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/search.py +39 -0
- ldraney_notion_mcp-0.1.1/src/notion_mcp/tools/users.py +38 -0
- ldraney_notion_mcp-0.1.1/tests/test_tools.py +534 -0
|
@@ -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,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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
notion_mcp
|
|
@@ -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
|