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
@@ -0,0 +1,156 @@
1
+ // Slice a JSON Schema down to the failing field at a given path, and
2
+ // summarize any unions / deep nesting so the error envelope stays small.
3
+ //
4
+ // The full schema is always available via `notion_describe`; in a validation
5
+ // error we only need to show the LLM what the failing field expects, plus a
6
+ // working example. The unsliced schemas can be 10+KB (set_page_property's
7
+ // value union, update_database's properties propertyNames union, etc.).
8
+ const DEFAULT_SUMMARY_DEPTH = 2;
9
+ function resolveRef(node, defs) {
10
+ const ref = node["$ref"];
11
+ if (typeof ref !== "string" || !defs)
12
+ return node;
13
+ const match = /^#\/\$defs\/(.+)$/.exec(ref);
14
+ if (!match)
15
+ return node;
16
+ if (!Object.hasOwn(defs, match[1]))
17
+ return node;
18
+ const resolved = defs[match[1]];
19
+ if (typeof resolved !== "object" || resolved === null)
20
+ return node;
21
+ return resolved;
22
+ }
23
+ function asObject(value) {
24
+ if (typeof value !== "object" || value === null)
25
+ return undefined;
26
+ return value;
27
+ }
28
+ export function sliceJsonSchema(root, path) {
29
+ const defs = root.$defs;
30
+ let cur = root;
31
+ for (const seg of path) {
32
+ cur = resolveRef(cur, defs);
33
+ if (typeof seg === "string") {
34
+ // Only follow own-property keys: a Zod error path comes from caller-supplied
35
+ // payload field names, so `__proto__` / `constructor` could otherwise walk
36
+ // the prototype chain when slicing.
37
+ const props = asObject(cur.properties);
38
+ if (props && Object.hasOwn(props, seg)) {
39
+ const next = asObject(props[seg]);
40
+ if (next) {
41
+ cur = next;
42
+ continue;
43
+ }
44
+ }
45
+ const branches = (cur.oneOf ?? cur.anyOf);
46
+ if (Array.isArray(branches)) {
47
+ const matched = branches
48
+ .map((b) => resolveRef(b, defs))
49
+ .find((b) => {
50
+ const p = asObject(b.properties);
51
+ return p !== undefined && Object.hasOwn(p, seg);
52
+ });
53
+ if (matched) {
54
+ const props = asObject(matched.properties);
55
+ if (props) {
56
+ const next = asObject(props[seg]);
57
+ if (next) {
58
+ cur = next;
59
+ continue;
60
+ }
61
+ }
62
+ }
63
+ }
64
+ return cur;
65
+ }
66
+ if (typeof seg === "number") {
67
+ const items = cur.items;
68
+ if (Array.isArray(items)) {
69
+ const next = asObject(items[seg]);
70
+ if (next) {
71
+ cur = next;
72
+ continue;
73
+ }
74
+ }
75
+ else if (items) {
76
+ const next = asObject(items);
77
+ if (next) {
78
+ cur = next;
79
+ continue;
80
+ }
81
+ }
82
+ return cur;
83
+ }
84
+ }
85
+ return resolveRef(cur, defs);
86
+ }
87
+ // Replace large unions with a one-line-per-branch discriminator summary,
88
+ // and cap nested objects/arrays at DEFAULT_SUMMARY_DEPTH.
89
+ export function summarizeSchema(schema, depth = DEFAULT_SUMMARY_DEPTH, defs) {
90
+ const allDefs = defs ?? schema.$defs;
91
+ const resolved = resolveRef(schema, allDefs);
92
+ if (depth < 0) {
93
+ const t = resolved.type;
94
+ return { _truncated: true, ...(t ? { type: t } : {}) };
95
+ }
96
+ for (const key of ["oneOf", "anyOf"]) {
97
+ const branches = resolved[key];
98
+ if (Array.isArray(branches)) {
99
+ const summary = branches.map((b) => discriminatorSummary(b, allDefs));
100
+ const out = { [key]: summary };
101
+ if (resolved.description)
102
+ out.description = resolved.description;
103
+ return out;
104
+ }
105
+ }
106
+ if (resolved.type === "object" && asObject(resolved.properties)) {
107
+ const props = resolved.properties;
108
+ const summarizedProps = {};
109
+ for (const [k, v] of Object.entries(props)) {
110
+ summarizedProps[k] = summarizeSchema(v, depth - 1, allDefs);
111
+ }
112
+ const out = { ...resolved, properties: summarizedProps };
113
+ delete out.$defs;
114
+ return out;
115
+ }
116
+ if (resolved.type === "array") {
117
+ const items = resolved.items;
118
+ if (items && !Array.isArray(items)) {
119
+ const out = {
120
+ ...resolved,
121
+ items: summarizeSchema(items, depth - 1, allDefs),
122
+ };
123
+ delete out.$defs;
124
+ return out;
125
+ }
126
+ }
127
+ const out = { ...resolved };
128
+ delete out.$defs;
129
+ return out;
130
+ }
131
+ // One-line-per-branch: if a branch has a property with a literal `const`
132
+ // (Zod literals emit as such), surface it as the discriminator tag. Otherwise
133
+ // fall back to `type` + the first required field name.
134
+ function discriminatorSummary(branch, defs) {
135
+ const resolved = resolveRef(branch, defs);
136
+ const props = asObject(resolved.properties);
137
+ if (props) {
138
+ for (const [k, v] of Object.entries(props)) {
139
+ const val = asObject(v);
140
+ if (val && val.const !== undefined) {
141
+ return { [k]: val.const };
142
+ }
143
+ }
144
+ const required = resolved.required;
145
+ if (Array.isArray(required) && required.length > 0) {
146
+ return { type: "object", required };
147
+ }
148
+ }
149
+ if (resolved.type)
150
+ return { type: resolved.type };
151
+ if (resolved.const !== undefined)
152
+ return { const: resolved.const };
153
+ if (Array.isArray(resolved.enum))
154
+ return { enum: resolved.enum };
155
+ return resolved;
156
+ }
@@ -0,0 +1,269 @@
1
+ import { isFullBlock, isFullComment, isFullDatabase, isFullDataSource, isFullPage, isFullUser, } from "@notionhq/client";
2
+ function extractRichText(rich) {
3
+ return rich.map((r) => r.plain_text).join("");
4
+ }
5
+ function extractTitle(properties) {
6
+ for (const value of Object.values(properties)) {
7
+ if (value.type === "title")
8
+ return extractRichText(value.title);
9
+ }
10
+ return undefined;
11
+ }
12
+ // Flatten a single Notion property to a primitive (or small object) the LLM
13
+ // can read directly. Returns undefined for empty values so the caller can skip
14
+ // them — keeps the response tight for sparsely populated rows.
15
+ function flattenProperty(prop) {
16
+ switch (prop.type) {
17
+ case "title":
18
+ return extractRichText(prop.title) || undefined;
19
+ case "rich_text":
20
+ return extractRichText(prop.rich_text) || undefined;
21
+ case "number":
22
+ return prop.number ?? undefined;
23
+ case "select":
24
+ return prop.select?.name ?? undefined;
25
+ case "multi_select":
26
+ return prop.multi_select.length ? prop.multi_select.map((s) => s.name) : undefined;
27
+ case "status":
28
+ return prop.status?.name ?? undefined;
29
+ case "date": {
30
+ if (!prop.date)
31
+ return undefined;
32
+ const { start, end } = prop.date;
33
+ return end ? { start, end } : start;
34
+ }
35
+ case "people":
36
+ return prop.people.length ? prop.people.map((p) => p.id) : undefined;
37
+ case "files":
38
+ return prop.files.length
39
+ ? prop.files.map((f) => {
40
+ if (f.type === "external")
41
+ return { name: f.name, url: f.external.url };
42
+ return { name: f.name, url: f.file.url };
43
+ })
44
+ : undefined;
45
+ case "checkbox":
46
+ return prop.checkbox;
47
+ case "url":
48
+ return prop.url ?? undefined;
49
+ case "email":
50
+ return prop.email ?? undefined;
51
+ case "phone_number":
52
+ return prop.phone_number ?? undefined;
53
+ case "formula": {
54
+ const f = prop.formula;
55
+ if (f.type === "string")
56
+ return f.string ?? undefined;
57
+ if (f.type === "number")
58
+ return f.number ?? undefined;
59
+ if (f.type === "boolean")
60
+ return f.boolean ?? undefined;
61
+ if (f.type === "date")
62
+ return f.date?.start ?? undefined;
63
+ return undefined;
64
+ }
65
+ case "relation":
66
+ return prop.relation.length ? prop.relation.map((r) => r.id) : undefined;
67
+ case "rollup": {
68
+ const r = prop.rollup;
69
+ if (r.type === "number")
70
+ return r.number ?? undefined;
71
+ if (r.type === "date")
72
+ return r.date?.start ?? undefined;
73
+ if (r.type === "array") {
74
+ if (!r.array.length)
75
+ return undefined;
76
+ const flat = r.array
77
+ .map((item) => flattenProperty(item))
78
+ .filter((v) => v !== undefined);
79
+ return flat.length ? flat : undefined;
80
+ }
81
+ return undefined;
82
+ }
83
+ case "created_time":
84
+ return prop.created_time;
85
+ case "last_edited_time":
86
+ return prop.last_edited_time;
87
+ case "created_by":
88
+ return prop.created_by.id;
89
+ case "last_edited_by":
90
+ return prop.last_edited_by.id;
91
+ case "unique_id": {
92
+ const { prefix, number } = prop.unique_id;
93
+ if (number == null)
94
+ return undefined;
95
+ return prefix ? `${prefix}-${number}` : number;
96
+ }
97
+ case "verification":
98
+ return prop.verification?.state ?? undefined;
99
+ default:
100
+ return undefined;
101
+ }
102
+ }
103
+ function flattenProperties(properties) {
104
+ const out = {};
105
+ for (const [name, value] of Object.entries(properties)) {
106
+ // Skip the title prop — already surfaced as `title`.
107
+ if (value.type === "title")
108
+ continue;
109
+ const flat = flattenProperty(value);
110
+ if (flat !== undefined)
111
+ out[name] = flat;
112
+ }
113
+ return out;
114
+ }
115
+ export function slimPage(page, verbose = false, includeProperties = false) {
116
+ if (verbose)
117
+ return page;
118
+ if (!isFullPage(page))
119
+ return { id: page.id };
120
+ const base = {
121
+ id: page.id,
122
+ url: page.url,
123
+ title: extractTitle(page.properties),
124
+ parent: page.parent,
125
+ ...(page.in_trash ? { in_trash: true } : {}),
126
+ ...(page.icon ? { icon: page.icon.type } : {}),
127
+ };
128
+ if (!includeProperties)
129
+ return base;
130
+ const props = flattenProperties(page.properties);
131
+ return Object.keys(props).length ? { ...base, properties: props } : base;
132
+ }
133
+ export function slimBlock(block, verbose = false) {
134
+ if (verbose)
135
+ return block;
136
+ if (!isFullBlock(block))
137
+ return { id: block.id };
138
+ const base = {
139
+ id: block.id,
140
+ type: block.type,
141
+ text: extractBlockText(block),
142
+ ...(block.has_children ? { has_children: true } : {}),
143
+ ...(block.in_trash ? { in_trash: true } : {}),
144
+ };
145
+ if (block.type === "to_do") {
146
+ return { ...base, checked: block.to_do.checked };
147
+ }
148
+ if (block.type === "code") {
149
+ return { ...base, language: block.code.language };
150
+ }
151
+ if (block.type === "image") {
152
+ const img = block.image;
153
+ const url = img.type === "external" ? img.external.url : img.file.url;
154
+ return { ...base, image: url };
155
+ }
156
+ return base;
157
+ }
158
+ function extractBlockText(block) {
159
+ // Many block subtypes expose a `rich_text` array under their type key.
160
+ // Read it via a structural narrow so we don't have to enumerate every variant.
161
+ const inner = block[block.type];
162
+ if (typeof inner !== "object" || inner === null)
163
+ return undefined;
164
+ const richText = inner.rich_text;
165
+ if (!Array.isArray(richText))
166
+ return undefined;
167
+ return extractRichText(richText);
168
+ }
169
+ export function slimDatabase(db, verbose = false) {
170
+ if (verbose)
171
+ return db;
172
+ if (!isFullDatabase(db))
173
+ return { id: db.id };
174
+ const description = extractRichText(db.description);
175
+ return {
176
+ id: db.id,
177
+ url: db.url,
178
+ title: extractRichText(db.title),
179
+ ...(description ? { description } : {}),
180
+ parent: db.parent,
181
+ ...(db.in_trash ? { in_trash: true } : {}),
182
+ ...(db.is_inline ? { is_inline: true } : {}),
183
+ ...(db.is_locked ? { is_locked: true } : {}),
184
+ data_sources: db.data_sources.map((s) => ({ id: s.id, name: s.name })),
185
+ ...(db.icon ? { icon: db.icon.type } : {}),
186
+ };
187
+ }
188
+ export function slimDataSource(ds, verbose = false) {
189
+ if (verbose)
190
+ return ds;
191
+ if (!isFullDataSource(ds))
192
+ return { id: ds.id };
193
+ const description = extractRichText(ds.description);
194
+ return {
195
+ id: ds.id,
196
+ url: ds.url,
197
+ title: extractRichText(ds.title),
198
+ ...(description ? { description } : {}),
199
+ parent: ds.parent,
200
+ // name → property-type map. Same byte cost as a name-only array but the
201
+ // type info is what query_database planners actually need (otherwise
202
+ // callers would have to drop verbose:true just to learn types).
203
+ properties: Object.fromEntries(Object.entries(ds.properties).map(([name, def]) => [name, def.type])),
204
+ ...(ds.icon ? { icon: ds.icon.type } : {}),
205
+ ...(ds.in_trash ? { in_trash: true } : {}),
206
+ };
207
+ }
208
+ export function slimItem(item, verbose = false, includeProperties = false) {
209
+ if (verbose)
210
+ return item;
211
+ if (item.object === "page")
212
+ return slimPage(item, verbose, includeProperties);
213
+ if (item.object === "database")
214
+ return slimDatabase(item, verbose);
215
+ return slimDataSource(item, verbose);
216
+ }
217
+ export function slimUser(user, verbose = false) {
218
+ if (verbose)
219
+ return user;
220
+ if (!isFullUser(user))
221
+ return { id: user.id };
222
+ const base = {
223
+ id: user.id,
224
+ type: user.type,
225
+ name: user.name,
226
+ ...(user.avatar_url ? { avatar_url: user.avatar_url } : {}),
227
+ };
228
+ if (user.type === "person")
229
+ return { ...base, email: user.person.email };
230
+ if (user.type === "bot") {
231
+ const workspaceName = "workspace_name" in user.bot ? user.bot.workspace_name : undefined;
232
+ return workspaceName ? { ...base, workspace_name: workspaceName } : base;
233
+ }
234
+ return base;
235
+ }
236
+ export function slimFileUpload(fu, verbose = false) {
237
+ if (verbose)
238
+ return fu;
239
+ return {
240
+ file_upload_id: fu.id,
241
+ ...(fu.status ? { status: fu.status } : {}),
242
+ ...(fu.filename ? { filename: fu.filename } : {}),
243
+ ...(fu.content_type ? { content_type: fu.content_type } : {}),
244
+ ...(fu.content_length !== undefined && fu.content_length !== null
245
+ ? { content_length: fu.content_length }
246
+ : {}),
247
+ ...(fu.expiry_time ? { expiry_time: fu.expiry_time } : {}),
248
+ };
249
+ }
250
+ export function slimComment(comment, verbose = false) {
251
+ if (verbose)
252
+ return comment;
253
+ if (!isFullComment(comment))
254
+ return { id: comment.id };
255
+ return {
256
+ id: comment.id,
257
+ parent: comment.parent,
258
+ discussion_id: comment.discussion_id,
259
+ text: extractRichText(comment.rich_text),
260
+ created_by: comment.created_by.id,
261
+ };
262
+ }
263
+ export function slimList(list, slim, verbose = false) {
264
+ return {
265
+ results: list.results.map((r) => slim(r, verbose)),
266
+ has_more: list.has_more ?? false,
267
+ next_cursor: list.next_cursor ?? null,
268
+ };
269
+ }
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "notion-mcp-server",
3
- "version": "1.0.0",
3
+ "version": "2.4.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "notion-mcp-server": "build/index.js"
7
7
  },
