notion-mcp-server 1.0.0 → 2.4.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.
Files changed (95) hide show
  1. package/README.md +383 -192
  2. package/build/config/index.js +3 -1
  3. package/build/dispatch/concurrency.js +15 -0
  4. package/build/dispatch/idempotency.js +38 -0
  5. package/build/dispatch/index.js +175 -0
  6. package/build/dispatch/rate-limit.js +56 -0
  7. package/build/dispatch/retry.js +97 -0
  8. package/build/index.js +1 -1
  9. package/build/markdown/parse.js +265 -0
  10. package/build/operations/blocks.js +331 -0
  11. package/build/operations/comments.js +191 -0
  12. package/build/operations/data-sources.js +85 -0
  13. package/build/operations/databases.js +345 -0
  14. package/build/operations/files.js +239 -0
  15. package/build/operations/index.js +19 -0
  16. package/build/operations/pages.js +486 -0
  17. package/build/operations/registry.js +16 -0
  18. package/build/operations/users.js +101 -0
  19. package/build/prompts/index.js +105 -0
  20. package/build/schema/blocks.js +19 -77
  21. package/build/schema/database.js +27 -86
  22. package/build/schema/emit.js +68 -0
  23. package/build/schema/file.js +1 -1
  24. package/build/schema/filter-dsl.js +333 -0
  25. package/build/schema/icon.js +1 -1
  26. package/build/schema/page-properties.js +17 -3
  27. package/build/schema/page.js +12 -88
  28. package/build/schema/refs.js +16 -0
  29. package/build/schema/rich-text.js +1 -1
  30. package/build/server/index.js +15 -2
  31. package/build/services/auth.js +19 -0
  32. package/build/services/notion.js +14 -17
  33. package/build/tools/index.js +119 -51
  34. package/build/utils/error.js +125 -86
  35. package/build/utils/handler.js +11 -0
  36. package/build/utils/learning-error.js +40 -0
  37. package/build/utils/notion-types.js +16 -0
  38. package/build/utils/paginate.js +35 -0
  39. package/build/utils/schema-slice.js +156 -0
  40. package/build/utils/slim.js +269 -0
  41. package/package.json +13 -7
  42. package/build/resources/imageList.js +0 -62
  43. package/build/resources/index.js +0 -1
  44. package/build/resources/predictionList.js +0 -43
  45. package/build/resources/svgList.js +0 -69
  46. package/build/schema/comments.js +0 -34
  47. package/build/schema/notion.js +0 -57
  48. package/build/schema/richText.js +0 -757
  49. package/build/schema/tools.js +0 -17
  50. package/build/schema/users.js +0 -13
  51. package/build/services/replicate.js +0 -23
  52. package/build/tools/appendBlockChildren.js +0 -25
  53. package/build/tools/batchAppendBlockChildren.js +0 -33
  54. package/build/tools/batchDeleteBlocks.js +0 -32
  55. package/build/tools/batchMixedOperations.js +0 -58
  56. package/build/tools/batchUpdateBlocks.js +0 -33
  57. package/build/tools/comments.js +0 -62
  58. package/build/tools/createDatabase.js +0 -18
  59. package/build/tools/createPage.js +0 -18
  60. package/build/tools/createPrediction.js +0 -28
  61. package/build/tools/deleteBlock.js +0 -24
  62. package/build/tools/formatRichText.js +0 -83
  63. package/build/tools/generateImage.js +0 -48
  64. package/build/tools/generateImageVariants.js +0 -105
  65. package/build/tools/generateMultipleImages.js +0 -60
  66. package/build/tools/generateSVG.js +0 -43
  67. package/build/tools/getPrediction.js +0 -22
  68. package/build/tools/predictionList.js +0 -30
  69. package/build/tools/queryDatabase.js +0 -22
  70. package/build/tools/retrieveBlock.js +0 -24
  71. package/build/tools/retrieveBlockChildren.js +0 -32
  72. package/build/tools/searchPage.js +0 -24
  73. package/build/tools/updateBlock.js +0 -25
  74. package/build/tools/updateDatabase.js +0 -18
  75. package/build/tools/updatePage.js +0 -40
  76. package/build/tools/updatePageProperties.js +0 -21
  77. package/build/tools/users.js +0 -62
  78. package/build/types/blocks.js +0 -11
  79. package/build/types/comments.js +0 -6
  80. package/build/types/database.js +0 -5
  81. package/build/types/notion.js +0 -1
  82. package/build/types/page.js +0 -7
  83. package/build/types/richText.js +0 -1
  84. package/build/types/tools.js +0 -1
  85. package/build/types/users.js +0 -5
  86. package/build/utils/blob.js +0 -5
  87. package/build/utils/image.js +0 -34
  88. package/build/utils/index.js +0 -1
  89. package/build/utils/richText.js +0 -174
  90. package/build/validation/blocks.js +0 -568
  91. package/build/validation/notion.js +0 -51
  92. package/build/validation/page.js +0 -262
  93. package/build/validation/richText.js +0 -744
  94. package/build/validation/tools.js +0 -16
  95. /package/build/{types/index.js → operations/types.js} +0 -0
