@atikk-co-jp/notion-mcp-server 0.1.0 → 0.2.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.
Files changed (97) hide show
  1. package/README.ja.md +95 -4
  2. package/README.md +95 -4
  3. package/dist/bin/cli.js +10 -10
  4. package/dist/src/converters/__tests__/block-to-markdown.test.d.ts +2 -0
  5. package/dist/src/converters/__tests__/block-to-markdown.test.d.ts.map +1 -0
  6. package/dist/src/converters/__tests__/block-to-markdown.test.js +611 -0
  7. package/dist/src/converters/__tests__/page-to-markdown.test.d.ts +2 -0
  8. package/dist/src/converters/__tests__/page-to-markdown.test.d.ts.map +1 -0
  9. package/dist/src/converters/__tests__/page-to-markdown.test.js +567 -0
  10. package/dist/src/converters/__tests__/rich-text-to-markdown.test.d.ts +2 -0
  11. package/dist/src/converters/__tests__/rich-text-to-markdown.test.d.ts.map +1 -0
  12. package/dist/src/converters/__tests__/rich-text-to-markdown.test.js +353 -0
  13. package/dist/src/converters/block-to-markdown.d.ts +38 -0
  14. package/dist/src/converters/block-to-markdown.d.ts.map +1 -0
  15. package/dist/src/converters/block-to-markdown.js +484 -0
  16. package/dist/src/converters/index.d.ts +9 -0
  17. package/dist/src/converters/index.d.ts.map +1 -0
  18. package/dist/src/converters/index.js +11 -0
  19. package/dist/src/converters/page-to-markdown.d.ts +64 -0
  20. package/dist/src/converters/page-to-markdown.d.ts.map +1 -0
  21. package/dist/src/converters/page-to-markdown.js +189 -0
  22. package/dist/src/converters/rich-text-to-markdown.d.ts +61 -0
  23. package/dist/src/converters/rich-text-to-markdown.d.ts.map +1 -0
  24. package/dist/src/converters/rich-text-to-markdown.js +95 -0
  25. package/dist/src/index.d.ts +6 -6
  26. package/dist/src/index.d.ts.map +1 -1
  27. package/dist/src/index.js +5 -5
  28. package/dist/src/notion-client.d.ts +58 -15
  29. package/dist/src/notion-client.d.ts.map +1 -1
  30. package/dist/src/notion-client.js +23 -13
  31. package/dist/src/schemas/block.d.ts +2158 -622
  32. package/dist/src/schemas/block.d.ts.map +1 -1
  33. package/dist/src/schemas/block.js +283 -76
  34. package/dist/src/schemas/common.d.ts +518 -6
  35. package/dist/src/schemas/common.d.ts.map +1 -1
  36. package/dist/src/schemas/common.js +120 -42
  37. package/dist/src/schemas/database.d.ts +687 -0
  38. package/dist/src/schemas/database.d.ts.map +1 -0
  39. package/dist/src/schemas/database.js +264 -0
  40. package/dist/src/schemas/filter.d.ts +509 -3
  41. package/dist/src/schemas/filter.d.ts.map +1 -1
  42. package/dist/src/schemas/filter.js +110 -13
  43. package/dist/src/schemas/index.d.ts +5 -4
  44. package/dist/src/schemas/index.d.ts.map +1 -1
  45. package/dist/src/schemas/index.js +7 -5
  46. package/dist/src/schemas/page.d.ts +2152 -19
  47. package/dist/src/schemas/page.d.ts.map +1 -1
  48. package/dist/src/schemas/page.js +216 -22
  49. package/dist/src/schemas/schemas.test.d.ts +2 -0
  50. package/dist/src/schemas/schemas.test.d.ts.map +1 -0
  51. package/dist/src/schemas/schemas.test.js +418 -0
  52. package/dist/src/server.d.ts +2 -2
  53. package/dist/src/server.d.ts.map +1 -1
  54. package/dist/src/server.js +6 -6
  55. package/dist/src/tools/append-block-children.d.ts +2 -2
  56. package/dist/src/tools/append-block-children.d.ts.map +1 -1
  57. package/dist/src/tools/append-block-children.js +16 -10
  58. package/dist/src/tools/create-comment.d.ts +2 -2
  59. package/dist/src/tools/create-comment.d.ts.map +1 -1
  60. package/dist/src/tools/create-comment.js +15 -9
  61. package/dist/src/tools/create-database.d.ts +4 -0
  62. package/dist/src/tools/create-database.d.ts.map +1 -0
  63. package/dist/src/tools/create-database.js +57 -0
  64. package/dist/src/tools/create-page.d.ts +2 -2
  65. package/dist/src/tools/create-page.d.ts.map +1 -1
  66. package/dist/src/tools/create-page.js +22 -24
  67. package/dist/src/tools/get-block-children.d.ts +2 -2
  68. package/dist/src/tools/get-block-children.d.ts.map +1 -1
  69. package/dist/src/tools/get-block-children.js +39 -6
  70. package/dist/src/tools/index.d.ts +13 -11
  71. package/dist/src/tools/index.d.ts.map +1 -1
  72. package/dist/src/tools/index.js +13 -9
  73. package/dist/src/tools/query-database.d.ts +2 -2
  74. package/dist/src/tools/query-database.d.ts.map +1 -1
  75. package/dist/src/tools/query-database.js +27 -18
  76. package/dist/src/tools/retrieve-page.d.ts +2 -2
  77. package/dist/src/tools/retrieve-page.d.ts.map +1 -1
  78. package/dist/src/tools/retrieve-page.js +44 -4
  79. package/dist/src/tools/search.d.ts +2 -2
  80. package/dist/src/tools/search.d.ts.map +1 -1
  81. package/dist/src/tools/search.js +18 -12
  82. package/dist/src/tools/update-database.d.ts +4 -0
  83. package/dist/src/tools/update-database.d.ts.map +1 -0
  84. package/dist/src/tools/update-database.js +74 -0
  85. package/dist/src/tools/update-page.d.ts +2 -2
  86. package/dist/src/tools/update-page.d.ts.map +1 -1
  87. package/dist/src/tools/update-page.js +23 -18
  88. package/dist/src/utils/error-handler.d.ts +1 -1
  89. package/dist/src/utils/error-handler.d.ts.map +1 -1
  90. package/dist/src/utils/error-handler.js +14 -14
  91. package/dist/src/utils/index.d.ts +2 -2
  92. package/dist/src/utils/index.d.ts.map +1 -1
  93. package/dist/src/utils/index.js +2 -2
  94. package/dist/src/utils/response-formatter.d.ts +13 -1
  95. package/dist/src/utils/response-formatter.d.ts.map +1 -1
  96. package/dist/src/utils/response-formatter.js +46 -3
  97. package/package.json +11 -2
