notion-mcp-server 0.0.2 → 1.0.1

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 CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
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
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.
12
+ > 🚧 **Active Development**: Database support is now available! Comments and user management tools have been added. 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
13
 
14
14
  <a href="https://glama.ai/mcp/servers/zrh07hteaa">
15
15
  <img width="380" height="200" src="https://glama.ai/mcp/servers/zrh07hteaa/badge" />
@@ -56,6 +56,10 @@
56
56
  - "Add bullet points to my meeting notes page"
57
57
  - "Create a new database for tracking projects"
58
58
  - "Add new entries to my task database"
59
+ - "Add a comment to my project page"
60
+ - "Show me all comments on this document"
61
+ - "List all users in my workspace"
62
+ - "Get information about a specific user"
59
63
 
60
64
  ### Cursor Integration
61
65
 
@@ -124,6 +128,8 @@ env NOTION_TOKEN=YOUR_KEY NOTION_PAGE_ID=YOUR_PAGE_ID npx -y notion-mcp-server
124
128
  - **🔄 Batch Operations** - Perform multiple operations in a single request
125
129
  - **🗑️ Archive & Restore** - Archive and restore Notion pages
126
130
  - **🔎 Search Functionality** - Search Notion pages and databases by title
131
+ - **💬 Comments Management** - Get, create, and reply to comments on pages and discussions
132
+ - **👥 User Management** - Retrieve workspace users and user information
127
133
 
128
134
  ## 📚 Documentation
129
135
 
@@ -190,6 +196,28 @@ Delete multiple blocks in a single operation
190
196
  ##### `batch_mixed_operations`
191
197
  Perform a mix of append, update, and delete operations in a single request
192
198
 
199
+ #### Comment Operations
200
+
201
+ ##### `get_comments`
202
+ Retrieve comments from a page or block with pagination support
203
+
204
+ ##### `add_page_comment`
205
+ Add a new comment to a Notion page
206
+
207
+ ##### `add_discussion_comment`
208
+ Add a comment to an existing discussion thread
209
+
210
+ #### User Operations
211
+
212
+ ##### `get_list_users`
213
+ Retrieve a paginated list of all users in the workspace
214
+
215
+ ##### `get_user`
216
+ Get detailed information about a specific user by ID
217
+
218
+ ##### `get_bot_user`
219
+ Retrieve the current bot user associated with the API token
220
+
193
221
  ### Available Resources
194
222
 
195
223
  The server currently does not expose any resources, focusing instead on tool-based operations.
@@ -1,5 +1,5 @@
1
1
  // Configuration
2
2
  export const CONFIG = {
3
3
  serverName: "notion-mcp-server",
4
- serverVersion: "0.0.2",
4
+ serverVersion: "1.0.1",
5
5
  };
@@ -207,3 +207,64 @@ export const BATCH_MIXED_OPERATIONS_SCHEMA = {
207
207
  ]))
208
208
  .describe("Array of mixed operations to perform in a single batch"),
209
209
  };
