notion-mcp-server 0.0.1 → 0.0.2
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/README.md +28 -3
- package/build/config/index.js +1 -1
- package/build/schema/database.js +341 -0
- package/build/schema/number.js +42 -0
- package/build/schema/page-properties.js +60 -0
- package/build/schema/page.js +34 -3
- package/build/tools/createDatabase.js +18 -0
- package/build/tools/index.js +11 -1
- package/build/tools/queryDatabase.js +22 -0
- package/build/tools/updateDatabase.js +18 -0
- package/build/tools/updatePageProperties.js +21 -0
- package/build/types/database.js +5 -0
- package/build/types/page.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
# Notion MCP Server
|
|
2
2
|
|
|
3
|
-

|
|
4
3
|

|
|
5
4
|

|
|
6
5
|

|
|
6
|
+
[](https://smithery.ai/server/@awkoy/notion-mcp-server)
|
|
7
|
+

|
|
8
|
+

|
|
7
9
|
|
|
8
|
-
**Notion MCP Server** is a Model Context Protocol (MCP) server
|
|
10
|
+
**Notion MCP Server** is a Model Context Protocol (MCP) server implementation that enables AI assistants to interact with Notion's API. This production-ready server provides a complete set of tools and endpoints for reading, creating, and modifying Notion content through natural language interactions.
|
|
11
|
+
|
|
12
|
+
> 🚧 **Active Development**: Database support is now available! If you find this project useful, please consider giving it a star - it helps me know that this work is valuable to the community and motivates further development.
|
|
13
|
+
|
|
14
|
+
<a href="https://glama.ai/mcp/servers/zrh07hteaa">
|
|
15
|
+
<img width="380" height="200" src="https://glama.ai/mcp/servers/zrh07hteaa/badge" />
|
|
16
|
+
</a>
|
|
9
17
|
|
|
10
18
|
## 📑 Table of Contents
|
|
11
19
|
|
|
@@ -46,6 +54,8 @@
|
|
|
46
54
|
- "Create a new page with today's tasks"
|
|
47
55
|
- "Update my meeting notes in Notion"
|
|
48
56
|
- "Add bullet points to my meeting notes page"
|
|
57
|
+
- "Create a new database for tracking projects"
|
|
58
|
+
- "Add new entries to my task database"
|
|
49
59
|
|
|
50
60
|
### Cursor Integration
|
|
51
61
|
|
|
@@ -110,6 +120,7 @@ env NOTION_TOKEN=YOUR_KEY NOTION_PAGE_ID=YOUR_PAGE_ID npx -y notion-mcp-server
|
|
|
110
120
|
- **🔍 Data Retrieval** - Fetch information from Notion pages, blocks, and databases
|
|
111
121
|
- **✏️ Content Creation** - Create and update Notion pages and blocks
|
|
112
122
|
- **📊 Block Management** - Append, update, and delete blocks within Notion pages
|
|
123
|
+
- **💾 Database Operations** - Create, query, and update databases
|
|
113
124
|
- **🔄 Batch Operations** - Perform multiple operations in a single request
|
|
114
125
|
- **🗑️ Archive & Restore** - Archive and restore Notion pages
|
|
115
126
|
- **🔎 Search Functionality** - Search Notion pages and databases by title
|
|
@@ -125,6 +136,9 @@ The server provides the following tools for interacting with Notion:
|
|
|
125
136
|
##### `create_page`
|
|
126
137
|
Create a new page in Notion with specified content
|
|
127
138
|
|
|
139
|
+
##### `update_page_properties`
|
|
140
|
+
Update the properties of an existing Notion page
|
|
141
|
+
|
|
128
142
|
##### `archive_page`
|
|
129
143
|
Archive (move to trash) a Notion page by ID
|
|
130
144
|
|
|
@@ -134,6 +148,17 @@ Restore a previously archived Notion page by ID
|
|
|
134
148
|
##### `search_pages`
|
|
135
149
|
Search for pages and databases in Notion by title
|
|
136
150
|
|
|
151
|
+
#### Database Operations
|
|
152
|
+
|
|
153
|
+
##### `create_database`
|
|
154
|
+
Create a new database in Notion with specified properties
|
|
155
|
+
|
|
156
|
+
##### `query_database`
|
|
157
|
+
Query a database in Notion with filters, sorts, and pagination
|
|
158
|
+
|
|
159
|
+
##### `update_database`
|
|
160
|
+
Update an existing database's properties, title, or description
|
|
161
|
+
|
|
137
162
|
#### Block Operations
|
|
138
163
|
|
|
139
164
|
##### `retrieve_block`
|
|
@@ -204,7 +229,7 @@ The server currently does not expose any resources, focusing instead on tool-bas
|
|
|
204
229
|
- Built using TypeScript and the MCP SDK (version 1.7.0+)
|
|
205
230
|
- Uses the official Notion API client (@notionhq/client v2.3.0+)
|
|
206
231
|
- Follows the Model Context Protocol specification
|
|
207
|
-
- Implements tools for CRUD operations on Notion pages and
|
|
232
|
+
- Implements tools for CRUD operations on Notion pages, blocks, and databases
|
|
208
233
|
- Supports efficient batch operations for performance optimization
|
|
209
234
|
- Validates input/output with Zod schemas
|
|
210
235
|
|
package/build/config/index.js
CHANGED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ICON_SCHEMA } from "./icon.js";
|
|
3
|
+
import { FILE_SCHEMA } from "./file.js";
|
|
4
|
+
import { PARENT_SCHEMA } from "./page.js";
|
|
5
|
+
import { RICH_TEXT_ITEM_REQUEST_SCHEMA, TEXT_CONTENT_REQUEST_SCHEMA, TEXT_RICH_TEXT_ITEM_REQUEST_SCHEMA, } from "./rich-text.js";
|
|
6
|
+
import { preprocessJson } from "./preprocess.js";
|
|
7
|
+
import { NUMBER_FORMAT } from "./number.js";
|
|
8
|
+
import { getRootPageId } from "../services/notion.js";
|
|
9
|
+
export const EMPTY_OBJECT_SCHEMA = z.record(z.string(), z.never()).default({});
|
|
10
|
+
export const SELECT_COLOR_SCHEMA = z.enum([
|
|
11
|
+
"default",
|
|
12
|
+
"gray",
|
|
13
|
+
"brown",
|
|
14
|
+
"orange",
|
|
15
|
+
"yellow",
|
|
16
|
+
"green",
|
|
17
|
+
"blue",
|
|
18
|
+
"purple",
|
|
19
|
+
"pink",
|
|
20
|
+
"red",
|
|
21
|
+
]);
|
|
22
|
+
// Title property for database creation
|
|
23
|
+
export const TITLE_PROPERTY_SCHEMA = z.object({
|
|
24
|
+
title: z
|
|
25
|
+
.array(z.object({
|
|
26
|
+
text: TEXT_CONTENT_REQUEST_SCHEMA.describe("Text content for title segment"),
|
|
27
|
+
}))
|
|
28
|
+
.describe("Array of text segments that make up the title"),
|
|
29
|
+
});
|
|
30
|
+
// Database property schemas
|
|
31
|
+
// 1. Title property
|
|
32
|
+
export const TITLE_DB_PROPERTY_SCHEMA = z.object({
|
|
33
|
+
type: z.literal("title").describe("Title property type"),
|
|
34
|
+
title: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
35
|
+
description: z.string().optional().describe("Property description"),
|
|
36
|
+
});
|
|
37
|
+
// 2. Rich text property
|
|
38
|
+
export const RICH_TEXT_DB_PROPERTY_SCHEMA = z.object({
|
|
39
|
+
type: z.literal("rich_text").describe("Rich text property type"),
|
|
40
|
+
rich_text: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
41
|
+
description: z.string().optional().describe("Property description"),
|
|
42
|
+
});
|
|
43
|
+
// 3. Number property
|
|
44
|
+
export const NUMBER_DB_PROPERTY_SCHEMA = z.object({
|
|
45
|
+
type: z.literal("number").describe("Number property type"),
|
|
46
|
+
number: z
|
|
47
|
+
.object({
|
|
48
|
+
format: NUMBER_FORMAT.describe("Number format"),
|
|
49
|
+
})
|
|
50
|
+
.describe("Number property configuration"),
|
|
51
|
+
description: z.string().optional().describe("Property description"),
|
|
52
|
+
});
|
|
53
|
+
// 4. Select property
|
|
54
|
+
export const SELECT_OPTION_SCHEMA = z.object({
|
|
55
|
+
name: z.string().describe("Name of the select option"),
|
|
56
|
+
color: SELECT_COLOR_SCHEMA.optional().describe("Color of the select option"),
|
|
57
|
+
id: z.string().optional().describe("ID of the select option"),
|
|
58
|
+
});
|
|
59
|
+
export const SELECT_DB_PROPERTY_SCHEMA = z.object({
|
|
60
|
+
type: z.literal("select").describe("Select property type"),
|
|
61
|
+
select: z
|
|
62
|
+
.object({
|
|
63
|
+
options: z
|
|
64
|
+
.array(SELECT_OPTION_SCHEMA)
|
|
65
|
+
.optional()
|
|
66
|
+
.describe("Select options"),
|
|
67
|
+
})
|
|
68
|
+
.describe("Select property configuration"),
|
|
69
|
+
description: z.string().optional().describe("Property description"),
|
|
70
|
+
});
|
|
71
|
+
// 5. Multi-select property
|
|
72
|
+
export const MULTI_SELECT_DB_PROPERTY_SCHEMA = z.object({
|
|
73
|
+
type: z.literal("multi_select").describe("Multi-select property type"),
|
|
74
|
+
multi_select: z
|
|
75
|
+
.object({
|
|
76
|
+
options: z
|
|
77
|
+
.array(SELECT_OPTION_SCHEMA)
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Multi-select options"),
|
|
80
|
+
})
|
|
81
|
+
.describe("Multi-select property configuration"),
|
|
82
|
+
description: z.string().optional().describe("Property description"),
|
|
83
|
+
});
|
|
84
|
+
// 6. Date property
|
|
85
|
+
export const DATE_DB_PROPERTY_SCHEMA = z.object({
|
|
86
|
+
type: z.literal("date").describe("Date property type"),
|
|
87
|
+
date: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
88
|
+
description: z.string().optional().describe("Property description"),
|
|
89
|
+
});
|
|
90
|
+
// 7. People property
|
|
91
|
+
export const PEOPLE_DB_PROPERTY_SCHEMA = z.object({
|
|
92
|
+
type: z.literal("people").describe("People property type"),
|
|
93
|
+
people: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
94
|
+
description: z.string().optional().describe("Property description"),
|
|
95
|
+
});
|
|
96
|
+
// 8. Files property
|
|
97
|
+
export const FILES_DB_PROPERTY_SCHEMA = z.object({
|
|
98
|
+
type: z.literal("files").describe("Files property type"),
|
|
99
|
+
files: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
100
|
+
description: z.string().optional().describe("Property description"),
|
|
101
|
+
});
|
|
102
|
+
// 9. Checkbox property
|
|
103
|
+
export const CHECKBOX_DB_PROPERTY_SCHEMA = z.object({
|
|
104
|
+
type: z.literal("checkbox").describe("Checkbox property type"),
|
|
105
|
+
checkbox: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
106
|
+
description: z.string().optional().describe("Property description"),
|
|
107
|
+
});
|
|
108
|
+
// 10. URL property
|
|
109
|
+
export const URL_DB_PROPERTY_SCHEMA = z.object({
|
|
110
|
+
type: z.literal("url").describe("URL property type"),
|
|
111
|
+
url: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
112
|
+
description: z.string().optional().describe("Property description"),
|
|
113
|
+
});
|
|
114
|
+
// 11. Email property
|
|
115
|
+
export const EMAIL_DB_PROPERTY_SCHEMA = z.object({
|
|
116
|
+
type: z.literal("email").describe("Email property type"),
|
|
117
|
+
email: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
118
|
+
description: z.string().optional().describe("Property description"),
|
|
119
|
+
});
|
|
120
|
+
// 12. Phone number property
|
|
121
|
+
export const PHONE_NUMBER_DB_PROPERTY_SCHEMA = z.object({
|
|
122
|
+
type: z.literal("phone_number").describe("Phone number property type"),
|
|
123
|
+
phone_number: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
124
|
+
description: z.string().optional().describe("Property description"),
|
|
125
|
+
});
|
|
126
|
+
// 13. Formula property
|
|
127
|
+
export const FORMULA_DB_PROPERTY_SCHEMA = z.object({
|
|
128
|
+
type: z.literal("formula").describe("Formula property type"),
|
|
129
|
+
formula: z
|
|
130
|
+
.object({
|
|
131
|
+
expression: z.string().describe("Formula expression"),
|
|
132
|
+
})
|
|
133
|
+
.describe("Formula property configuration"),
|
|
134
|
+
description: z.string().optional().describe("Property description"),
|
|
135
|
+
});
|
|
136
|
+
// 14. Relation property
|
|
137
|
+
export const RELATION_DB_PROPERTY_SCHEMA = z.object({
|
|
138
|
+
type: z.literal("relation").describe("Relation property type"),
|
|
139
|
+
relation: z
|
|
140
|
+
.object({
|
|
141
|
+
database_id: z
|
|
142
|
+
.string()
|
|
143
|
+
.describe("The ID of the database this relation refers to"),
|
|
144
|
+
synced_property_name: z
|
|
145
|
+
.string()
|
|
146
|
+
.optional()
|
|
147
|
+
.describe("Synced property name"),
|
|
148
|
+
synced_property_id: z.string().optional().describe("Synced property ID"),
|
|
149
|
+
single_property: EMPTY_OBJECT_SCHEMA.describe("Whether this is a single property relation"),
|
|
150
|
+
})
|
|
151
|
+
.describe("Relation property configuration"),
|
|
152
|
+
description: z.string().optional().describe("Property description"),
|
|
153
|
+
});
|
|
154
|
+
// 15. Rollup property
|
|
155
|
+
export const ROLLUP_FUNCTION = z.enum([
|
|
156
|
+
"average",
|
|
157
|
+
"checked",
|
|
158
|
+
"count_per_group",
|
|
159
|
+
"count",
|
|
160
|
+
"count_values",
|
|
161
|
+
"date_range",
|
|
162
|
+
"earliest_date",
|
|
163
|
+
"empty",
|
|
164
|
+
"latest_date",
|
|
165
|
+
"max",
|
|
166
|
+
"median",
|
|
167
|
+
"min",
|
|
168
|
+
"not_empty",
|
|
169
|
+
"percent_checked",
|
|
170
|
+
"percent_empty",
|
|
171
|
+
"percent_not_empty",
|
|
172
|
+
"percent_per_group",
|
|
173
|
+
"percent_unchecked",
|
|
174
|
+
"range",
|
|
175
|
+
"show_original",
|
|
176
|
+
"show_unique",
|
|
177
|
+
"sum",
|
|
178
|
+
"unchecked",
|
|
179
|
+
"unique",
|
|
180
|
+
]);
|
|
181
|
+
export const ROLLUP_DB_PROPERTY_SCHEMA = z.object({
|
|
182
|
+
type: z.literal("rollup").describe("Rollup property type"),
|
|
183
|
+
rollup: z
|
|
184
|
+
.object({
|
|
185
|
+
relation_property_name: z
|
|
186
|
+
.string()
|
|
187
|
+
.describe("Name of the relation property"),
|
|
188
|
+
relation_property_id: z.string().describe("ID of the relation property"),
|
|
189
|
+
rollup_property_name: z
|
|
190
|
+
.string()
|
|
191
|
+
.describe("Name of the property to roll up"),
|
|
192
|
+
rollup_property_id: z.string().describe("ID of the property to roll up"),
|
|
193
|
+
function: ROLLUP_FUNCTION.describe("Rollup function"),
|
|
194
|
+
})
|
|
195
|
+
.describe("Rollup property configuration"),
|
|
196
|
+
description: z.string().optional().describe("Property description"),
|
|
197
|
+
});
|
|
198
|
+
// 16. Created time property
|
|
199
|
+
export const CREATED_TIME_DB_PROPERTY_SCHEMA = z.object({
|
|
200
|
+
type: z.literal("created_time").describe("Created time property type"),
|
|
201
|
+
created_time: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
202
|
+
description: z.string().optional().describe("Property description"),
|
|
203
|
+
});
|
|
204
|
+
// 17. Created by property
|
|
205
|
+
export const CREATED_BY_DB_PROPERTY_SCHEMA = z.object({
|
|
206
|
+
type: z.literal("created_by").describe("Created by property type"),
|
|
207
|
+
created_by: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
208
|
+
description: z.string().optional().describe("Property description"),
|
|
209
|
+
});
|
|
210
|
+
// 18. Last edited time property
|
|
211
|
+
export const LAST_EDITED_TIME_DB_PROPERTY_SCHEMA = z.object({
|
|
212
|
+
type: z
|
|
213
|
+
.literal("last_edited_time")
|
|
214
|
+
.describe("Last edited time property type"),
|
|
215
|
+
last_edited_time: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
216
|
+
description: z.string().optional().describe("Property description"),
|
|
217
|
+
});
|
|
218
|
+
// 19. Last edited by property
|
|
219
|
+
export const LAST_EDITED_BY_DB_PROPERTY_SCHEMA = z.object({
|
|
220
|
+
type: z.literal("last_edited_by").describe("Last edited by property type"),
|
|
221
|
+
last_edited_by: EMPTY_OBJECT_SCHEMA.describe("There is no additional property configuration."),
|
|
222
|
+
description: z.string().optional().describe("Property description"),
|
|
223
|
+
});
|
|
224
|
+
// Status property
|
|
225
|
+
export const STATUS_OPTION_SCHEMA = z.object({
|
|
226
|
+
id: z.string().optional().describe("ID of the status option"),
|
|
227
|
+
name: z.string().describe("Name of the status option"),
|
|
228
|
+
color: SELECT_COLOR_SCHEMA.describe("Color of the status option"),
|
|
229
|
+
});
|
|
230
|
+
export const STATUS_GROUP_SCHEMA = z.object({
|
|
231
|
+
id: z.string().optional().describe("ID of the status group"),
|
|
232
|
+
name: z.string().describe("Name of the status group"),
|
|
233
|
+
color: SELECT_COLOR_SCHEMA.describe("Color of the status group"),
|
|
234
|
+
option_ids: z.array(z.string()).describe("IDs of options in this group"),
|
|
235
|
+
});
|
|
236
|
+
export const STATUS_DB_PROPERTY_SCHEMA = z.object({
|
|
237
|
+
type: z.literal("status").describe("Status property type"),
|
|
238
|
+
status: z
|
|
239
|
+
.object({
|
|
240
|
+
options: z.array(STATUS_OPTION_SCHEMA).describe("Status options"),
|
|
241
|
+
})
|
|
242
|
+
.describe("Status property configuration"),
|
|
243
|
+
description: z.string().optional().describe("Property description"),
|
|
244
|
+
});
|
|
245
|
+
// Combined database property schema
|
|
246
|
+
export const DATABASE_PROPERTY_SCHEMA = z.preprocess(preprocessJson, z
|
|
247
|
+
.discriminatedUnion("type", [
|
|
248
|
+
TITLE_DB_PROPERTY_SCHEMA,
|
|
249
|
+
RICH_TEXT_DB_PROPERTY_SCHEMA,
|
|
250
|
+
NUMBER_DB_PROPERTY_SCHEMA,
|
|
251
|
+
SELECT_DB_PROPERTY_SCHEMA,
|
|
252
|
+
MULTI_SELECT_DB_PROPERTY_SCHEMA,
|
|
253
|
+
DATE_DB_PROPERTY_SCHEMA,
|
|
254
|
+
PEOPLE_DB_PROPERTY_SCHEMA,
|
|
255
|
+
FILES_DB_PROPERTY_SCHEMA,
|
|
256
|
+
CHECKBOX_DB_PROPERTY_SCHEMA,
|
|
257
|
+
URL_DB_PROPERTY_SCHEMA,
|
|
258
|
+
EMAIL_DB_PROPERTY_SCHEMA,
|
|
259
|
+
PHONE_NUMBER_DB_PROPERTY_SCHEMA,
|
|
260
|
+
FORMULA_DB_PROPERTY_SCHEMA,
|
|
261
|
+
RELATION_DB_PROPERTY_SCHEMA,
|
|
262
|
+
ROLLUP_DB_PROPERTY_SCHEMA,
|
|
263
|
+
CREATED_TIME_DB_PROPERTY_SCHEMA,
|
|
264
|
+
CREATED_BY_DB_PROPERTY_SCHEMA,
|
|
265
|
+
LAST_EDITED_TIME_DB_PROPERTY_SCHEMA,
|
|
266
|
+
LAST_EDITED_BY_DB_PROPERTY_SCHEMA,
|
|
267
|
+
])
|
|
268
|
+
.describe("Union of all possible database property types"));
|
|
269
|
+
// Create database schema
|
|
270
|
+
export const CREATE_DATABASE_SCHEMA = {
|
|
271
|
+
parent: PARENT_SCHEMA.optional()
|
|
272
|
+
.default({
|
|
273
|
+
type: "page_id",
|
|
274
|
+
page_id: getRootPageId(),
|
|
275
|
+
})
|
|
276
|
+
.describe("Optional parent - if not provided, will use NOTION_PAGE_ID as parent page"),
|
|
277
|
+
title: z.array(TEXT_RICH_TEXT_ITEM_REQUEST_SCHEMA).describe("Database title"),
|
|
278
|
+
description: z
|
|
279
|
+
.array(TEXT_RICH_TEXT_ITEM_REQUEST_SCHEMA)
|
|
280
|
+
.optional()
|
|
281
|
+
.describe("Database description"),
|
|
282
|
+
properties: z
|
|
283
|
+
.record(z.string().describe("Property name"), DATABASE_PROPERTY_SCHEMA.describe("Property schema"))
|
|
284
|
+
.describe("Database properties"),
|
|
285
|
+
is_inline: z
|
|
286
|
+
.boolean()
|
|
287
|
+
.optional()
|
|
288
|
+
.default(false)
|
|
289
|
+
.describe("Whether database is inline"),
|
|
290
|
+
icon: z.preprocess(preprocessJson, ICON_SCHEMA.nullable().optional().describe("Optional icon for the database")),
|
|
291
|
+
cover: z.preprocess(preprocessJson, FILE_SCHEMA.nullable()
|
|
292
|
+
.optional()
|
|
293
|
+
.describe("Optional cover image for the database")),
|
|
294
|
+
};
|
|
295
|
+
// Query database schema
|
|
296
|
+
export const QUERY_DATABASE_SCHEMA = {
|
|
297
|
+
database_id: z.string().describe("The ID of the database to query"),
|
|
298
|
+
filter: z
|
|
299
|
+
.preprocess(preprocessJson, z.any())
|
|
300
|
+
.optional()
|
|
301
|
+
.describe("Filter criteria for the query"),
|
|
302
|
+
sorts: z
|
|
303
|
+
.array(z.object({
|
|
304
|
+
property: z.string().optional().describe("Property to sort by"),
|
|
305
|
+
timestamp: z
|
|
306
|
+
.enum(["created_time", "last_edited_time"])
|
|
307
|
+
.describe("Timestamp to sort by"),
|
|
308
|
+
direction: z
|
|
309
|
+
.enum(["ascending", "descending"])
|
|
310
|
+
.describe("Sort direction"),
|
|
311
|
+
}))
|
|
312
|
+
.optional()
|
|
313
|
+
.describe("Sort criteria for the query"),
|
|
314
|
+
start_cursor: z.string().optional().describe("Cursor for pagination"),
|
|
315
|
+
page_size: z
|
|
316
|
+
.number()
|
|
317
|
+
.min(1)
|
|
318
|
+
.max(100)
|
|
319
|
+
.optional()
|
|
320
|
+
.describe("Number of results to return (1-100)"),
|
|
321
|
+
};
|
|
322
|
+
// Update database schema
|
|
323
|
+
export const UPDATE_DATABASE_SCHEMA = {
|
|
324
|
+
database_id: z.string().describe("The ID of the database to update"),
|
|
325
|
+
title: z
|
|
326
|
+
.array(RICH_TEXT_ITEM_REQUEST_SCHEMA)
|
|
327
|
+
.optional()
|
|
328
|
+
.describe("Updated database title"),
|
|
329
|
+
description: z
|
|
330
|
+
.array(RICH_TEXT_ITEM_REQUEST_SCHEMA)
|
|
331
|
+
.optional()
|
|
332
|
+
.describe("Updated database description"),
|
|
333
|
+
properties: z
|
|
334
|
+
.record(z.string().describe("Property name"), DATABASE_PROPERTY_SCHEMA.describe("Property schema"))
|
|
335
|
+
.describe("Properties of the page"),
|
|
336
|
+
is_inline: z.boolean().optional().describe("Whether database is inline"),
|
|
337
|
+
icon: z.preprocess(preprocessJson, ICON_SCHEMA.nullable().optional().describe("Updated icon for the database")),
|
|
338
|
+
cover: z.preprocess(preprocessJson, FILE_SCHEMA.nullable()
|
|
339
|
+
.optional()
|
|
340
|
+
.describe("Updated cover image for the database")),
|
|
341
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const NUMBER_FORMAT = z.enum([
|
|
3
|
+
"number",
|
|
4
|
+
"number_with_commas",
|
|
5
|
+
"percent",
|
|
6
|
+
"dollar",
|
|
7
|
+
"canadian_dollar",
|
|
8
|
+
"euro",
|
|
9
|
+
"pound",
|
|
10
|
+
"yen",
|
|
11
|
+
"ruble",
|
|
12
|
+
"rupee",
|
|
13
|
+
"won",
|
|
14
|
+
"yuan",
|
|
15
|
+
"real",
|
|
16
|
+
"lira",
|
|
17
|
+
"rupiah",
|
|
18
|
+
"franc",
|
|
19
|
+
"hong_kong_dollar",
|
|
20
|
+
"new_zealand_dollar",
|
|
21
|
+
"krona",
|
|
22
|
+
"norwegian_krone",
|
|
23
|
+
"mexican_peso",
|
|
24
|
+
"rand",
|
|
25
|
+
"new_taiwan_dollar",
|
|
26
|
+
"danish_krone",
|
|
27
|
+
"zloty",
|
|
28
|
+
"baht",
|
|
29
|
+
"forint",
|
|
30
|
+
"koruna",
|
|
31
|
+
"shekel",
|
|
32
|
+
"chilean_peso",
|
|
33
|
+
"philippine_peso",
|
|
34
|
+
"dirham",
|
|
35
|
+
"colombian_peso",
|
|
36
|
+
"riyal",
|
|
37
|
+
"ringgit",
|
|
38
|
+
"leu",
|
|
39
|
+
"argentine_peso",
|
|
40
|
+
"uruguayan_peso",
|
|
41
|
+
"singapore_dollar",
|
|
42
|
+
]);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { RICH_TEXT_ITEM_REQUEST_SCHEMA, TEXT_RICH_TEXT_ITEM_REQUEST_SCHEMA, } from "./rich-text.js";
|
|
3
|
+
export const CHECKBOX_PROPERTY_VALUE_SCHEMA = z.object({
|
|
4
|
+
checkbox: z.boolean(),
|
|
5
|
+
});
|
|
6
|
+
export const DATE_PROPERTY_VALUE_SCHEMA = z.object({
|
|
7
|
+
date: z.object({
|
|
8
|
+
start: z.string(),
|
|
9
|
+
end: z.string().optional(),
|
|
10
|
+
}),
|
|
11
|
+
});
|
|
12
|
+
export const EMAIL_PROPERTY_VALUE_SCHEMA = z.object({
|
|
13
|
+
email: z.string().email(),
|
|
14
|
+
});
|
|
15
|
+
export const FILES_PROPERTY_VALUE_SCHEMA = z.object({
|
|
16
|
+
files: z.array(z.object({
|
|
17
|
+
name: z.string(),
|
|
18
|
+
external: z.object({
|
|
19
|
+
url: z.string().url(),
|
|
20
|
+
}),
|
|
21
|
+
})),
|
|
22
|
+
});
|
|
23
|
+
export const MULTI_SELECT_PROPERTY_VALUE_SCHEMA = z.object({
|
|
24
|
+
multi_select: z.array(z.object({
|
|
25
|
+
id: z.string().optional(),
|
|
26
|
+
name: z.string().optional(),
|
|
27
|
+
})),
|
|
28
|
+
});
|
|
29
|
+
export const NUMBER_PROPERTY_VALUE_SCHEMA = z.object({ number: z.number() });
|
|
30
|
+
export const PEOPLE_PROPERTY_VALUE_SCHEMA = z.object({
|
|
31
|
+
people: z.array(z.object({
|
|
32
|
+
object: z.literal("user"),
|
|
33
|
+
id: z.string(),
|
|
34
|
+
})),
|
|
35
|
+
});
|
|
36
|
+
export const PHONE_NUMBER_PROPERTY_VALUE_SCHEMA = z.object({
|
|
37
|
+
phone_number: z.string(),
|
|
38
|
+
});
|
|
39
|
+
export const RELATION_PROPERTY_VALUE_SCHEMA = z.object({
|
|
40
|
+
relation: z.array(z.object({
|
|
41
|
+
id: z.string(),
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
export const RICH_TEXT_PROPERTY_VALUE_SCHEMA = z.object({
|
|
45
|
+
rich_text: z.array(RICH_TEXT_ITEM_REQUEST_SCHEMA),
|
|
46
|
+
});
|
|
47
|
+
export const SELECT_PROPERTY_VALUE_SCHEMA = z.object({
|
|
48
|
+
select: z.object({
|
|
49
|
+
name: z.string(),
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
export const STATUS_PROPERTY_VALUE_SCHEMA = z.object({
|
|
53
|
+
status: z.object({ name: z.string() }),
|
|
54
|
+
});
|
|
55
|
+
export const TITLE_PROPERTY_VALUE_SCHEMA = z.object({
|
|
56
|
+
title: z.array(TEXT_RICH_TEXT_ITEM_REQUEST_SCHEMA),
|
|
57
|
+
});
|
|
58
|
+
export const URL_PROPERTY_VALUE_SCHEMA = z.object({
|
|
59
|
+
url: z.string().url(),
|
|
60
|
+
});
|
package/build/schema/page.js
CHANGED
|
@@ -5,6 +5,7 @@ import { TEXT_BLOCK_REQUEST_SCHEMA } from "./blocks.js";
|
|
|
5
5
|
import { preprocessJson } from "./preprocess.js";
|
|
6
6
|
import { TEXT_CONTENT_REQUEST_SCHEMA } from "./rich-text.js";
|
|
7
7
|
import { FILE_SCHEMA } from "./file.js";
|
|
8
|
+
import { CHECKBOX_PROPERTY_VALUE_SCHEMA, DATE_PROPERTY_VALUE_SCHEMA, EMAIL_PROPERTY_VALUE_SCHEMA, FILES_PROPERTY_VALUE_SCHEMA, NUMBER_PROPERTY_VALUE_SCHEMA, PEOPLE_PROPERTY_VALUE_SCHEMA, PHONE_NUMBER_PROPERTY_VALUE_SCHEMA, RELATION_PROPERTY_VALUE_SCHEMA, RICH_TEXT_PROPERTY_VALUE_SCHEMA, SELECT_PROPERTY_VALUE_SCHEMA, STATUS_PROPERTY_VALUE_SCHEMA, } from "./page-properties.js";
|
|
8
9
|
export const TITLE_PROPERTY_SCHEMA = z.object({
|
|
9
10
|
title: z
|
|
10
11
|
.array(z.object({
|
|
@@ -30,9 +31,20 @@ export const CREATE_PAGE_SCHEMA = {
|
|
|
30
31
|
})
|
|
31
32
|
.describe("Optional parent - if not provided, will use NOTION_PAGE_ID as parent page"),
|
|
32
33
|
properties: z
|
|
33
|
-
.
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
.record(z.string().describe("Property name"), z.union([
|
|
35
|
+
TITLE_PROPERTY_SCHEMA,
|
|
36
|
+
CHECKBOX_PROPERTY_VALUE_SCHEMA,
|
|
37
|
+
EMAIL_PROPERTY_VALUE_SCHEMA,
|
|
38
|
+
STATUS_PROPERTY_VALUE_SCHEMA,
|
|
39
|
+
FILES_PROPERTY_VALUE_SCHEMA,
|
|
40
|
+
DATE_PROPERTY_VALUE_SCHEMA,
|
|
41
|
+
PEOPLE_PROPERTY_VALUE_SCHEMA,
|
|
42
|
+
PHONE_NUMBER_PROPERTY_VALUE_SCHEMA,
|
|
43
|
+
RELATION_PROPERTY_VALUE_SCHEMA,
|
|
44
|
+
RICH_TEXT_PROPERTY_VALUE_SCHEMA,
|
|
45
|
+
SELECT_PROPERTY_VALUE_SCHEMA,
|
|
46
|
+
NUMBER_PROPERTY_VALUE_SCHEMA,
|
|
47
|
+
]))
|
|
36
48
|
.describe("Properties of the page"),
|
|
37
49
|
children: z
|
|
38
50
|
.array(TEXT_BLOCK_REQUEST_SCHEMA)
|
|
@@ -49,6 +61,25 @@ export const ARCHIVE_PAGE_SCHEMA = {
|
|
|
49
61
|
export const RESTORE_PAGE_SCHEMA = {
|
|
50
62
|
pageId: z.string().describe("The ID of the page to restore"),
|
|
51
63
|
};
|
|
64
|
+
export const UPDATE_PAGE_PROPERTIES_SCHEMA = {
|
|
65
|
+
pageId: z.string().describe("The ID of the page to restore"),
|
|
66
|
+
properties: z
|
|
67
|
+
.record(z.string().describe("Property name"), z.union([
|
|
68
|
+
TITLE_PROPERTY_SCHEMA,
|
|
69
|
+
CHECKBOX_PROPERTY_VALUE_SCHEMA,
|
|
70
|
+
EMAIL_PROPERTY_VALUE_SCHEMA,
|
|
71
|
+
STATUS_PROPERTY_VALUE_SCHEMA,
|
|
72
|
+
FILES_PROPERTY_VALUE_SCHEMA,
|
|
73
|
+
DATE_PROPERTY_VALUE_SCHEMA,
|
|
74
|
+
PEOPLE_PROPERTY_VALUE_SCHEMA,
|
|
75
|
+
PHONE_NUMBER_PROPERTY_VALUE_SCHEMA,
|
|
76
|
+
RELATION_PROPERTY_VALUE_SCHEMA,
|
|
77
|
+
RICH_TEXT_PROPERTY_VALUE_SCHEMA,
|
|
78
|
+
SELECT_PROPERTY_VALUE_SCHEMA,
|
|
79
|
+
NUMBER_PROPERTY_VALUE_SCHEMA,
|
|
80
|
+
]))
|
|
81
|
+
.describe("Properties of the page"),
|
|
82
|
+
};
|
|
52
83
|
export const SEARCH_PAGES_SCHEMA = {
|
|
53
84
|
query: z.string().optional().describe("Search query for filtering by title"),
|
|
54
85
|
sort: z
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { notion } from "../services/notion.js";
|
|
2
|
+
import { handleNotionError } from "../utils/error.js";
|
|
3
|
+
export const createDatabase = async (params) => {
|
|
4
|
+
try {
|
|
5
|
+
const response = await notion.databases.create(params);
|
|
6
|
+
return {
|
|
7
|
+
content: [
|
|
8
|
+
{
|
|
9
|
+
type: "text",
|
|
10
|
+
text: `Database created successfully: ${response.id}`,
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return handleNotionError(error);
|
|
17
|
+
}
|
|
18
|
+
};
|
package/build/tools/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { server } from "../server/index.js";
|
|
2
|
-
import { CREATE_PAGE_SCHEMA, ARCHIVE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, } from "../schema/page.js";
|
|
2
|
+
import { CREATE_PAGE_SCHEMA, ARCHIVE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, UPDATE_PAGE_PROPERTIES_SCHEMA, } from "../schema/page.js";
|
|
3
3
|
import { APPEND_BLOCK_CHILDREN_SCHEMA, RETRIEVE_BLOCK_SCHEMA, RETRIEVE_BLOCK_CHILDREN_SCHEMA, UPDATE_BLOCK_SCHEMA, DELETE_BLOCK_SCHEMA, BATCH_APPEND_BLOCK_CHILDREN_SCHEMA, BATCH_UPDATE_BLOCKS_SCHEMA, BATCH_DELETE_BLOCKS_SCHEMA, BATCH_MIXED_OPERATIONS_SCHEMA, } from "../schema/blocks.js";
|
|
4
|
+
import { CREATE_DATABASE_SCHEMA, QUERY_DATABASE_SCHEMA, UPDATE_DATABASE_SCHEMA, } from "../schema/database.js";
|
|
4
5
|
import { archivePage, restorePage } from "./updatePage.js";
|
|
5
6
|
import { registerCreatePageTool } from "./createPage.js";
|
|
6
7
|
import { searchPages } from "./searchPage.js";
|
|
@@ -13,9 +14,14 @@ import { batchAppendBlockChildren } from "./batchAppendBlockChildren.js";
|
|
|
13
14
|
import { batchUpdateBlocks } from "./batchUpdateBlocks.js";
|
|
14
15
|
import { batchDeleteBlocks } from "./batchDeleteBlocks.js";
|
|
15
16
|
import { batchMixedOperations } from "./batchMixedOperations.js";
|
|
17
|
+
import { createDatabase } from "./createDatabase.js";
|
|
18
|
+
import { queryDatabase } from "./queryDatabase.js";
|
|
19
|
+
import { updateDatabase } from "./updateDatabase.js";
|
|
20
|
+
import { updatePageProperties } from "./updatePageProperties.js";
|
|
16
21
|
export const registerAllTools = () => {
|
|
17
22
|
server.tool("create_page", "Create a new page in Notion", CREATE_PAGE_SCHEMA, registerCreatePageTool);
|
|
18
23
|
server.tool("archive_page", "Archive (trash) a Notion page", ARCHIVE_PAGE_SCHEMA, archivePage);
|
|
24
|
+
server.tool("update_page_properties", "Update the properties of a Notion page", UPDATE_PAGE_PROPERTIES_SCHEMA, updatePageProperties);
|
|
19
25
|
server.tool("restore_page", "Restore a previously archived Notion page", RESTORE_PAGE_SCHEMA, restorePage);
|
|
20
26
|
server.tool("search_pages", "Search for pages and databases in Notion by title", SEARCH_PAGES_SCHEMA, searchPages);
|
|
21
27
|
server.tool("append_block_children", "Append child blocks to a parent block in Notion", APPEND_BLOCK_CHILDREN_SCHEMA, appendBlockChildren);
|
|
@@ -23,6 +29,10 @@ export const registerAllTools = () => {
|
|
|
23
29
|
server.tool("retrieve_block_children", "Retrieve the children of a block from Notion", RETRIEVE_BLOCK_CHILDREN_SCHEMA, retrieveBlockChildren);
|
|
24
30
|
server.tool("update_block", "Update a block's content in Notion", UPDATE_BLOCK_SCHEMA, updateBlock);
|
|
25
31
|
server.tool("delete_block", "Delete (move to trash) a block in Notion", DELETE_BLOCK_SCHEMA, deleteBlock);
|
|
32
|
+
// Register database tools
|
|
33
|
+
server.tool("create_database", "Create a new database in Notion", CREATE_DATABASE_SCHEMA, createDatabase);
|
|
34
|
+
server.tool("query_database", "Query a database in Notion", QUERY_DATABASE_SCHEMA, queryDatabase);
|
|
35
|
+
server.tool("update_database", "Update a database in Notion", UPDATE_DATABASE_SCHEMA, updateDatabase);
|
|
26
36
|
// Register batch operation tools
|
|
27
37
|
server.tool("batch_append_block_children", "Append children to multiple blocks in a single operation", BATCH_APPEND_BLOCK_CHILDREN_SCHEMA, batchAppendBlockChildren);
|
|
28
38
|
server.tool("batch_update_blocks", "Update multiple blocks in a single operation", BATCH_UPDATE_BLOCKS_SCHEMA, batchUpdateBlocks);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { notion } from "../services/notion.js";
|
|
2
|
+
import { handleNotionError } from "../utils/error.js";
|
|
3
|
+
export const queryDatabase = async (params) => {
|
|
4
|
+
try {
|
|
5
|
+
const response = await notion.databases.query(params);
|
|
6
|
+
return {
|
|
7
|
+
content: [
|
|
8
|
+
{
|
|
9
|
+
type: "text",
|
|
10
|
+
text: `Database queried successfully. Found ${response.results.length} results.`,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
type: "text",
|
|
14
|
+
text: JSON.stringify(response, null, 2),
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
return handleNotionError(error);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { notion } from "../services/notion.js";
|
|
2
|
+
import { handleNotionError } from "../utils/error.js";
|
|
3
|
+
export const updateDatabase = async (params) => {
|
|
4
|
+
try {
|
|
5
|
+
const response = await notion.databases.update(params);
|
|
6
|
+
return {
|
|
7
|
+
content: [
|
|
8
|
+
{
|
|
9
|
+
type: "text",
|
|
10
|
+
text: `Database updated successfully: ${response.id}`,
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
return handleNotionError(error);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { notion } from "../services/notion.js";
|
|
2
|
+
import { handleNotionError } from "../utils/error.js";
|
|
3
|
+
export async function updatePageProperties(params) {
|
|
4
|
+
try {
|
|
5
|
+
const response = await notion.pages.update({
|
|
6
|
+
page_id: params.pageId,
|
|
7
|
+
properties: params.properties,
|
|
8
|
+
});
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: `Page properties updated successfully: ${response.id}`,
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
return handleNotionError(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { CREATE_DATABASE_SCHEMA, QUERY_DATABASE_SCHEMA, UPDATE_DATABASE_SCHEMA, } from "../schema/database.js";
|
|
3
|
+
export const createDatabaseSchema = z.object(CREATE_DATABASE_SCHEMA);
|
|
4
|
+
export const queryDatabaseSchema = z.object(QUERY_DATABASE_SCHEMA);
|
|
5
|
+
export const updateDatabaseSchema = z.object(UPDATE_DATABASE_SCHEMA);
|
package/build/types/page.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ARCHIVE_PAGE_SCHEMA, CREATE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, } from "../schema/page.js";
|
|
2
|
+
import { ARCHIVE_PAGE_SCHEMA, CREATE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, UPDATE_PAGE_PROPERTIES_SCHEMA, } from "../schema/page.js";
|
|
3
3
|
export const createPageSchema = z.object(CREATE_PAGE_SCHEMA);
|
|
4
4
|
export const archivePageSchema = z.object(ARCHIVE_PAGE_SCHEMA);
|
|
5
5
|
export const restorePageSchema = z.object(RESTORE_PAGE_SCHEMA);
|
|
6
6
|
export const searchPagesSchema = z.object(SEARCH_PAGES_SCHEMA);
|
|
7
|
+
export const updatePagePropertiesSchema = z.object(UPDATE_PAGE_PROPERTIES_SCHEMA);
|