@@ -1,17 +0,0 @@
1
- // import { z } from "zod";
2
- // import { blockSchema } from "./blocks.js";
3
- // import { parentSchema } from "./page.js";
4
- export {};
5
- // export const createPageSchema = {
6
- // parent: parentSchema,
7
- // properties: z.object({
8
- // title: z.object({
9
- // title: z.array(z.any()), // Rich text array
10
- // }),
11
- // }),
12
- // children: z.array(blockSchema).optional(),
13
- // };
14
- // export const appendBlocksSchema = {
15
- // block_id: z.string(),
16
- // children: z.array(blockSchema),
17
- // };
@@ -1,13 +0,0 @@
1
- import { z } from "zod";
2
- // Schema for listing users with pagination
3
- export const LIST_USERS_SCHEMA = {
4
- start_cursor: z.string().optional().describe("Pagination cursor"),
5
- page_size: z
6
- .number()
7
- .optional()
8
- .describe("Number of users to return per page"),
9
- };
10
- // Schema for getting a single user
11
- export const GET_USER_SCHEMA = {
12
- user_id: z.string().describe("The ID of the user to retrieve"),
13
- };
@@ -1,23 +0,0 @@
1
- import Replicate from "replicate";
2
- import { CONFIG } from "../config/index.js";
3
- export function getReplicateApiToken() {
4
- const token = process.env.REPLICATE_API_TOKEN;
5
- if (!token) {
6
- console.error("Error: REPLICATE_API_TOKEN environment variable is required");
7
- process.exit(1);
8
- }
9
- return token;
10
- }
11
- export const replicate = new Replicate({
12
- auth: getReplicateApiToken(),
13
- });
14
- export async function pollForCompletion(predictionId) {
15
- for (let i = 0; i < CONFIG.pollingAttempts; i++) {
16
- const latest = await replicate.predictions.get(predictionId);
17
- if (latest.status !== "starting" && latest.status !== "processing") {
18
- return latest;
19
- }
20
- await new Promise((resolve) => setTimeout(resolve, CONFIG.pollingInterval));
21
- }
22
- return null;
23
- }
@@ -1,25 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const appendBlockChildren = async (params) => {
4
- try {
5
- const response = await notion.blocks.children.append({
6
- block_id: params.blockId,
7
- children: params.children,
8
- });
9
- return {
10
- content: [
11
- {
12
- type: "text",
13
- text: `Successfully appended ${params.children.length} block(s) to ${params.blockId}`,
14
- },
15
- {
16
- type: "text",
17
- text: `Block ID: ${JSON.stringify(response, null, 2)}`,
18
- },
19
- ],
20
- };
21
- }
22
- catch (error) {
23
- return handleNotionError(error);
24
- }
25
- };
@@ -1,33 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const batchAppendBlockChildren = async (params) => {
4
- try {
5
- const results = [];
6
- for (const operation of params.operations) {
7
- const response = await notion.blocks.children.append({
8
- block_id: operation.blockId,
9
- children: operation.children,
10
- });
11
- results.push({
12
- blockId: operation.blockId,
13
- success: true,
14
- response,
15
- });
16
- }
17
- return {
18
- content: [
19
- {
20
- type: "text",
21
- text: `Successfully completed ${params.operations.length} append operations`,
22
- },
23
- {
24
- type: "text",
25
- text: JSON.stringify(results, null, 2),
26
- },
27
- ],
28
- };
29
- }
30
- catch (error) {
31
- return handleNotionError(error);
32
- }
33
- };
@@ -1,32 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const batchDeleteBlocks = async (params) => {
4
- try {
5
- const results = [];
6
- for (const blockId of params.blockIds) {
7
- const response = await notion.blocks.delete({
8
- block_id: blockId,
9
- });
10
- results.push({
11
- blockId,
12
- success: true,
13
- response,
14
- });
15
- }
16
- return {
17
- content: [
18
- {
19
- type: "text",
20
- text: `Successfully deleted ${params.blockIds.length} blocks (moved to trash)`,
21
- },
22
- {
23
- type: "text",
24
- text: JSON.stringify(results, null, 2),
25
- },
26
- ],
27
- };
28
- }
29
- catch (error) {
30
- return handleNotionError(error);
31
- }
32
- };
@@ -1,58 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const batchMixedOperations = async (params) => {
4
- try {
5
- const results = [];
6
- const operationCounts = {
7
- append: 0,
8
- update: 0,
9
- delete: 0,
10
- };
11
- for (const op of params.operations) {
12
- let response;
13
- switch (op.operation) {
14
- case "append":
15
- response = await notion.blocks.children.append({
16
- block_id: op.blockId,
17
- children: op.children,
18
- });
19
- operationCounts.append++;
20
- break;
21
- case "update":
22
- response = await notion.blocks.update({
23
- block_id: op.blockId,
24
- ...op.data,
25
- });
26
- operationCounts.update++;
27
- break;
28
- case "delete":
29
- response = await notion.blocks.delete({
30
- block_id: op.blockId,
31
- });
32
- operationCounts.delete++;
33
- break;
34
- }
35
- results.push({
36
- operation: op.operation,
37
- blockId: op.blockId,
38
- success: true,
39
- response,
40
- });
41
- }
42
- return {
43
- content: [
44
- {
45
- type: "text",
46
- text: `Successfully performed ${params.operations.length} operations (${operationCounts.append} append, ${operationCounts.update} update, ${operationCounts.delete} delete)`,
47
- },
48
- {
49
- type: "text",
50
- text: JSON.stringify(results, null, 2),
51
- },
52
- ],
53
- };
54
- }
55
- catch (error) {
56
- return handleNotionError(error);
57
- }
58
- };
@@ -1,33 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const batchUpdateBlocks = async (params) => {
4
- try {
5
- const results = [];
6
- for (const operation of params.operations) {
7
- const response = await notion.blocks.update({
8
- block_id: operation.blockId,
9
- ...operation.data,
10
- });
11
- results.push({
12
- blockId: operation.blockId,
13
- success: true,
14
- response,
15
- });
16
- }
17
- return {
18
- content: [
19
- {
20
- type: "text",
21
- text: `Successfully updated ${params.operations.length} blocks`,
22
- },
23
- {
24
- type: "text",
25
- text: JSON.stringify(results, null, 2),
26
- },
27
- ],
28
- };
29
- }
30
- catch (error) {
31
- return handleNotionError(error);
32
- }
33
- };
@@ -1,62 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export 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
- export 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
- export 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
- };
@@ -1,18 +0,0 @@
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
- };
@@ -1,18 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const registerCreatePageTool = async (params) => {
4
- try {
5
- const response = await notion.pages.create(params);
6
- return {
7
- content: [
8
- {
9
- type: "text",
10
- text: `Page created successfully: ${response.id}`,
11
- },
12
- ],
13
- };
14
- }
15
- catch (error) {
16
- return handleNotionError(error);
17
- }
18
- };
@@ -1,28 +0,0 @@
1
- // import { CreatePredictionParams } from "../types/index.js";
2
- // import { pollForCompletion, replicate } from "../services/replicate.js";
3
- // import { handleError } from "../utils/error.js";
4
- // import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
5
- // import { CONFIG } from "../config/index.js";
6
- export {};
7
- // export const registerCreatePredictionTool = async (
8
- // input: CreatePredictionParams
9
- // ): Promise<CallToolResult> => {
10
- // try {
11
- // const prediction = await replicate.predictions.create({
12
- // model: CONFIG.imageModelId,
13
- // input,
14
- // });
15
- // await replicate.predictions.get(prediction.id);
16
- // const completed = await pollForCompletion(prediction.id);
17
- // return {
18
- // content: [
19
- // {
20
- // type: "text",
21
- // text: JSON.stringify(completed || "Processing timed out", null, 2),
22
- // },
23
- // ],
24
- // };
25
- // } catch (error) {
26
- // handleError(error);
27
- // }
28
- // };
@@ -1,24 +0,0 @@
1
- import { notion } from "../services/notion.js";
2
- import { handleNotionError } from "../utils/error.js";
3
- export const deleteBlock = async (params) => {
4
- try {
5
- const response = await notion.blocks.delete({
6
- block_id: params.blockId,
7
- });
8
- return {
9
- content: [
10
- {
11
- type: "text",
12
- text: `Block ${params.blockId} deleted (moved to trash) successfully`,
13
- },
14
- {
15
- type: "text",
16
- text: JSON.stringify(response, null, 2),
17
- },
18
- ],
19
- };
20
- }
21
- catch (error) {
22
- return handleNotionError(error);
23
- }
24
- };
@@ -1,83 +0,0 @@
1
- import { z } from "zod";
2
- import { handleError } from "../utils/error.js";
3
- import { boldText, italicText, codeText, colorText, createTextRichText, } from "../utils/richText.js";
4
- // Schema for the formatRichText tool as a record of ZodTypes
5
- export const formatRichTextSchema = {
6
- text: z.string().describe("Text content to format"),
7
- include_bold: z
8
- .boolean()
9
- .optional()
10
- .describe("Whether to include bold formatting"),
11
- include_italic: z
12
- .boolean()
13
- .optional()
14
- .describe("Whether to include italic formatting"),
15
- include_code: z
16
- .boolean()
17
- .optional()
18
- .describe("Whether to include code formatting"),
19
- include_color: z
20
- .boolean()
21
- .optional()
22
- .describe("Whether to include color formatting"),
23
- include_link: z.boolean().optional().describe("Whether to include a link"),
24
- link_url: z
25
- .string()
26
- .url()
27
- .optional()
28
- .describe("URL to link to if include_link is true"),
29
- color: z
30
- .string()
31
- .optional()
32
- .describe("Color to use if include_color is true"),
33
- };
34
- // Object schema for type inference
35
- const formatRichTextObjectSchema = z.object(formatRichTextSchema);
36
- /**
37
- * Tool that demonstrates rich text formatting in Notion
38
- * @param params The parameters for formatting rich text
39
- * @returns A formatted JSON representation of the rich text
40
- */
41
- export const registerFormatRichTextTool = async (params) => {
42
- try {
43
- const { text, include_bold = false, include_italic = false, include_code = false, include_color = false, include_link = false, link_url = "https://example.com", color = "blue", } = params;
44
- // Split the text into parts to demonstrate formatting each part differently
45
- const parts = text.split(" ");
46
- const formattedParts = [];
47
- // Format each part based on the parameters
48
- for (let i = 0; i < parts.length; i++) {
49
- const part = parts[i];
50
- if (i % 5 === 0 && include_bold) {
51
- formattedParts.push(boldText(part + " "));
52
- }
53
- else if (i % 5 === 1 && include_italic) {
54
- formattedParts.push(italicText(part + " "));
55
- }
56
- else if (i % 5 === 2 && include_code) {
57
- formattedParts.push(codeText(part + " "));
58
- }
59
- else if (i % 5 === 3 && include_color) {
60
- formattedParts.push(colorText(part + " ", color));
61
- }
62
- else if (i % 5 === 4 && include_link) {
63
- formattedParts.push(createTextRichText(part + " ", undefined, link_url));
64
- }
65
- else {
66
- formattedParts.push(createTextRichText(part + " "));
67
- }
68
- }
69
- // The resulting rich text array
70
- const richText = formattedParts;
71
- return {
72
- content: [
73
- {
74
- type: "text",
75
- text: JSON.stringify(richText, null, 2),
76
- },
77
- ],
78
- };
79
- }
80
- catch (error) {
81
- return handleError(error);
82
- }
83
- };
@@ -1,48 +0,0 @@
1
- import { replicate } from "../services/replicate.js";
2
- import { handleError } from "../utils/error.js";
3
- import { outputToBase64 } from "../utils/image.js";
4
- import { CONFIG } from "../config/index.js";
5
- export const registerGenerateImageTool = async (input) => {
6
- const { support_image_mcp_response_type, ...predictionInput } = input;
7
- try {
8
- const [output] = (await replicate.run(CONFIG.imageModelId, {
9
- input: predictionInput,
10
- }));
11
- const imageUrl = output.url();
12
- if (support_image_mcp_response_type) {
13
- const imageBase64 = await outputToBase64(output);
14
- return {
15
- content: [
16
- {
17
- type: "text",
18
- text: `This is a generated image link: ${imageUrl}`,
19
- },
20
- {
21
- type: "image",
22
- data: imageBase64,
23
- mimeType: "image/png",
24
- },
25
- {
26
- type: "text",
27
- text: `The image above is generated by the Flux model and prompt: ${input.prompt}`,
28
- },
29
- ],
30
- };
31
- }
32
- return {
33
- content: [
34
- {
35
- type: "text",
36
- text: `This is a generated image link: ${imageUrl}`,
37
- },
38
- {
39
- type: "text",
40
- text: `The image above is generated by the Flux model and prompt: ${input.prompt}`,
41
- },
42
- ],
43
- };
44
- }
45
- catch (error) {
46
- handleError(error);
47
- }
48
- };
@@ -1,105 +0,0 @@
1
- import { replicate } from "../services/replicate.js";
2
- import { handleError } from "../utils/error.js";
3
- import { outputToBase64 } from "../utils/image.js";
4
- import { CONFIG } from "../config/index.js";
5
- export const registerGenerateImageVariantsTool = async (input) => {
6
- const { prompt, num_variants, seed, support_image_mcp_response_type, prompt_variations, variation_mode, ...commonParams } = input;
7
- try {
8
- let effectiveVariants = num_variants;
9
- let usingPromptVariations = false;
10
- // Decide if we're using prompt variations
11
- if (prompt_variations && prompt_variations.length > 0) {
12
- usingPromptVariations = true;
13
- // If using prompt variations, number of variants is limited by available variations
14
- effectiveVariants = Math.min(num_variants, prompt_variations.length);
15
- }
16
- // Process all variants in parallel
17
- const generationPromises = Array.from({ length: effectiveVariants }, (_, index) => {
18
- // If seed is provided, create deterministic variants by adding the index
19
- const variantSeed = seed !== undefined ? seed + index : undefined;
20
- // Determine which prompt to use for this variant
21
- let variantPrompt = prompt;
22
- if (usingPromptVariations) {
23
- const variation = prompt_variations[index];
24
- if (variation_mode === "append") {
25
- variantPrompt = `${prompt} ${variation}`;
26
- }
27
- else {
28
- // 'replace' mode
29
- variantPrompt = variation;
30
- }
31
- }
32
- return replicate
33
- .run(CONFIG.imageModelId, {
34
- input: {
35
- prompt: variantPrompt,
36
- seed: variantSeed,
37
- ...commonParams,
38
- },
39
- })
40
- .then((outputs) => {
41
- const [output] = outputs;
42
- const imageUrl = output.url();
43
- if (support_image_mcp_response_type) {
44
- return outputToBase64(output).then((imageBase64) => ({
45
- variantIndex: index + 1,
46
- imageUrl,
47
- imageBase64,
48
- usedPrompt: variantPrompt,
49
- }));
50
- }
51
- return {
52
- variantIndex: index + 1,
53
- imageUrl,
54
- usedPrompt: variantPrompt,
55
- };
56
- });
57
- });
58
- // Wait for all variant generation to complete
59
- const results = (await Promise.all(generationPromises));
60
- // Build response content
61
- const responseContent = [];
62
- // Add intro text - different based on whether we're using prompt variations
63
- if (usingPromptVariations) {
64
- responseContent.push({
65
- type: "text",
66
- text: `Generated ${results.length} variants of "${prompt}" using custom prompt variations (${variation_mode} mode)`,
67
- });
68
- }
69
- else {
70
- responseContent.push({
71
- type: "text",
72
- text: `Generated ${results.length} variants of: "${prompt}" using seed variations`,
73
- });
74
- }
75
- // Add each variant with its index and prompt info
76
- for (const result of results) {
77
- // Build an appropriate description based on variant type
78
- let variantDescription = `Variant #${result.variantIndex}`;
79
- if (usingPromptVariations) {
80
- variantDescription += `\nPrompt: "${result.usedPrompt}"`;
81
- }
82
- else if (seed !== undefined) {
83
- variantDescription += ` (seed: ${seed + (result.variantIndex - 1)})`;
84
- }
85
- variantDescription += `\nImage URL: ${result.imageUrl}`;
86
- responseContent.push({
87
- type: "text",
88
- text: `\n\n${variantDescription}`,
89
- });
90
- if (support_image_mcp_response_type && result.imageBase64) {
91
- responseContent.push({
92
- type: "image",
93
- data: result.imageBase64,
94
- mimeType: `image/${input.output_format === "jpg" ? "jpeg" : input.output_format}`,
95
- });
96
- }
97
- }
98
- return {
99
- content: responseContent,
100
- };
101
- }
102
- catch (error) {
103
- handleError(error);
104
- }
105
- };