210
+ // Combined schema for all block operations
211
+ export const BLOCKS_OPERATION_SCHEMA = {
212
+ payload: z
213
+ .preprocess(preprocessJson, z.discriminatedUnion("action", [
214
+ z.object({
215
+ action: z
216
+ .literal("append_block_children")
217
+ .describe("Use this action to append children to a block."),
218
+ params: z.object(APPEND_BLOCK_CHILDREN_SCHEMA),
219
+ }),
220
+ z.object({
221
+ action: z
222
+ .literal("retrieve_block")
223
+ .describe("Use this action to retrieve a block."),
224
+ params: z.object(RETRIEVE_BLOCK_SCHEMA),
225
+ }),
226
+ z.object({
227
+ action: z
228
+ .literal("retrieve_block_children")
229
+ .describe("Use this action to retrieve children of a block."),
230
+ params: z.object(RETRIEVE_BLOCK_CHILDREN_SCHEMA),
231
+ }),
232
+ z.object({
233
+ action: z
234
+ .literal("update_block")
235
+ .describe("Use this action to update a block."),
236
+ params: z.object(UPDATE_BLOCK_SCHEMA),
237
+ }),
238
+ z.object({
239
+ action: z
240
+ .literal("delete_block")
241
+ .describe("Use this action to delete/archive a block."),
242
+ params: z.object(DELETE_BLOCK_SCHEMA),
243
+ }),
244
+ z.object({
245
+ action: z
246
+ .literal("batch_append_block_children")
247
+ .describe("Use this action to perform batch append operations on blocks."),
248
+ params: z.object(BATCH_APPEND_BLOCK_CHILDREN_SCHEMA),
249
+ }),
250
+ z.object({
251
+ action: z
252
+ .literal("batch_update_blocks")
253
+ .describe("Use this action to perform batch update operations on blocks."),
254
+ params: z.object(BATCH_UPDATE_BLOCKS_SCHEMA),
255
+ }),
256
+ z.object({
257
+ action: z
258
+ .literal("batch_delete_blocks")
259
+ .describe("Use this action to perform batch delete operations on blocks."),
260
+ params: z.object(BATCH_DELETE_BLOCKS_SCHEMA),
261
+ }),
262
+ z.object({
263
+ action: z
264
+ .literal("batch_mixed_operations")
265
+ .describe("Use this action to perform batch mixed operations on blocks."),
266
+ params: z.object(BATCH_MIXED_OPERATIONS_SCHEMA),
267
+ }),
268
+ ]))
269
+ .describe("A union of all possible block operations. Each operation has a specific action and corresponding parameters. Use this schema to validate the input for block operations such as appending, retrieving, updating, deleting, and performing batch operations. Available actions include: 'append_block_children', 'retrieve_block', 'retrieve_block_children', 'update_block', 'delete_block', 'batch_append_block_children', 'batch_update_blocks', 'batch_delete_blocks', and 'batch_mixed_operations'. Each operation requires specific parameters as defined in the corresponding schemas."),
270
+ };
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { RICH_TEXT_ITEM_REQUEST_SCHEMA } from "./rich-text.js";
3
+ import { preprocessJson } from "./preprocess.js";
4
+ // Schema for getting comments
5
+ export const GET_COMMENTS_SCHEMA = {
6
+ block_id: z
7
+ .string()
8
+ .describe("The ID of the block or page to get comments from"),
9
+ start_cursor: z
10
+ .string()
11
+ .optional()
12
+ .describe("The cursor to start from for pagination"),
13
+ page_size: z
14
+ .number()
15
+ .optional()
16
+ .describe("Number of comments to return per page"),
17
+ };
18
+ // Schema for adding a comment to a page
19
+ export const ADD_PAGE_COMMENT_SCHEMA = {
20
+ parent: z.object({
21
+ page_id: z.string().describe("The ID of the page to add the comment to"),
22
+ }),
23
+ rich_text: z
24
+ .array(RICH_TEXT_ITEM_REQUEST_SCHEMA)
25
+ .describe("Rich text content for the comment"),
26
+ };
27
+ // Schema for adding a comment to a discussion
28
+ export const ADD_DISCUSSION_COMMENT_SCHEMA = {
29
+ discussion_id: z
30
+ .string()
31
+ .describe("The ID of the discussion to add the comment to"),
32
+ rich_text: z
33
+ .array(RICH_TEXT_ITEM_REQUEST_SCHEMA)
34
+ .describe("Rich text content for the comment"),
35
+ };
36
+ // Combined schema for all comment operations
37
+ export const COMMENTS_OPERATION_SCHEMA = {
38
+ payload: z
39
+ .preprocess(preprocessJson, z.discriminatedUnion("action", [
40
+ z.object({
41
+ action: z
42
+ .literal("get_comments")
43
+ .describe("Use this action to get comments from a block or page."),
44
+ params: z.object(GET_COMMENTS_SCHEMA),
45
+ }),
46
+ z.object({
47
+ action: z
48
+ .literal("add_page_comment")
49
+ .describe("Use this action to add a comment to a page."),
50
+ params: z.object(ADD_PAGE_COMMENT_SCHEMA),
51
+ }),
52
+ z.object({
53
+ action: z
54
+ .literal("add_discussion_comment")
55
+ .describe("Use this action to add a comment to a discussion."),
56
+ params: z.object(ADD_DISCUSSION_COMMENT_SCHEMA),
57
+ }),
58
+ ]))
59
+ .describe("A union of all possible comment operations. Each operation has a specific action and corresponding parameters. Use this schema to validate the input for comment operations such as getting, adding to page, and adding to discussion. Available actions include: 'get_comments', 'add_page_comment', and 'add_discussion_comment'. Each operation requires specific parameters as defined in the corresponding schemas."),
60
+ };
@@ -339,3 +339,28 @@ export const UPDATE_DATABASE_SCHEMA = {
339
339
  .optional()
340
340
  .describe("Updated cover image for the database")),