8
8
  "scripts": {
9
- "build": "tsc && shx chmod +x build/*.js",
9
+ "build": "shx rm -rf build && tsc && shx chmod +x build/*.js",
10
10
  "prepare": "npm run build",
11
11
  "watch": "tsc --watch",
12
+ "test": "vitest run",
13
+ "test:watch": "vitest",
12
14
  "inspector": "npx @modelcontextprotocol/inspector build/index.js -e NOTION_TOKEN=your_notion_token -e NOTION_PAGE_ID=your_notion_page_id"
13
15
  },
14
16
  "homepage": "https://github.com/awkoy/notion-mcp-server",
@@ -25,17 +27,21 @@
25
27
  "build"
26
28
  ],
27
29
  "dependencies": {
28
- "@modelcontextprotocol/sdk": "^1.7.0",
29
- "@notionhq/client": "^2.3.0",
30
- "zod": "^3.24.2"
30
+ "@modelcontextprotocol/sdk": "^1.29.0",
31
+ "@notionhq/client": "^5.22.0",
32
+ "remark-gfm": "^4.0.1",
33
+ "remark-parse": "^11.0.0",
34
+ "unified": "^11.0.5",
35
+ "zod": "^4.4.3"
31
36
  },
32
37
  "devDependencies": {
33
38
  "@types/node": "^22.13.10",
34
39
  "shx": "^0.3.4",
35
- "typescript": "^5.8.2"
40
+ "typescript": "^5.8.2",
41
+ "vitest": "^4.1.7"
36
42
  },