@@ -1,35 +1,33 @@
1
- import { z } from "zod";
2
- import { formatResponse, handleError } from "../utils/index.js";
1
+ import { z } from 'zod';
2
+ import { BlockChildrenSchema } from '../schemas/block.js';
3
+ import { CoverSchema, IconSchema } from '../schemas/common.js';
4
+ import { PropertiesSchema } from '../schemas/page.js';
5
+ import { formatResponse, handleError } from '../utils/index.js';
3
6
  const inputSchema = {
4
- database_id: z.string().describe("The ID of the database where the page will be created"),
5
- properties: z
6
- .record(z.string(), z.any())
7
- .describe("Page properties as a JSON object. Keys are property names, values are property values. " +
8
- 'Example: { "Name": { "title": [{ "text": { "content": "My Page" } }] }, ' +
9
- '"Status": { "status": { "name": "In Progress" } } }'),
10
- children: z
11
- .array(z.any())
12
- .optional()
13
- .describe("Optional array of block objects for the page content. " +
7
+ database_id: z.string().describe('The ID of the database where the page will be created'),
8
+ properties: PropertiesSchema.describe('Page properties object. Keys are property names, values follow Notion property format. ' +
9
+ 'Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, relation, people, files. ' +
10
+ 'Example: { "Name": { "title": [{ "text": { "content": "My Page" } }] }, "Status": { "status": { "name": "In Progress" } } }'),
11
+ children: BlockChildrenSchema.optional().describe('Optional array of block objects for the page content. ' +
12
+ 'Supported types: paragraph, heading_1/2/3, bulleted_list_item, numbered_list_item, to_do, toggle, code, quote, callout, divider, bookmark, image, video, embed, table_of_contents. ' +
14
13
  'Example: [{ "type": "paragraph", "paragraph": { "rich_text": [{ "text": { "content": "Hello" } }] } }]'),
15
- icon: z
16
- .any()
17
- .optional()
18
- .describe("Optional icon for the page. " +
19
- 'Emoji example: { "type": "emoji", "emoji": "🚀" }. ' +
20
- 'External example: { "type": "external", "external": { "url": "https://..." } }'),
21
- cover: z
22
- .any()
23
- .optional()
24
- .describe("Optional cover image for the page. " +
14
+ icon: IconSchema.optional().describe('Optional icon for the page. ' +
15
+ 'Emoji: { "type": "emoji", "emoji": "🚀" }. ' +
16
+ 'External: { "type": "external", "external": { "url": "https://..." } }'),
17
+ cover: CoverSchema.optional().describe('Optional cover image for the page. ' +
25
18
  'Example: { "type": "external", "external": { "url": "https://..." } }'),
26
19
  };
27
20
  export function registerCreatePage(server, notion) {
28
- server.tool("create-page", "Create a new page in a Notion database. Requires a database_id and properties object.", inputSchema, async ({ database_id, properties, children, icon, cover }) => {
21
+ server.registerTool('create-page', {
22
+ description: 'Create a new page in a Notion database. Requires a database_id and properties object. ' +
23
+ 'Optionally include initial content blocks, icon, and cover image. ' +
24
+ 'Returns the created page with its ID and URL.',
25
+ inputSchema,
26
+ }, async ({ database_id, properties, children, icon, cover }) => {
29
27
  try {
30
28
  const params = {
31
29
  parent: { database_id },
32
- properties,
30
+ properties: properties,
33
31
  };
34
32
  if (children) {
35
33
  params.children = children;
@@ -1,4 +1,4 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { NotionClient } from "../notion-client.js";
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
3
  export declare function registerGetBlockChildren(server: McpServer, notion: NotionClient): void;
4
4
  //# sourceMappingURL=get-block-children.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-block-children.d.ts","sourceRoot":"","sources":["../../../src/tools/get-block-children.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAuBxD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAkBtF"}
1
+ {"version":3,"file":"get-block-children.d.ts","sourceRoot":"","sources":["../../../src/tools/get-block-children.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAqCvD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA2CtF"}
@@ -1,26 +1,59 @@
1
- import { z } from "zod";
2
- import { formatPaginatedResponse, handleError } from "../utils/index.js";
1
+ import { z } from 'zod';
2
+ import { blocksToMarkdown, blocksToMarkdownSync } from '../converters/index.js';
3
+ import { formatMarkdownResponse, formatPaginatedResponse, handleError } from '../utils/index.js';
3
4
  const inputSchema = {
4
- block_id: z.string().describe("The ID of the block or page to get children from"),
5
+ block_id: z.string().describe('The ID of the block or page to get children from'),
5
6
  start_cursor: z
6
7
  .string()
7
8
  .optional()
8
- .describe("Cursor for pagination. Use the next_cursor from previous response."),
9
+ .describe('Cursor for pagination. Use the next_cursor from previous response.'),
9
10
  page_size: z
10
11
  .number()
11
12
  .min(1)
12
13
  .max(100)
13
14
  .optional()
14
- .describe("Number of results to return (1-100). Default is 100."),
15
+ .describe('Number of results to return (1-100). Default is 100.'),
16
+ format: z
17
+ .enum(['json', 'markdown'])
18
+ .optional()
19
+ .default('markdown')
20
+ .describe("Output format: 'markdown' (default) returns human-readable text with significantly reduced token usage, 'json' returns raw Notion API response"),
21
+ fetch_nested: z
22
+ .boolean()
23
+ .optional()
24
+ .default(false)
25
+ .describe("When format='markdown', fetch nested children blocks recursively (toggle, list items with children, etc.). Default is false."),
15
26
  };
16
27
  export function registerGetBlockChildren(server, notion) {
17
- server.tool("get-block-children", "Retrieve the children blocks of a block or page. Returns paginated results.", inputSchema, async ({ block_id, start_cursor, page_size }) => {
28
+ server.registerTool('get-block-children', {
29
+ description: "Retrieve the children blocks of a block or page. Returns paginated results. Use format='markdown' (default) for human-readable output with significantly reduced token usage.",
30
+ inputSchema,
31
+ }, async ({ block_id, start_cursor, page_size, format, fetch_nested }) => {
18
32
  try {
19
33
  const response = await notion.blocks.children.list({
20
34
  block_id,
21
35
  start_cursor,
22
36
  page_size,
23
37
  });
38
+ if (format === 'markdown') {
39
+ let markdown;
40
+ if (fetch_nested) {
41
+ // 子ブロックを再帰的に取得
42
+ const fetchChildren = async (blockId) => {
43
+ const res = await notion.blocks.children.list({
44
+ block_id: blockId,
45
+ });
46
+ return res.results;
47
+ };
48
+ markdown = await blocksToMarkdown(response.results, { fetchChildren });
49
+ }
50
+ else {
51
+ // 子ブロック取得なし(同期版)
52
+ markdown = blocksToMarkdownSync(response.results);
53
+ }
54
+ return formatMarkdownResponse(markdown, response.has_more, response.next_cursor);
55
+ }
56
+ // JSON形式
24
57
  return formatPaginatedResponse(response.results, response.has_more, response.next_cursor);
25
58
  }
26
59
  catch (error) {
@@ -1,13 +1,15 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { NotionClient } from "../notion-client.js";
3
- import { registerAppendBlockChildren } from "./append-block-children.js";
4
- import { registerCreateComment } from "./create-comment.js";
5
- import { registerCreatePage } from "./create-page.js";
6
- import { registerGetBlockChildren } from "./get-block-children.js";
7
- import { registerQueryDatabase } from "./query-database.js";
8
- import { registerRetrievePage } from "./retrieve-page.js";
9
- import { registerSearch } from "./search.js";
10
- import { registerUpdatePage } from "./update-page.js";
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
+ import { registerAppendBlockChildren } from './append-block-children.js';
4
+ import { registerCreateComment } from './create-comment.js';
5
+ import { registerCreateDatabase } from './create-database.js';
6
+ import { registerCreatePage } from './create-page.js';
7
+ import { registerGetBlockChildren } from './get-block-children.js';
8
+ import { registerQueryDatabase } from './query-database.js';
9
+ import { registerRetrievePage } from './retrieve-page.js';
10
+ import { registerSearch } from './search.js';
11
+ import { registerUpdateDatabase } from './update-database.js';
12
+ import { registerUpdatePage } from './update-page.js';
11
13
  export declare function registerAllTools(server: McpServer, notion: NotionClient): void;
12
- export { registerRetrievePage, registerCreatePage, registerUpdatePage, registerQueryDatabase, registerSearch, registerGetBlockChildren, registerAppendBlockChildren, registerCreateComment, };
14
+ export { registerRetrievePage, registerCreatePage, registerUpdatePage, registerCreateDatabase, registerUpdateDatabase, registerQueryDatabase, registerSearch, registerGetBlockChildren, registerAppendBlockChildren, registerCreateComment, };
13
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAkB9E;AAED,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,2BAA2B,EAC3B,qBAAqB,GACtB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAA;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAoB9E;AAED,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,2BAA2B,EAC3B,qBAAqB,GACtB,CAAA"}
@@ -1,17 +1,21 @@
1
- import { registerAppendBlockChildren } from "./append-block-children.js";
2
- import { registerCreateComment } from "./create-comment.js";
3
- import { registerCreatePage } from "./create-page.js";
4
- import { registerGetBlockChildren } from "./get-block-children.js";
5
- import { registerQueryDatabase } from "./query-database.js";
6
- import { registerRetrievePage } from "./retrieve-page.js";
7
- import { registerSearch } from "./search.js";
8
- import { registerUpdatePage } from "./update-page.js";
1
+ import { registerAppendBlockChildren } from './append-block-children.js';
2
+ import { registerCreateComment } from './create-comment.js';
3
+ import { registerCreateDatabase } from './create-database.js';
4
+ import { registerCreatePage } from './create-page.js';
5
+ import { registerGetBlockChildren } from './get-block-children.js';
6
+ import { registerQueryDatabase } from './query-database.js';
7
+ import { registerRetrievePage } from './retrieve-page.js';
8
+ import { registerSearch } from './search.js';
9
+ import { registerUpdateDatabase } from './update-database.js';
10
+ import { registerUpdatePage } from './update-page.js';
9
11
  export function registerAllTools(server, notion) {
10
12
  // Page operations
11
13
  registerRetrievePage(server, notion);
12
14
  registerCreatePage(server, notion);
13
15
  registerUpdatePage(server, notion);
14
16
  // Database operations
17
+ registerCreateDatabase(server, notion);
18
+ registerUpdateDatabase(server, notion);
15
19
  registerQueryDatabase(server, notion);
16
20
  // Search
17
21
  registerSearch(server, notion);
@@ -21,4 +25,4 @@ export function registerAllTools(server, notion) {
21
25
  // Comment operations
22
26
  registerCreateComment(server, notion);
23
27
  }
24
- export { registerRetrievePage, registerCreatePage, registerUpdatePage, registerQueryDatabase, registerSearch, registerGetBlockChildren, registerAppendBlockChildren, registerCreateComment, };
28
+ export { registerRetrievePage, registerCreatePage, registerUpdatePage, registerCreateDatabase, registerUpdateDatabase, registerQueryDatabase, registerSearch, registerGetBlockChildren, registerAppendBlockChildren, registerCreateComment, };
@@ -1,4 +1,4 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { NotionClient } from "../notion-client.js";
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
3
  export declare function registerQueryDatabase(server: McpServer, notion: NotionClient): void;
4
4
  //# sourceMappingURL=query-database.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-database.d.ts","sourceRoot":"","sources":["../../../src/tools/query-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAuCxD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAsCnF"}
1
+ {"version":3,"file":"query-database.d.ts","sourceRoot":"","sources":["../../../src/tools/query-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAwDvD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA+CnF"}
@@ -1,32 +1,37 @@
1
- import { z } from "zod";
2
- import { formatPaginatedResponse, handleError } from "../utils/index.js";
1
+ import { z } from 'zod';
2
+ import { pagesToSimple } from '../converters/index.js';
3
+ import { FilterSchema, SortsSchema } from '../schemas/filter.js';
4
+ import { formatPaginatedResponse, formatSimplePaginatedResponse, handleError, } from '../utils/index.js';
3
5
  const inputSchema = {
4
- database_id: z.string().describe("The ID of the database to query"),
5
- filter: z
6
- .any()
7
- .optional()
8
- .describe("Filter conditions as a JSON object. " +
9
- 'Property filter example: { "property": "Status", "status": { "equals": "Done" } }. ' +
10
- 'Compound filter example: { "and": [{ "property": "Status", "status": { "equals": "Done" } }] }'),
11
- sorts: z
12
- .array(z.any())
13
- .optional()
14
- .describe("Sort conditions as an array. " +
15
- 'Example: [{ "property": "Created", "direction": "descending" }] or ' +
16
- '[{ "timestamp": "created_time", "direction": "ascending" }]'),
6
+ database_id: z.string().describe('The ID of the database to query'),
7
+ filter: FilterSchema.optional().describe('Filter conditions. ' +
8
+ 'Property filter: { "property": "Status", "status": { "equals": "Done" } }. ' +
9
+ 'Compound filter: { "and": [...] } or { "or": [...] }. ' +
10
+ 'Supported property types: title, rich_text, number, checkbox, select, multi_select, status, date, relation.'),
11
+ sorts: SortsSchema.optional().describe('Sort conditions array. ' +
12
+ 'By property: { "property": "Name", "direction": "ascending" }. ' +
13
+ 'By timestamp: { "timestamp": "created_time", "direction": "descending" }.'),
17
14
  start_cursor: z
18
15
  .string()
19
16
  .optional()
20
- .describe("Cursor for pagination. Use the next_cursor from previous response."),
17
+ .describe('Cursor for pagination. Use the next_cursor from previous response.'),
21
18
  page_size: z
22
19
  .number()
23
20
  .min(1)
24
21
  .max(100)
25
22
  .optional()
26
- .describe("Number of results to return (1-100). Default is 100."),
23
+ .describe('Number of results to return (1-100). Default is 100.'),
24
+ format: z
25
+ .enum(['json', 'simple'])
26
+ .optional()
27
+ .default('simple')
28
+ .describe("Output format: 'simple' (default) returns simplified property values with reduced token usage, 'json' returns raw Notion API response"),
27
29
  };
28
30
  export function registerQueryDatabase(server, notion) {
29
- server.tool("query-database", "Query a Notion database with optional filters and sorts. Returns paginated results.", inputSchema, async ({ database_id, filter, sorts, start_cursor, page_size }) => {
31
+ server.registerTool('query-database', {
32
+ description: "Query a Notion database with optional filters and sorts. Returns paginated results. Use format='simple' (default) for human-readable output with reduced token usage.",
33
+ inputSchema,
34
+ }, async ({ database_id, filter, sorts, start_cursor, page_size, format }) => {
30
35
  try {
31
36
  const params = { database_id };
32
37
  if (filter) {
@@ -42,6 +47,10 @@ export function registerQueryDatabase(server, notion) {
42
47
  params.page_size = page_size;
43
48
  }
44
49
  const response = await notion.databases.query(params);
50
+ if (format === 'simple') {
51
+ const simplePages = pagesToSimple(response.results);
52
+ return formatSimplePaginatedResponse(simplePages, response.has_more, response.next_cursor);
53
+ }
45
54
  return formatPaginatedResponse(response.results, response.has_more, response.next_cursor);
46
55
  }
47
56
  catch (error) {
@@ -1,4 +1,4 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { NotionClient } from "../notion-client.js";
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
3
  export declare function registerRetrievePage(server: McpServer, notion: NotionClient): void;
4
4
  //# sourceMappingURL=retrieve-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"retrieve-page.d.ts","sourceRoot":"","sources":["../../../src/tools/retrieve-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAOxD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAclF"}
1
+ {"version":3,"file":"retrieve-page.d.ts","sourceRoot":"","sources":["../../../src/tools/retrieve-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAQxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAkCvD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAgDlF"}
@@ -1,12 +1,52 @@
1
- import { z } from "zod";
2
- import { formatResponse, handleError } from "../utils/index.js";
1
+ import { z } from 'zod';
2
+ import { blocksToMarkdown, pageToSimple, } from '../converters/index.js';
3
+ import { formatResponse, formatSimpleResponse, handleError } from '../utils/index.js';
3
4
  const inputSchema = {
4
- page_id: z.string().describe("The ID of the page to retrieve"),
5
+ page_id: z.string().describe('The ID of the page to retrieve'),
6
+ format: z
7
+ .enum(['json', 'simple'])
8
+ .optional()
9
+ .default('simple')
10
+ .describe("Output format: 'simple' (default) returns simplified property values with reduced token usage, 'json' returns raw Notion API response"),
11
+ include_content: z
12
+ .boolean()
13
+ .optional()
14
+ .default(true)
15
+ .describe('Include page content (blocks) as markdown. Default is true. Set to false to only retrieve page properties.'),
5
16
  };
6
17
  export function registerRetrievePage(server, notion) {
7
- server.tool("retrieve-page", "Retrieve a Notion page by its ID. Returns the page properties and metadata.", inputSchema, async ({ page_id }) => {
18
+ server.registerTool('retrieve-page', {
19
+ description: "Retrieve a Notion page by its ID. Returns the page properties, metadata, and optionally content (blocks as markdown). Use format='simple' (default) for human-readable output with reduced token usage.",
20
+ inputSchema,
21
+ }, async ({ page_id, format, include_content }) => {
8
22
  try {
9
23
  const response = await notion.pages.retrieve({ page_id });
24
+ // コンテンツを取得
25
+ let content;
26
+ if (include_content) {
27
+ const blocksResponse = await notion.blocks.children.list({
28
+ block_id: page_id,
29
+ });
30
+ // 子ブロックを再帰的に取得するヘルパー
31
+ const fetchChildren = async (blockId) => {
32
+ const res = await notion.blocks.children.list({
33
+ block_id: blockId,
34
+ });
35
+ return res.results;
36
+ };
37
+ content = await blocksToMarkdown(blocksResponse.results, { fetchChildren });
38
+ }
39
+ if (format === 'simple') {
40
+ const simple = pageToSimple(response);
41
+ if (content !== undefined) {
42
+ return formatSimpleResponse({ ...simple, content });
43
+ }
44
+ return formatSimpleResponse(simple);
45
+ }
46
+ // JSON形式
47
+ if (content !== undefined) {
48
+ return formatResponse({ ...response, content });
49
+ }
10
50
  return formatResponse(response);
11
51
  }
12
52
  catch (error) {
@@ -1,4 +1,4 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { NotionClient } from "../notion-client.js";
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
3
  export declare function registerSearch(server: McpServer, notion: NotionClient): void;
4
4
  //# sourceMappingURL=search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA2CxD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA0C5E"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AA8CvD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAgD5E"}
@@ -1,36 +1,42 @@
1
- import { z } from "zod";
2
- import { formatPaginatedResponse, handleError } from "../utils/index.js";
1
+ import { z } from 'zod';
2
+ import { formatPaginatedResponse, handleError } from '../utils/index.js';
3
3
  const inputSchema = {
4
- query: z.string().optional().describe("Text to search for in page titles and content"),
4
+ query: z.string().optional().describe('Text to search for in page titles and content'),
5
5
  filter: z
6
6
  .object({
7
- value: z.enum(["page", "database"]),
8
- property: z.literal("object"),
7
+ value: z.enum(['page', 'database']),
8
+ property: z.literal('object'),
9
9
  })
10
10
  .optional()
11
- .describe("Filter to limit results to pages or databases. " +
11
+ .describe('Filter to limit results to pages or databases. ' +
12
12
  'Example: { "value": "page", "property": "object" }'),
13
13
  sort: z
14
14
  .object({
15
- direction: z.enum(["ascending", "descending"]),
16
- timestamp: z.literal("last_edited_time"),
15
+ direction: z.enum(['ascending', 'descending']),
16
+ timestamp: z.literal('last_edited_time'),
17
17
  })
18
18
  .optional()
19
- .describe("Sort order for results. " +
19
+ .describe('Sort order for results. ' +
20
20
  'Example: { "direction": "descending", "timestamp": "last_edited_time" }'),
21
21
  start_cursor: z
22
22
  .string()
23
23
  .optional()
24
- .describe("Cursor for pagination. Use the next_cursor from previous response."),
24
+ .describe('Cursor for pagination. Use the next_cursor from previous response.'),
25
25
  page_size: z
26
26
  .number()
27
27
  .min(1)
28
28
  .max(100)
29
29
  .optional()
30
- .describe("Number of results to return (1-100). Default is 100."),
30
+ .describe('Number of results to return (1-100). Default is 100.'),
31
31
  };
32
32
  export function registerSearch(server, notion) {
33
- server.tool("search", "Search across all pages and databases in the workspace. Returns paginated results.", inputSchema, async ({ query, filter, sort, start_cursor, page_size }) => {
33
+ server.registerTool('search', {
34
+ description: 'Search across all pages and databases in the workspace by title and content. ' +
35
+ 'Filter results by type (page or database) and sort by last edited time. ' +
36
+ 'Returns paginated results. ' +
37
+ 'For querying a specific database with filters, use query-database instead.',
38
+ inputSchema,
39
+ }, async ({ query, filter, sort, start_cursor, page_size }) => {
34
40
  try {
35
41
  const params = {};
36
42
  if (query) {
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
+ export declare function registerUpdateDatabase(server: McpServer, notion: NotionClient): void;
4
+ //# sourceMappingURL=update-database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-database.d.ts","sourceRoot":"","sources":["../../../src/tools/update-database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AA2DvD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA2DpF"}
@@ -0,0 +1,74 @@
1
+ import { z } from 'zod';
2
+ import { CoverSchema, IconSchema, RichTextArraySchema, } from '../schemas/common.js';
3
+ import { DatabasePropertiesSchema } from '../schemas/database.js';
4
+ import { formatResponse, handleError } from '../utils/index.js';
5
+ const inputSchema = {
6
+ database_id: z.string().describe('The ID of the database to update'),
7
+ title: RichTextArraySchema.optional().describe('Optional new title for the database as an array of rich text objects. ' +
8
+ 'Example: [{ "type": "text", "text": { "content": "Updated Database Title" } }]'),
9
+ description: RichTextArraySchema.optional().describe('Optional new description for the database as an array of rich text objects. ' +
10
+ 'Example: [{ "type": "text", "text": { "content": "Database description" } }]'),
11
+ properties: DatabasePropertiesSchema.optional().describe('Optional properties to add or update. Keys are property names, values define the property type and configuration. ' +
12
+ 'To add a new property, include its full schema. To update an existing property, provide the property name with its new configuration. ' +
13
+ 'To rename a property, use the property ID as key with a "name" field. ' +
14
+ 'To delete a property, set it to null. ' +
15
+ 'Supported types: title, rich_text, number, select, multi_select, date, people, files, checkbox, url, email, phone_number, formula, relation, rollup, created_time, created_by, last_edited_time, last_edited_by. ' +
16
+ 'Example: { "NewColumn": { "rich_text": {} }, "Price": { "number": { "format": "euro" } } }'),
17
+ icon: IconSchema.nullable()
18
+ .optional()
19
+ .describe('Optional icon for the database. Set to null to remove the icon. ' +
20
+ 'Emoji: { "type": "emoji", "emoji": "📊" }. ' +
21
+ 'External: { "type": "external", "external": { "url": "https://..." } }'),
22
+ cover: CoverSchema.nullable()
23
+ .optional()
24
+ .describe('Optional cover image for the database. Set to null to remove the cover. ' +
25
+ 'Example: { "type": "external", "external": { "url": "https://..." } }'),
26
+ is_inline: z
27
+ .boolean()
28
+ .optional()
29
+ .describe('Optional. If true, the database will appear as an inline database. ' +
30
+ 'If false, it will be a full page database.'),
31
+ archived: z
32
+ .boolean()
33
+ .optional()
34
+ .describe('Optional. Set to true to archive the database, false to unarchive.'),
35
+ };
36
+ export function registerUpdateDatabase(server, notion) {
37
+ server.registerTool('update-database', {
38
+ description: 'Update an existing Notion database. Can modify title, description, properties (add/update/delete columns), icon, cover, inline status, and archive status. ' +
39
+ 'Returns the updated database object.',
40
+ inputSchema,
41
+ }, async ({ database_id, title, description, properties, icon, cover, is_inline, archived }) => {
42
+ try {
43
+ const params = {
44
+ database_id,
45
+ };
46
+ if (title !== undefined) {
47
+ params.title = title;
48
+ }
49
+ if (description !== undefined) {
50
+ params.description = description;
51
+ }
52
+ if (properties !== undefined) {
53
+ params.properties = properties;
54
+ }
55
+ if (icon !== undefined) {
56
+ params.icon = icon;
57
+ }
58
+ if (cover !== undefined) {
59
+ params.cover = cover;
60
+ }
61
+ if (is_inline !== undefined) {
62
+ params.is_inline = is_inline;
63
+ }
64
+ if (archived !== undefined) {
65
+ params.archived = archived;
66
+ }
67
+ const response = await notion.databases.update(params);
68
+ return formatResponse(response);
69
+ }
70
+ catch (error) {
71
+ return handleError(error);
72
+ }
73
+ });
74
+ }
@@ -1,4 +1,4 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { NotionClient } from "../notion-client.js";
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { NotionClient } from '../notion-client.js';
3
3
  export declare function registerUpdatePage(server: McpServer, notion: NotionClient): void;
4
4
  //# sourceMappingURL=update-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-page.d.ts","sourceRoot":"","sources":["../../../src/tools/update-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA+BxD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAsChF"}
1
+ {"version":3,"file":"update-page.d.ts","sourceRoot":"","sources":["../../../src/tools/update-page.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAExE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAkCvD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA4ChF"}
@@ -1,28 +1,33 @@
1
- import { z } from "zod";
2
- import { formatResponse, handleError } from "../utils/index.js";
1
+ import { z } from 'zod';
2
+ import { CoverSchema, IconSchema } from '../schemas/common.js';
3
+ import { PropertiesSchema } from '../schemas/page.js';
4
+ import { formatResponse, handleError } from '../utils/index.js';
3
5
  const inputSchema = {
4
- page_id: z.string().describe("The ID of the page to update"),
5
- properties: z
6
- .record(z.string(), z.any())
7
- .optional()
8
- .describe("Properties to update as a JSON object. Keys are property names, values are property values. " +
6
+ page_id: z.string().describe('The ID of the page to update'),
7
+ properties: PropertiesSchema.optional().describe('Properties to update. Keys are property names, values follow Notion property format. ' +
8
+ 'Supported types: title, rich_text, number, select, multi_select, status, date, checkbox, url, email, phone_number, relation, people, files. ' +
9
9
  'Example: { "Status": { "status": { "name": "Done" } } }'),
10
- archived: z.boolean().optional().describe("Set to true to archive (delete) the page"),
11
- icon: z
12
- .any()
10
+ archived: z.boolean().optional().describe('Set to true to archive (delete) the page'),
11
+ icon: IconSchema.nullable()
13
12
  .optional()
14
- .describe("Optional icon for the page. " +
15
- 'Emoji example: { "type": "emoji", "emoji": "🚀" }. ' +
16
- "Set to null to remove the icon."),
17
- cover: z
18
- .any()
13
+ .describe('Icon for the page. ' +
14
+ 'Emoji: { "type": "emoji", "emoji": "🚀" }. ' +
15
+ 'External: { "type": "external", "external": { "url": "https://..." } }. ' +
16
+ 'Set to null to remove.'),
17
+ cover: CoverSchema.nullable()
19
18
  .optional()
20
- .describe("Optional cover image for the page. " +
19
+ .describe('Cover image for the page. ' +
21
20
  'Example: { "type": "external", "external": { "url": "https://..." } }. ' +
22
- "Set to null to remove the cover."),
21
+ 'Set to null to remove.'),
23
22
  };
24
23
  export function registerUpdatePage(server, notion) {
25
- server.tool("update-page", "Update a Notion page's properties, icon, cover, or archive status.", inputSchema, async ({ page_id, properties, archived, icon, cover }) => {
24
+ server.registerTool('update-page', {
25
+ description: "Update a Notion page's properties, icon, cover, or archive status. " +
26
+ 'Partial updates are supported - only provide the fields you want to change. ' +
27
+ 'Set icon or cover to null to remove them. ' +
28
+ 'Set archived to true to move the page to trash.',
29
+ inputSchema,
30
+ }, async ({ page_id, properties, archived, icon, cover }) => {
26
31
  try {
27
32
  const params = { page_id };
28
33
  if (properties !== undefined) {
@@ -1,5 +1,5 @@
1
1
  export interface McpTextContent {
2
- type: "text";
2
+ type: 'text';
3
3
  text: string;
4
4
  }
5
5
  export interface McpResponse {
@@ -1 +1 @@
1
- {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/utils/error-handler.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAaD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAoBvD"}
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../../src/utils/error-handler.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAaD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAoBvD"}