341
341
  };
342
+ // Combined schema for all database operations
343
+ export const DATABASE_OPERATION_SCHEMA = {
344
+ payload: z
345
+ .preprocess(preprocessJson, z.discriminatedUnion("action", [
346
+ z.object({
347
+ action: z
348
+ .literal("create_database")
349
+ .describe("Use this action to create a new database."),
350
+ params: z.object(CREATE_DATABASE_SCHEMA),
351
+ }),
352
+ z.object({
353
+ action: z
354
+ .literal("query_database")
355
+ .describe("Use this action to query a database."),
356
+ params: z.object(QUERY_DATABASE_SCHEMA),
357
+ }),
358
+ z.object({
359
+ action: z
360
+ .literal("update_database")
361
+ .describe("Use this action to update a database."),
362
+ params: z.object(UPDATE_DATABASE_SCHEMA),
363
+ }),
364
+ ]))
365
+ .describe("A union of all possible database operations. Each operation has a specific action and corresponding parameters. Use this schema to validate the input for database operations such as creating, querying, and updating databases. Available actions include: 'create_database', 'query_database', and 'update_database'. Each operation requires specific parameters as defined in the corresponding schemas."),
366
+ };
@@ -97,3 +97,40 @@ export const SEARCH_PAGES_SCHEMA = {
97
97
  .optional()
98
98
  .describe("Number of results to return (1-100)"),
99
99
  };