37
43
  "engines": {
38
- "node": ">=18"
44
+ "node": ">=20"
39
45
  },
40
46
  "repository": {
41
47
  "type": "git",
@@ -1,62 +0,0 @@
1
- import { server } from "../server/index.js";
2
- import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { replicate } from "../services/replicate.js";
4
- import { urlToBase64 } from "../utils/image.js";
5
- import { CONFIG } from "../config/index.js";
6
- export const registerImageListResource = () => {
7
- const list = async () => {
8
- try {
9
- const predictions = [];
10
- for await (const page of replicate.paginate(replicate.predictions.list)) {
11
- predictions.push(...page);
12
- }
13
- return {
14
- resources: predictions
15
- .filter((prediction) => prediction.output?.length &&
16
- prediction.model === CONFIG.imageModelId)
17
- .map((prediction) => ({
18
- uri: `images://${prediction.id}`,
19
- name: `Image ${prediction.id}`,
20
- mimeType: "application/json",
21
- description: `Generated image by ${prediction.model} with id ${prediction.id}`,
22
- })),
23
- nextCursor: undefined,
24
- };
25
- }
26
- catch (error) {
27
- console.error("Error listing predictions:", error);
28
- return {
29
- resources: [],
30
- nextCursor: undefined,
31
- };
32
- }
33
- };
34
- server.resource("images", new ResourceTemplate("images://{id}", {
35
- list,
36
- }), async (uri, { id }) => {
37
- const prediction = await replicate.predictions.get(id);
38
- if (!prediction.output?.length) {
39
- return {
40
- contents: [
41
- {
42
- name: "Not Found!",
43
- uri: uri.href,
44
- text: `Data has been removed by Replicate automatically after an hour, by default. You have to save your own copies before it is removed.`,
45
- mimeType: "text/plain",
46
- },
47
- ],
48
- };
49
- }
50
- const imageBase64 = await urlToBase64(prediction.output[0]);
51
- return {
52
- contents: [
53
- {
54
- name: "image",
55
- uri: uri.href,
56
- blob: imageBase64,
57
- mimeType: "image/png",
58
- },
59
- ],
60
- };
61
- });
62
- };
@@ -1 +0,0 @@
1
- export const registerAllResources = () => { };
@@ -1,43 +0,0 @@
1
- import { server } from "../server/index.js";
2
- import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { replicate } from "../services/replicate.js";
4
- export const registerPreditionListResource = () => {
5
- const list = async () => {
6
- try {
7
- const predictions = [];
8
- for await (const page of replicate.paginate(replicate.predictions.list)) {
9
- predictions.push(...page);
10
- }
11
- return {
12
- resources: predictions.map((prediction) => ({
13
- uri: `predictions://${prediction.id}`,
14
- name: `Prediction ${prediction.id}`,
15
- mimeType: "application/json",
16
- })),
17
- nextCursor: undefined,
18
- };
19
- }
20
- catch (error) {
21
- console.error("Error listing predictions:", error);
22
- return {
23
- resources: [],
24
- nextCursor: undefined,
25
- };
26
- }
27
- };
28
- server.resource("predictions", new ResourceTemplate("predictions://{id}", {
29
- list,
30
- }), async (uri, { id }) => {
31
- const prediction = await replicate.predictions.get(id);
32
- return {
33
- contents: [
34
- {
35
- name: "prediction",
36
- uri: uri.href,
37
- text: JSON.stringify(prediction),
38
- mimeType: "application/json",
39
- },
40
- ],
41
- };
42
- });
43
- };
@@ -1,69 +0,0 @@
1
- // import { server } from "../server/index.js";
2
- // import {
3
- // ListResourcesCallback,
4
- // ResourceTemplate,
5
- // } from "@modelcontextprotocol/sdk/server/mcp.js";
6
- // import { replicate } from "../services/notion.js";
7
- // import { urlToSvg } from "../utils/image.js";
8
- // import { Prediction } from "replicate";
9
- // import { CONFIG } from "../config/index.js";
10
- export {};
11
- // export const registerSvgListResource = () => {
12
- // const list: ListResourcesCallback = async () => {
13
- // try {
14
- // const predictions: Prediction[] = [];
15
- // for await (const page of replicate.paginate(replicate.predictions.list)) {
16
- // predictions.push(...page);
17
- // }
18
- // return {
19
- // resources: predictions
20
- // .filter((prediction) => prediction.model === CONFIG.svgModelId)
21
- // .map((prediction) => ({
22
- // uri: `svglist://${prediction.id}`,
23
- // name: `SVG ${prediction.id}`,
24
- // mimeType: "application/json",
25
- // description: `Generated image by ${prediction.model} with id ${prediction.id}`,
26
- // })),
27
- // nextCursor: undefined,
28
- // };
29
- // } catch (error) {
30
- // console.error("Error listing predictions:", error);
31
- // return {
32
- // resources: [],
33
- // nextCursor: undefined,
34
- // };
35
- // }
36
- // };
37
- // server.resource(
38
- // "svglist",
39
- // new ResourceTemplate("svglist://{id}", {
40
- // list,
41
- // }),
42
- // async (uri, { id }) => {
43
- // const prediction = await replicate.predictions.get(id as string);
44
- // if (!prediction.output) {
45
- // return {
46
- // contents: [
47
- // {
48
- // name: "Not Found!",
49
- // uri: uri.href,
50
- // text: `Data has been removed by Replicate automatically after an hour, by default. You have to save your own copies before it is removed.`,
51
- // mimeType: "text/plain",
52
- // },
53
- // ],
54
- // };
55
- // }
56
- // const svg = await urlToSvg(prediction.output);
57
- // return {
58
- // contents: [
59
- // {
60
- // name: "svglist",
61
- // uri: uri.href,
62
- // text: svg,
63
- // mimeType: "image/svg+xml",
64
- // },
65
- // ],
66
- // };
67
- // }
68
- // );
69
- // };
@@ -1,34 +0,0 @@
1
- import { z } from "zod";
2
- import { RICH_TEXT_ITEM_REQUEST_SCHEMA } from "./rich-text.js";
3
- // Schema for getting comments
4
- export const GET_COMMENTS_SCHEMA = {
5
- block_id: z
6
- .string()
7
- .describe("The ID of the block or page to get comments from"),
8
- start_cursor: z
9
- .string()
10
- .optional()
11
- .describe("The cursor to start from for pagination"),
12
- page_size: z
13
- .number()
14
- .optional()
15
- .describe("Number of comments to return per page"),
16
- };
17
- // Schema for adding a comment to a page
18
- export const ADD_PAGE_COMMENT_SCHEMA = {
19
- parent: z.object({
20
- page_id: z.string().describe("The ID of the page to add the comment to"),
21
- }),
22
- rich_text: z
23
- .array(RICH_TEXT_ITEM_REQUEST_SCHEMA)
24
- .describe("Rich text content for the comment"),
25
- };
26
- // Schema for adding a comment to a discussion
27
- export const ADD_DISCUSSION_COMMENT_SCHEMA = {
28
- discussion_id: z
29
- .string()
30
- .describe("The ID of the discussion to add the comment to"),
31
- rich_text: z
32
- .array(RICH_TEXT_ITEM_REQUEST_SCHEMA)
33
- .describe("Rich text content for the comment"),
34
- };