@m2ai-mcp/notion-mcp 0.1.0
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.
- package/.env.example +7 -0
- package/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +374 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/blocks.d.ts +43 -0
- package/dist/tools/blocks.d.ts.map +1 -0
- package/dist/tools/blocks.js +124 -0
- package/dist/tools/blocks.js.map +1 -0
- package/dist/tools/databases.d.ts +71 -0
- package/dist/tools/databases.d.ts.map +1 -0
- package/dist/tools/databases.js +121 -0
- package/dist/tools/databases.js.map +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/pages.d.ts +72 -0
- package/dist/tools/pages.d.ts.map +1 -0
- package/dist/tools/pages.js +153 -0
- package/dist/tools/pages.js.map +1 -0
- package/dist/tools/search.d.ts +28 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +62 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/users.d.ts +33 -0
- package/dist/tools/users.d.ts.map +1 -0
- package/dist/tools/users.js +51 -0
- package/dist/tools/users.js.map +1 -0
- package/dist/utils/markdown-converter.d.ts +31 -0
- package/dist/utils/markdown-converter.d.ts.map +1 -0
- package/dist/utils/markdown-converter.js +355 -0
- package/dist/utils/markdown-converter.js.map +1 -0
- package/dist/utils/notion-client.d.ts +32 -0
- package/dist/utils/notion-client.d.ts.map +1 -0
- package/dist/utils/notion-client.js +111 -0
- package/dist/utils/notion-client.js.map +1 -0
- package/dist/utils/types.d.ts +212 -0
- package/dist/utils/types.d.ts.map +1 -0
- package/dist/utils/types.js +18 -0
- package/dist/utils/types.js.map +1 -0
- package/jest.config.cjs +33 -0
- package/package.json +53 -0
- package/server.json +92 -0
- package/src/index.ts +435 -0
- package/src/tools/blocks.ts +184 -0
- package/src/tools/databases.ts +216 -0
- package/src/tools/index.ts +9 -0
- package/src/tools/pages.ts +253 -0
- package/src/tools/search.ts +96 -0
- package/src/tools/users.ts +93 -0
- package/src/utils/markdown-converter.ts +408 -0
- package/src/utils/notion-client.ts +159 -0
- package/src/utils/types.ts +237 -0
- package/tests/markdown-converter.test.ts +252 -0
- package/tests/notion-client.test.ts +67 -0
- package/tests/tools.test.ts +448 -0
- package/tsconfig.json +20 -0
package/.env.example
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Notion MCP Server Configuration
|
|
2
|
+
# Copy this file to .env and fill in your values
|
|
3
|
+
|
|
4
|
+
# Required: Notion Integration API Key
|
|
5
|
+
# Create at: https://www.notion.so/my-integrations
|
|
6
|
+
# Select "Internal Integration" and copy the token
|
|
7
|
+
NOTION_API_KEY=secret_your_notion_integration_token_here
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Me, Myself Plus AI LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Notion MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server that provides AI assistants with full access to Notion workspaces. Enables Claude to search, read, create, and update pages, databases, and blocks.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Search & Discovery**: Search across all pages and databases in your workspace
|
|
8
|
+
- **Page Operations**: Create, read, update, and archive pages
|
|
9
|
+
- **Content Management**: Add, update, and delete content blocks with markdown support
|
|
10
|
+
- **Database Operations**: Query databases with filters and sorts, create new databases
|
|
11
|
+
- **User Management**: List workspace users and get user details
|
|
12
|
+
- **Rate Limiting**: Built-in rate limiting to respect Notion API limits (3 req/sec)
|
|
13
|
+
- **Markdown Conversion**: Automatic conversion between markdown and Notion blocks
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
### 1. Create a Notion Integration
|
|
25
|
+
|
|
26
|
+
1. Go to [Notion Integrations](https://www.notion.so/my-integrations)
|
|
27
|
+
2. Click "New integration"
|
|
28
|
+
3. Select "Internal integration"
|
|
29
|
+
4. Grant required capabilities:
|
|
30
|
+
- Read content
|
|
31
|
+
- Update content
|
|
32
|
+
- Insert content
|
|
33
|
+
- Read user information (optional)
|
|
34
|
+
5. Copy the "Internal Integration Token"
|
|
35
|
+
|
|
36
|
+
### 2. Share Content with Integration
|
|
37
|
+
|
|
38
|
+
For the integration to access pages and databases:
|
|
39
|
+
1. Open the page or database in Notion
|
|
40
|
+
2. Click the "..." menu in the top right
|
|
41
|
+
3. Click "Add connections"
|
|
42
|
+
4. Select your integration
|
|
43
|
+
|
|
44
|
+
### 3. Set Environment Variable
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export NOTION_API_KEY=secret_your_integration_token_here
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Or create a `.env` file:
|
|
51
|
+
```
|
|
52
|
+
NOTION_API_KEY=secret_your_integration_token_here
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Usage with Claude Desktop
|
|
56
|
+
|
|
57
|
+
Add to your `claude_desktop_config.json`:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"mcpServers": {
|
|
62
|
+
"notion": {
|
|
63
|
+
"command": "node",
|
|
64
|
+
"args": ["/path/to/notion-mcp/dist/index.js"],
|
|
65
|
+
"env": {
|
|
66
|
+
"NOTION_API_KEY": "secret_your_token_here"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Available Tools
|
|
74
|
+
|
|
75
|
+
### Search & Discovery
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `search` | Search across all pages and databases by keyword or title |
|
|
80
|
+
|
|
81
|
+
### Page Operations
|
|
82
|
+
|
|
83
|
+
| Tool | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| `get_page` | Retrieve a page's properties and metadata |
|
|
86
|
+
| `create_page` | Create a new page in a database or as child of another page |
|
|
87
|
+
| `update_page` | Update a page's properties (not content blocks) |
|
|
88
|
+
| `get_page_content` | Retrieve all content blocks from a page |
|
|
89
|
+
|
|
90
|
+
### Block Operations
|
|
91
|
+
|
|
92
|
+
| Tool | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `append_blocks` | Add new content blocks to a page (supports markdown) |
|
|
95
|
+
| `update_block` | Update an existing block's content |
|
|
96
|
+
| `delete_block` | Delete (archive) a block |
|
|
97
|
+
|
|
98
|
+
### Database Operations
|
|
99
|
+
|
|
100
|
+
| Tool | Description |
|
|
101
|
+
|------|-------------|
|
|
102
|
+
| `get_database` | Retrieve database schema and properties |
|
|
103
|
+
| `query_database` | Query a database with filters and sorts |
|
|
104
|
+
| `create_database` | Create a new database as child of a page |
|
|
105
|
+
|
|
106
|
+
### User Operations
|
|
107
|
+
|
|
108
|
+
| Tool | Description |
|
|
109
|
+
|------|-------------|
|
|
110
|
+
| `list_users` | List all users in the workspace |
|
|
111
|
+
| `get_user` | Get details about a specific user |
|
|
112
|
+
|
|
113
|
+
## Markdown Support
|
|
114
|
+
|
|
115
|
+
The server supports conversion of common markdown to Notion blocks:
|
|
116
|
+
|
|
117
|
+
- Headings (H1, H2, H3)
|
|
118
|
+
- Bold, italic, strikethrough, inline code
|
|
119
|
+
- Bullet and numbered lists
|
|
120
|
+
- Checkboxes / todo items
|
|
121
|
+
- Code blocks with language
|
|
122
|
+
- Links
|
|
123
|
+
- Blockquotes
|
|
124
|
+
- Horizontal rules
|
|
125
|
+
|
|
126
|
+
### Example
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
# My Page Title
|
|
130
|
+
|
|
131
|
+
This is a paragraph with **bold** and *italic* text.
|
|
132
|
+
|
|
133
|
+
- Bullet item 1
|
|
134
|
+
- Bullet item 2
|
|
135
|
+
|
|
136
|
+
1. Numbered item
|
|
137
|
+
2. Another item
|
|
138
|
+
|
|
139
|
+
- [ ] Todo item
|
|
140
|
+
- [x] Completed item
|
|
141
|
+
|
|
142
|
+
> A blockquote
|
|
143
|
+
|
|
144
|
+
\`\`\`javascript
|
|
145
|
+
const greeting = "Hello, World!";
|
|
146
|
+
\`\`\`
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Examples
|
|
150
|
+
|
|
151
|
+
### Search for Pages
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"query": "meeting notes",
|
|
156
|
+
"filter_type": "page",
|
|
157
|
+
"page_size": 10
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Create a Page in a Database
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"parent_id": "database-id-here",
|
|
166
|
+
"parent_type": "database_id",
|
|
167
|
+
"title": "New Task",
|
|
168
|
+
"properties": {
|
|
169
|
+
"Status": { "select": { "name": "In Progress" } }
|
|
170
|
+
},
|
|
171
|
+
"content": "## Task Description\n\nThis is the task content."
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Query a Database
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"database_id": "database-id-here",
|
|
180
|
+
"filter": {
|
|
181
|
+
"property": "Status",
|
|
182
|
+
"select": { "equals": "Done" }
|
|
183
|
+
},
|
|
184
|
+
"sorts": [
|
|
185
|
+
{ "property": "Due Date", "direction": "ascending" }
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Append Content to a Page
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"parent_id": "page-id-here",
|
|
195
|
+
"content": "## New Section\n\nAdding more content to this page.\n\n- Item 1\n- Item 2"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Known Limitations
|
|
200
|
+
|
|
201
|
+
- Cannot access pages not shared with the integration
|
|
202
|
+
- File/image uploads not supported (use URLs instead)
|
|
203
|
+
- Comments API limited
|
|
204
|
+
- Synced blocks are read-only
|
|
205
|
+
|
|
206
|
+
## Development
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Install dependencies
|
|
210
|
+
npm install
|
|
211
|
+
|
|
212
|
+
# Build
|
|
213
|
+
npm run build
|
|
214
|
+
|
|
215
|
+
# Run tests
|
|
216
|
+
npm test
|
|
217
|
+
|
|
218
|
+
# Run with coverage
|
|
219
|
+
npm run test:coverage
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
MIT
|
|
225
|
+
|
|
226
|
+
## Author
|
|
227
|
+
|
|
228
|
+
Me, Myself Plus AI LLC
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Notion MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Provides AI assistants with full access to Notion workspaces.
|
|
6
|
+
* Enables Claude to search, read, create, and update pages,
|
|
7
|
+
* databases, and blocks.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Notion MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Provides AI assistants with full access to Notion workspaces.
|
|
6
|
+
* Enables Claude to search, read, create, and update pages,
|
|
7
|
+
* databases, and blocks.
|
|
8
|
+
*/
|
|
9
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
10
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
11
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
12
|
+
import { NotionClient } from './utils/notion-client.js';
|
|
13
|
+
import { search, getPage, createPage, updatePage, getPageContent, appendBlocks, updateBlock, deleteBlock, getDatabase, queryDatabase, createDatabase, listUsers, getUser } from './tools/index.js';
|
|
14
|
+
// Get API key from environment
|
|
15
|
+
const NOTION_API_KEY = process.env.NOTION_API_KEY;
|
|
16
|
+
if (!NOTION_API_KEY) {
|
|
17
|
+
console.error('Error: NOTION_API_KEY environment variable is required');
|
|
18
|
+
console.error('Get your API key from https://www.notion.so/my-integrations');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
// Initialize Notion client
|
|
22
|
+
const notionClient = new NotionClient({ apiKey: NOTION_API_KEY });
|
|
23
|
+
// Tool definitions
|
|
24
|
+
const TOOLS = [
|
|
25
|
+
{
|
|
26
|
+
name: 'search',
|
|
27
|
+
description: 'Search across all pages and databases in the workspace. Use when user wants to find content by keyword or title.',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
query: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'Search query text'
|
|
34
|
+
},
|
|
35
|
+
filter_type: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
enum: ['page', 'database'],
|
|
38
|
+
description: 'Filter by object type'
|
|
39
|
+
},
|
|
40
|
+
sort_direction: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
enum: ['ascending', 'descending'],
|
|
43
|
+
description: 'Sort by last edited time'
|
|
44
|
+
},
|
|
45
|
+
page_size: {
|
|
46
|
+
type: 'number',
|
|
47
|
+
description: 'Number of results (max 100)'
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
required: ['query']
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'get_page',
|
|
55
|
+
description: 'Retrieve a page\'s properties and metadata. Use when user wants to view page details or check properties.',
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
properties: {
|
|
59
|
+
page_id: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
description: 'Notion page ID or URL'
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
required: ['page_id']
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'create_page',
|
|
69
|
+
description: 'Create a new page in a database or as a child of another page. Use when user wants to add new content to Notion.',
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
parent_id: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description: 'Parent database ID or page ID'
|
|
76
|
+
},
|
|
77
|
+
parent_type: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
enum: ['database_id', 'page_id'],
|
|
80
|
+
description: 'Type of parent'
|
|
81
|
+
},
|
|
82
|
+
title: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Page title'
|
|
85
|
+
},
|
|
86
|
+
properties: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
description: 'Database properties (for database parents)'
|
|
89
|
+
},
|
|
90
|
+
content: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Initial page content in markdown format'
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
required: ['parent_id', 'parent_type', 'title']
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'update_page',
|
|
100
|
+
description: 'Update a page\'s properties (not content blocks). Use when user wants to modify page metadata or database properties.',
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
page_id: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
description: 'Page ID to update'
|
|
107
|
+
},
|
|
108
|
+
properties: {
|
|
109
|
+
type: 'object',
|
|
110
|
+
description: 'Properties to update'
|
|
111
|
+
},
|
|
112
|
+
archived: {
|
|
113
|
+
type: 'boolean',
|
|
114
|
+
description: 'Archive or unarchive the page'
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
required: ['page_id', 'properties']
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'get_page_content',
|
|
122
|
+
description: 'Retrieve all content blocks from a page. Use when user wants to read the full content of a page.',
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
page_id: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
description: 'Page ID to get content from'
|
|
129
|
+
},
|
|
130
|
+
format: {
|
|
131
|
+
type: 'string',
|
|
132
|
+
enum: ['markdown', 'blocks', 'plain_text'],
|
|
133
|
+
description: 'Output format'
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
required: ['page_id']
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
name: 'append_blocks',
|
|
141
|
+
description: 'Add new content blocks to a page or block. Use when user wants to add content to an existing page.',
|
|
142
|
+
inputSchema: {
|
|
143
|
+
type: 'object',
|
|
144
|
+
properties: {
|
|
145
|
+
parent_id: {
|
|
146
|
+
type: 'string',
|
|
147
|
+
description: 'Page or block ID to append to'
|
|
148
|
+
},
|
|
149
|
+
content: {
|
|
150
|
+
type: 'string',
|
|
151
|
+
description: 'Content to add (supports markdown)'
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
required: ['parent_id', 'content']
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'update_block',
|
|
159
|
+
description: 'Update an existing block\'s content. Use when user wants to modify specific content.',
|
|
160
|
+
inputSchema: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
properties: {
|
|
163
|
+
block_id: {
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'Block ID to update'
|
|
166
|
+
},
|
|
167
|
+
content: {
|
|
168
|
+
type: 'string',
|
|
169
|
+
description: 'New content for the block'
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
required: ['block_id', 'content']
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'delete_block',
|
|
177
|
+
description: 'Delete a block (archive it). Use when user wants to remove content from a page.',
|
|
178
|
+
inputSchema: {
|
|
179
|
+
type: 'object',
|
|
180
|
+
properties: {
|
|
181
|
+
block_id: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'Block ID to delete'
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
required: ['block_id']
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'get_database',
|
|
191
|
+
description: 'Retrieve database schema and properties. Use when user wants to understand database structure.',
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: 'object',
|
|
194
|
+
properties: {
|
|
195
|
+
database_id: {
|
|
196
|
+
type: 'string',
|
|
197
|
+
description: 'Database ID'
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
required: ['database_id']
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'query_database',
|
|
205
|
+
description: 'Query a database with optional filters and sorts. Use when user wants to retrieve specific entries from a database.',
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
database_id: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
description: 'Database ID to query'
|
|
212
|
+
},
|
|
213
|
+
filter: {
|
|
214
|
+
type: 'object',
|
|
215
|
+
description: 'Notion filter object'
|
|
216
|
+
},
|
|
217
|
+
sorts: {
|
|
218
|
+
type: 'array',
|
|
219
|
+
description: 'Sort configuration'
|
|
220
|
+
},
|
|
221
|
+
page_size: {
|
|
222
|
+
type: 'number',
|
|
223
|
+
description: 'Results per page (max 100)'
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
required: ['database_id']
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'create_database',
|
|
231
|
+
description: 'Create a new database as a child of a page. Use when user wants to set up a new structured data collection.',
|
|
232
|
+
inputSchema: {
|
|
233
|
+
type: 'object',
|
|
234
|
+
properties: {
|
|
235
|
+
parent_page_id: {
|
|
236
|
+
type: 'string',
|
|
237
|
+
description: 'Parent page ID'
|
|
238
|
+
},
|
|
239
|
+
title: {
|
|
240
|
+
type: 'string',
|
|
241
|
+
description: 'Database title'
|
|
242
|
+
},
|
|
243
|
+
properties: {
|
|
244
|
+
type: 'object',
|
|
245
|
+
description: 'Database properties schema'
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
required: ['parent_page_id', 'title', 'properties']
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: 'list_users',
|
|
253
|
+
description: 'List all users in the workspace. Use when user needs to reference team members.',
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: 'object',
|
|
256
|
+
properties: {
|
|
257
|
+
page_size: {
|
|
258
|
+
type: 'number',
|
|
259
|
+
description: 'Number of users to return'
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'get_user',
|
|
266
|
+
description: 'Get details about a specific user. Use when user needs info about a team member.',
|
|
267
|
+
inputSchema: {
|
|
268
|
+
type: 'object',
|
|
269
|
+
properties: {
|
|
270
|
+
user_id: {
|
|
271
|
+
type: 'string',
|
|
272
|
+
description: 'User ID'
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
required: ['user_id']
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
];
|
|
279
|
+
// Create MCP server
|
|
280
|
+
const server = new Server({
|
|
281
|
+
name: 'notion-mcp',
|
|
282
|
+
version: '0.1.0'
|
|
283
|
+
}, {
|
|
284
|
+
capabilities: {
|
|
285
|
+
tools: {}
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
// Handle tool listing
|
|
289
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
290
|
+
return { tools: TOOLS };
|
|
291
|
+
});
|
|
292
|
+
// Handle tool execution
|
|
293
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
294
|
+
const { name, arguments: args } = request.params;
|
|
295
|
+
try {
|
|
296
|
+
let result;
|
|
297
|
+
switch (name) {
|
|
298
|
+
case 'search':
|
|
299
|
+
result = await search(notionClient, args);
|
|
300
|
+
break;
|
|
301
|
+
case 'get_page':
|
|
302
|
+
result = await getPage(notionClient, args);
|
|
303
|
+
break;
|
|
304
|
+
case 'create_page':
|
|
305
|
+
result = await createPage(notionClient, args);
|
|
306
|
+
break;
|
|
307
|
+
case 'update_page':
|
|
308
|
+
result = await updatePage(notionClient, args);
|
|
309
|
+
break;
|
|
310
|
+
case 'get_page_content':
|
|
311
|
+
result = await getPageContent(notionClient, args);
|
|
312
|
+
break;
|
|
313
|
+
case 'append_blocks':
|
|
314
|
+
result = await appendBlocks(notionClient, args);
|
|
315
|
+
break;
|
|
316
|
+
case 'update_block':
|
|
317
|
+
result = await updateBlock(notionClient, args);
|
|
318
|
+
break;
|
|
319
|
+
case 'delete_block':
|
|
320
|
+
result = await deleteBlock(notionClient, args);
|
|
321
|
+
break;
|
|
322
|
+
case 'get_database':
|
|
323
|
+
result = await getDatabase(notionClient, args);
|
|
324
|
+
break;
|
|
325
|
+
case 'query_database':
|
|
326
|
+
result = await queryDatabase(notionClient, args);
|
|
327
|
+
break;
|
|
328
|
+
case 'create_database':
|
|
329
|
+
result = await createDatabase(notionClient, args);
|
|
330
|
+
break;
|
|
331
|
+
case 'list_users':
|
|
332
|
+
result = await listUsers(notionClient, args);
|
|
333
|
+
break;
|
|
334
|
+
case 'get_user':
|
|
335
|
+
result = await getUser(notionClient, args);
|
|
336
|
+
break;
|
|
337
|
+
default:
|
|
338
|
+
return {
|
|
339
|
+
content: [{
|
|
340
|
+
type: 'text',
|
|
341
|
+
text: JSON.stringify({ error: `Unknown tool: ${name}` })
|
|
342
|
+
}],
|
|
343
|
+
isError: true
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
content: [{
|
|
348
|
+
type: 'text',
|
|
349
|
+
text: JSON.stringify(result, null, 2)
|
|
350
|
+
}]
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
355
|
+
return {
|
|
356
|
+
content: [{
|
|
357
|
+
type: 'text',
|
|
358
|
+
text: JSON.stringify({ error: errorMessage })
|
|
359
|
+
}],
|
|
360
|
+
isError: true
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
// Run server
|
|
365
|
+
async function main() {
|
|
366
|
+
const transport = new StdioServerTransport();
|
|
367
|
+
await server.connect(transport);
|
|
368
|
+
console.error('Notion MCP Server running on stdio');
|
|
369
|
+
}
|
|
370
|
+
main().catch((error) => {
|
|
371
|
+
console.error('Server error:', error);
|
|
372
|
+
process.exit(1);
|
|
373
|
+
});
|
|
374
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|