100
+ // Combined schema for all page operations
101
+ export const PAGES_OPERATION_SCHEMA = {
102
+ payload: z
103
+ .preprocess(preprocessJson, z.discriminatedUnion("action", [
104
+ z.object({
105
+ action: z
106
+ .literal("create_page")
107
+ .describe("Use this action to create a new page in the database."),
108
+ params: z.object(CREATE_PAGE_SCHEMA),
109
+ }),
110
+ z.object({
111
+ action: z
112
+ .literal("archive_page")
113
+ .describe("Use this action to archive an existing page, making it inactive."),
114
+ params: z.object(ARCHIVE_PAGE_SCHEMA),
115
+ }),
116
+ z.object({
117
+ action: z
118
+ .literal("restore_page")
119
+ .describe("Use this action to restore a previously archived page."),
120
+ params: z.object(RESTORE_PAGE_SCHEMA),
121
+ }),
122
+ z.object({
123
+ action: z
124
+ .literal("search_pages")
125
+ .describe("Use this action to search for pages based on a query."),
126
+ params: z.object(SEARCH_PAGES_SCHEMA),
127
+ }),
128
+ z.object({
129
+ action: z
130
+ .literal("update_page_properties")
131
+ .describe("Use this action to update the properties of an existing page."),
132
+ params: z.object(UPDATE_PAGE_PROPERTIES_SCHEMA),
133
+ }),
134
+ ]))
135
+ .describe("A union of all possible page operations. Each operation has a specific action and corresponding parameters. Use this schema to validate the input for page operations such as creating, archiving, restoring, searching, and updating pages. Available actions include: 'create_page', 'archive_page', 'restore_page', 'search_pages', and 'update_page_properties'. Each operation requires specific parameters as defined in the corresponding schemas."),
136
+ };
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ import { preprocessJson } from "./preprocess.js";
3
+ // Schema for listing users with pagination
4
+ export const LIST_USERS_SCHEMA = {
5
+ start_cursor: z.string().optional().describe("Pagination cursor"),
6
+ page_size: z
7
+ .number()
8
+ .optional()
9
+ .describe("Number of users to return per page"),
10
+ };
11
+ // Schema for getting a single user
12
+ export const GET_USER_SCHEMA = {
13
+ user_id: z.string().describe("The ID of the user to retrieve"),
14
+ };
15
+ // Combined schema for all user operations
16
+ export const USERS_OPERATION_SCHEMA = {
17
+ payload: z
18
+ .preprocess(preprocessJson, z.discriminatedUnion("action", [
19
+ z.object({
20
+ action: z
21
+ .literal("list_users")
22
+ .describe("Use this action to list users."),
23
+ params: z.object(LIST_USERS_SCHEMA),
24
+ }),
25
+ z.object({
26
+ action: z
27
+ .literal("get_user")
28
+ .describe("Use this action to get a single user."),
29
+ params: z.object(GET_USER_SCHEMA),
30
+ }),
31
+ z.object({
32
+ action: z
33
+ .literal("get_bot_user")
34
+ .describe("Use this action to get the bot user."),
35
+ params: z.object({}),
36
+ }),
37
+ ]))
38
+ .describe("A union of all possible user operations. Each operation has a specific action and corresponding parameters. Use this schema to validate the input for user operations such as listing, getting a single user, and getting the bot user. Available actions include: 'list_users', 'get_user', and 'get_bot_user'. Each operation requires specific parameters as defined in the corresponding schemas."),
39
+ };
@@ -18,7 +18,7 @@ export async function startServer() {
18
18
  try {
19
19
  const transport = new StdioServerTransport();
20
20
  await server.connect(transport);
21
- console.error(`${CONFIG.serverName} v${CONFIG.serverVersion} running on stdio`);
21
+ console.log(`${CONFIG.serverName} v${CONFIG.serverVersion} running on stdio`);
22
22
  }
23
23
  catch (error) {
24
24
  console.error("Server initialization error:", error instanceof Error ? error.message : String(error));
@@ -0,0 +1,13 @@
1
+ export function sendLog(level, message, data = null) {
2
+ fetch("http://localhost:4400/api/log", {
3
+ method: "POST",
4
+ headers: {
5
+ "Content-Type": "application/json",
6
+ },
7
+ body: JSON.stringify({
8
+ level, // 'debug', 'info', 'warn', 'error'
9
+ message,
10
+ data, // Optional additional data object or string
11
+ }),
12
+ }).catch((error) => console.error("Error sending log:", error));
13
+ }
@@ -0,0 +1,34 @@
1
+ import { handleNotionError } from "../utils/error.js";
2
+ import { appendBlockChildren } from "./appendBlockChildren.js";
3
+ import { retrieveBlock } from "./retrieveBlock.js";
4
+ import { retrieveBlockChildren } from "./retrieveBlockChildren.js";
5
+ import { updateBlock } from "./updateBlock.js";
6
+ import { deleteBlock } from "./deleteBlock.js";
7
+ import { batchAppendBlockChildren } from "./batchAppendBlockChildren.js";
8
+ import { batchUpdateBlocks } from "./batchUpdateBlocks.js";
9
+ import { batchDeleteBlocks } from "./batchDeleteBlocks.js";
10
+ import { batchMixedOperations } from "./batchMixedOperations.js";
11
+ export const registerBlocksOperationTool = async (params) => {
12
+ switch (params.payload.action) {
13
+ case "append_block_children":
14
+ return appendBlockChildren(params.payload.params);
15
+ case "retrieve_block":
16
+ return retrieveBlock(params.payload.params);
17
+ case "retrieve_block_children":
18
+ return retrieveBlockChildren(params.payload.params);
19
+ case "update_block":
20
+ return updateBlock(params.payload.params);
21
+ case "delete_block":
22
+ return deleteBlock(params.payload.params);
23
+ case "batch_append_block_children":
24
+ return batchAppendBlockChildren(params.payload.params);
25
+ case "batch_update_blocks":
26
+ return batchUpdateBlocks(params.payload.params);
27
+ case "batch_delete_blocks":
28
+ return batchDeleteBlocks(params.payload.params);
29
+ case "batch_mixed_operations":
30
+ return batchMixedOperations(params.payload.params);
31
+ default:
32
+ return handleNotionError(new Error(`Unsupported action, use one of the following: "append_block_children", "retrieve_block", "retrieve_block_children", "update_block", "delete_block", "batch_append_block_children", "batch_update_blocks", "batch_delete_blocks", "batch_mixed_operations"`));
33
+ }
34
+ };
@@ -0,0 +1,81 @@
1
+ import { notion } from "../services/notion.js";
2
+ import { handleNotionError } from "../utils/error.js";
3
+ const registerGetCommentsTool = async (params) => {
4
+ try {
5
+ const response = await notion.comments.list(params);
6
+ return {
7
+ content: [
8
+ {
9
+ type: "text",
10
+ text: `Comments retrieved successfully: ${response.results.length}`,
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
+ };
23
+ const registerAddPageCommentTool = async (params) => {
24
+ try {
25
+ const response = await notion.comments.create(params);
26
+ return {
27
+ content: [
28
+ {
29
+ type: "text",
30
+ text: `Comment created successfully: ${response.id}`,
31
+ },
32
+ {
33
+ type: "text",
34
+ text: JSON.stringify(response, null, 2),
35
+ },
36
+ ],
37
+ };
38
+ }
39
+ catch (error) {
40
+ return handleNotionError(error);
41
+ }
42
+ };
43
+ const registerAddDiscussionCommentTool = async (params) => {
44
+ try {
45
+ const response = await notion.comments.create(params);
46
+ return {
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: `Comment created successfully: ${response.id}`,
51
+ },
52
+ {
53
+ type: "text",
54
+ text: JSON.stringify(response, null, 2),
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ catch (error) {
60
+ return handleNotionError(error);
61
+ }
62
+ };
63
+ // Combined tool function that handles all comment operations
64
+ export const registerCommentsOperationTool = async (params) => {
65
+ try {
66
+ const { payload } = params;
67
+ switch (payload.action) {
68
+ case "get_comments":
69
+ return registerGetCommentsTool(payload.params);
70
+ case "add_page_comment":
71
+ return registerAddPageCommentTool(payload.params);
72
+ case "add_discussion_comment":
73
+ return registerAddDiscussionCommentTool(payload.params);
74
+ default:
75
+ throw new Error(`Unsupported action, use one of the following: "get_comments", "add_page_comment", "add_discussion_comment"`);
76
+ }
77
+ }
78
+ catch (error) {
79
+ return handleNotionError(error);
80
+ }
81
+ };
@@ -0,0 +1,16 @@
1
+ import { handleNotionError } from "../utils/error.js";
2
+ import { createDatabase } from "./createDatabase.js";
3
+ import { queryDatabase } from "./queryDatabase.js";
4
+ import { updateDatabase } from "./updateDatabase.js";
5
+ export const registerDatabaseOperationTool = async (params) => {
6
+ switch (params.payload.action) {
7
+ case "create_database":
8
+ return createDatabase(params.payload.params);
9
+ case "query_database":
10
+ return queryDatabase(params.payload.params);
11
+ case "update_database":
12
+ return updateDatabase(params.payload.params);
13
+ default:
14
+ return handleNotionError(new Error(`Unsupported action, use one of the following: "create_database", "query_database", "update_database"`));
15
+ }
16
+ };
@@ -1,41 +1,23 @@
1
1
  import { server } from "../server/index.js";
2
- import { CREATE_PAGE_SCHEMA, ARCHIVE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, UPDATE_PAGE_PROPERTIES_SCHEMA, } from "../schema/page.js";
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";
5
- import { archivePage, restorePage } from "./updatePage.js";
6
- import { registerCreatePageTool } from "./createPage.js";
7
- import { searchPages } from "./searchPage.js";
8
- import { appendBlockChildren } from "./appendBlockChildren.js";
9
- import { retrieveBlock } from "./retrieveBlock.js";
10
- import { retrieveBlockChildren } from "./retrieveBlockChildren.js";
11
- import { updateBlock } from "./updateBlock.js";
12
- import { deleteBlock } from "./deleteBlock.js";
13
- import { batchAppendBlockChildren } from "./batchAppendBlockChildren.js";
14
- import { batchUpdateBlocks } from "./batchUpdateBlocks.js";
15
- import { batchDeleteBlocks } from "./batchDeleteBlocks.js";
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";
2
+ import { PAGES_OPERATION_SCHEMA } from "../schema/page.js";
3
+ import { BLOCKS_OPERATION_SCHEMA } from "../schema/blocks.js";
4
+ import { DATABASE_OPERATION_SCHEMA } from "../schema/database.js";
5
+ import { COMMENTS_OPERATION_SCHEMA } from "../schema/comments.js";
6
+ import { USERS_OPERATION_SCHEMA } from "../schema/users.js";
7
+ import { registerPagesOperationTool } from "./pages.js";
8
+ import { registerBlocksOperationTool } from "./blocks.js";
9
+ import { registerDatabaseOperationTool } from "./database.js";
10
+ import { registerCommentsOperationTool } from "./comments.js";
11
+ import { registerUsersOperationTool } from "./users.js";
21
12
  export const registerAllTools = () => {
22
- server.tool("create_page", "Create a new page in Notion", CREATE_PAGE_SCHEMA, registerCreatePageTool);
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);
25
- server.tool("restore_page", "Restore a previously archived Notion page", RESTORE_PAGE_SCHEMA, restorePage);
26
- server.tool("search_pages", "Search for pages and databases in Notion by title", SEARCH_PAGES_SCHEMA, searchPages);
27
- server.tool("append_block_children", "Append child blocks to a parent block in Notion", APPEND_BLOCK_CHILDREN_SCHEMA, appendBlockChildren);
28
- server.tool("retrieve_block", "Retrieve a block from Notion by ID", RETRIEVE_BLOCK_SCHEMA, retrieveBlock);
29
- server.tool("retrieve_block_children", "Retrieve the children of a block from Notion", RETRIEVE_BLOCK_CHILDREN_SCHEMA, retrieveBlockChildren);
30
- server.tool("update_block", "Update a block's content in Notion", UPDATE_BLOCK_SCHEMA, updateBlock);
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);
36
- // Register batch operation tools
37
- server.tool("batch_append_block_children", "Append children to multiple blocks in a single operation", BATCH_APPEND_BLOCK_CHILDREN_SCHEMA, batchAppendBlockChildren);
38
- server.tool("batch_update_blocks", "Update multiple blocks in a single operation", BATCH_UPDATE_BLOCKS_SCHEMA, batchUpdateBlocks);
39
- server.tool("batch_delete_blocks", "Delete multiple blocks in a single operation", BATCH_DELETE_BLOCKS_SCHEMA, batchDeleteBlocks);
40
- server.tool("batch_mixed_operations", "Perform a mix of append, update, and delete operations in a single request", BATCH_MIXED_OPERATIONS_SCHEMA, batchMixedOperations);
13
+ // Register combined pages operation tool
14
+ server.tool("notion_pages", "Perform various page operations (create, archive, restore, search, update)", PAGES_OPERATION_SCHEMA, registerPagesOperationTool);
15
+ // Register combined blocks operation tool
16
+ server.tool("notion_blocks", "Perform various block operations (retrieve, update, delete, append children, batch operations)", BLOCKS_OPERATION_SCHEMA, registerBlocksOperationTool);
17
+ // Register combined database operation tool
18
+ server.tool("notion_database", "Perform various database operations (create, query, update)", DATABASE_OPERATION_SCHEMA, registerDatabaseOperationTool);
19
+ // Register combined comments operation tool
20
+ server.tool("notion_comments", "Perform various comment operations (get, add to page, add to discussion)", COMMENTS_OPERATION_SCHEMA, registerCommentsOperationTool);
21
+ // Register combined users operation tool
22
+ server.tool("notion_users", "Perform various user operations (list, get, get bot)", USERS_OPERATION_SCHEMA, registerUsersOperationTool);
41
23
  };
@@ -0,0 +1,22 @@
1
+ import { handleNotionError } from "../utils/error.js";
2
+ import { registerCreatePageTool } from "./createPage.js";
3
+ import { archivePage } from "./updatePage.js";
4
+ import { restorePage } from "./updatePage.js";
5
+ import { searchPages } from "./searchPage.js";
6
+ import { updatePageProperties } from "./updatePageProperties.js";
7
+ export const registerPagesOperationTool = async (params) => {
8
+ switch (params.payload.action) {
9
+ case "create_page":
10
+ return registerCreatePageTool(params.payload.params);
11
+ case "archive_page":
12
+ return archivePage(params.payload.params);
13
+ case "restore_page":
14
+ return restorePage(params.payload.params);
15
+ case "search_pages":
16
+ return searchPages(params.payload.params);
17
+ case "update_page_properties":
18
+ return updatePageProperties(params.payload.params);
19
+ default:
20
+ return handleNotionError(new Error(`Unsupported action, use one of the following: "create_page", "archive_page", "restore_page", "search_pages", "update_page_properties"`));
21
+ }
22
+ };
@@ -4,10 +4,6 @@ export async function searchPages(params) {
4
4
  try {
5
5
  const response = await notion.search({
6
6
  query: params.query || "",
7
- filter: {
8
- value: "page",
9
- property: "object",
10
- },
11
7
  sort: params.sort,
12
8
  start_cursor: params.start_cursor,
13
9
  page_size: params.page_size || 10,
@@ -0,0 +1,75 @@
1
+ import { notion } from "../services/notion.js";
2
+ import { handleNotionError } from "../utils/error.js";
3
+ export const registerGetListUsersTool = async (params) => {
4
+ try {
5
+ const response = await notion.users.list(params);
6
+ return {
7
+ content: [
8
+ {
9
+ type: "text",
10
+ text: `Users retrieved successfully: ${response.results.length}`,
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
+ };
23
+ export const registerGetUserTool = async (params) => {
24
+ try {
25
+ const response = await notion.users.retrieve(params);
26
+ return {
27
+ content: [
28
+ {
29
+ type: "text",
30
+ text: `User retrieved successfully: ${response.id}`,
31
+ },
32
+ {
33
+ type: "text",
34
+ text: JSON.stringify(response, null, 2),
35
+ },
36
+ ],
37
+ };
38
+ }
39
+ catch (error) {
40
+ return handleNotionError(error);
41
+ }
42
+ };
43
+ export const registerGetBotUserTool = async () => {
44
+ try {
45
+ const response = await notion.users.me({});
46
+ return {
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: `Bot user retrieved successfully: ${response.id}`,
51
+ },
52
+ {
53
+ type: "text",
54
+ text: JSON.stringify(response, null, 2),
55
+ },
56
+ ],
57
+ };
58
+ }
59
+ catch (error) {
60
+ return handleNotionError(error);
61
+ }
62
+ };
63
+ // Combined tool function that handles all user operations
64
+ export const registerUsersOperationTool = async (params) => {
65
+ switch (params.payload.action) {
66
+ case "list_users":
67
+ return registerGetListUsersTool(params.payload.params);
68
+ case "get_user":
69
+ return registerGetUserTool(params.payload.params);
70
+ case "get_bot_user":
71
+ return registerGetBotUserTool();
72
+ default:
73
+ return handleNotionError(new Error(`Unsupported action, use one of the following: "list_users", "get_user", "get_bot_user"`));
74
+ }
75
+ };
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- 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";
2
+ 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, BLOCKS_OPERATION_SCHEMA, } from "../schema/blocks.js";
3
3
  export const appendBlockChildrenSchema = z.object(APPEND_BLOCK_CHILDREN_SCHEMA);
4
4
  export const retrieveBlockSchema = z.object(RETRIEVE_BLOCK_SCHEMA);
5
5
  export const retrieveBlockChildrenSchema = z.object(RETRIEVE_BLOCK_CHILDREN_SCHEMA);
@@ -9,3 +9,4 @@ export const batchAppendBlockChildrenSchema = z.object(BATCH_APPEND_BLOCK_CHILDR
9
9
  export const batchUpdateBlocksSchema = z.object(BATCH_UPDATE_BLOCKS_SCHEMA);
10
10
  export const batchDeleteBlocksSchema = z.object(BATCH_DELETE_BLOCKS_SCHEMA);
11
11
  export const batchMixedOperationsSchema = z.object(BATCH_MIXED_OPERATIONS_SCHEMA);
12
+ export const blocksOperationSchema = z.object(BLOCKS_OPERATION_SCHEMA);
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ import { GET_COMMENTS_SCHEMA, ADD_PAGE_COMMENT_SCHEMA, ADD_DISCUSSION_COMMENT_SCHEMA, COMMENTS_OPERATION_SCHEMA, } from "../schema/comments.js";
3
+ // Types inferred from the schemas
4
+ export const getCommentsSchema = z.object(GET_COMMENTS_SCHEMA);
5
+ export const addPageCommentSchema = z.object(ADD_PAGE_COMMENT_SCHEMA);
6
+ export const addDiscussionCommentSchema = z.object(ADD_DISCUSSION_COMMENT_SCHEMA);
7
+ export const commentsOperationSchema = z.object(COMMENTS_OPERATION_SCHEMA);
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
- import { CREATE_DATABASE_SCHEMA, QUERY_DATABASE_SCHEMA, UPDATE_DATABASE_SCHEMA, } from "../schema/database.js";
2
+ import { CREATE_DATABASE_SCHEMA, QUERY_DATABASE_SCHEMA, UPDATE_DATABASE_SCHEMA, DATABASE_OPERATION_SCHEMA, } from "../schema/database.js";
3
3
  export const createDatabaseSchema = z.object(CREATE_DATABASE_SCHEMA);
4
4
  export const queryDatabaseSchema = z.object(QUERY_DATABASE_SCHEMA);
5
5
  export const updateDatabaseSchema = z.object(UPDATE_DATABASE_SCHEMA);
6
+ export const databaseOperationSchema = z.object(DATABASE_OPERATION_SCHEMA);
@@ -1,7 +1,8 @@
1
1
  import { z } from "zod";
2
- import { ARCHIVE_PAGE_SCHEMA, CREATE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, UPDATE_PAGE_PROPERTIES_SCHEMA, } from "../schema/page.js";
2
+ import { ARCHIVE_PAGE_SCHEMA, CREATE_PAGE_SCHEMA, RESTORE_PAGE_SCHEMA, SEARCH_PAGES_SCHEMA, UPDATE_PAGE_PROPERTIES_SCHEMA, PAGES_OPERATION_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
7
  export const updatePagePropertiesSchema = z.object(UPDATE_PAGE_PROPERTIES_SCHEMA);
8
+ export const pagesOperationSchema = z.object(PAGES_OPERATION_SCHEMA);
@@ -0,0 +1,6 @@
1
+ import { z } from "zod";
2
+ import { LIST_USERS_SCHEMA, GET_USER_SCHEMA, USERS_OPERATION_SCHEMA, } from "../schema/users.js";
3
+ // Types inferred from schemas
4
+ const listUsersSchema = z.object(LIST_USERS_SCHEMA);
5
+ const getUserSchema = z.object(GET_USER_SCHEMA);
6
+ const usersOperationSchema = z.object(USERS_OPERATION_SCHEMA);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "notion-mcp-server",
3
- "version": "0.0.2",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "notion-mcp-server": "build/index.js"
@@ -25,7 +25,7 @@
25
25
  "build"
26
26
  ],
27
27
  "dependencies": {
28
- "@modelcontextprotocol/sdk": "^1.7.0",
28
+ "@modelcontextprotocol/sdk": "^1.9.0",
29
29
  "@notionhq/client": "^2.3.0",
30
30
  "zod": "^3.24.2"
31
31
  },