@striderlabs/mcp-notion 1.0.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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +246 -0
- package/package.json +24 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
ListToolsRequestSchema
|
|
9
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
var API_KEY = process.env.NOTION_API_KEY;
|
|
12
|
+
var BASE_URL = "https://api.notion.com/v1";
|
|
13
|
+
var NOTION_VERSION = "2022-06-28";
|
|
14
|
+
async function notionRequest(method, path, body) {
|
|
15
|
+
const headers = {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
"Notion-Version": NOTION_VERSION
|
|
18
|
+
};
|
|
19
|
+
if (API_KEY) {
|
|
20
|
+
headers["Authorization"] = `Bearer ${API_KEY}`;
|
|
21
|
+
}
|
|
22
|
+
const res = await fetch(`${BASE_URL}${path}`, {
|
|
23
|
+
method,
|
|
24
|
+
headers,
|
|
25
|
+
body: body ? JSON.stringify(body) : void 0
|
|
26
|
+
});
|
|
27
|
+
const data = await res.json();
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
throw new Error(`Notion API error ${res.status}: ${JSON.stringify(data)}`);
|
|
30
|
+
}
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
var server = new Server(
|
|
34
|
+
{ name: "mcp-notion", version: "1.0.0" },
|
|
35
|
+
{ capabilities: { tools: {} } }
|
|
36
|
+
);
|
|
37
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
38
|
+
tools: [
|
|
39
|
+
{
|
|
40
|
+
name: "search_pages",
|
|
41
|
+
description: "Search Notion pages and databases",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
query: { type: "string", description: "Search query" },
|
|
46
|
+
page_size: { type: "number", description: "Number of results (max 100)" }
|
|
47
|
+
},
|
|
48
|
+
required: ["query"]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "get_page",
|
|
53
|
+
description: "Get a Notion page by ID",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {
|
|
57
|
+
page_id: { type: "string", description: "The page ID" }
|
|
58
|
+
},
|
|
59
|
+
required: ["page_id"]
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "create_page",
|
|
64
|
+
description: "Create a new Notion page",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
parent_type: { type: "string", enum: ["database_id", "page_id"], description: "Parent type" },
|
|
69
|
+
parent_id: { type: "string", description: "Parent ID" },
|
|
70
|
+
title: { type: "string", description: "Page title" },
|
|
71
|
+
properties: { type: "object", description: "Additional properties" }
|
|
72
|
+
},
|
|
73
|
+
required: ["parent_type", "parent_id", "title"]
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "update_page",
|
|
78
|
+
description: "Update a Notion page",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
page_id: { type: "string", description: "The page ID" },
|
|
83
|
+
properties: { type: "object", description: "Properties to update" }
|
|
84
|
+
},
|
|
85
|
+
required: ["page_id", "properties"]
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: "query_database",
|
|
90
|
+
description: "Query a Notion database",
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: "object",
|
|
93
|
+
properties: {
|
|
94
|
+
database_id: { type: "string", description: "The database ID" },
|
|
95
|
+
filter: { type: "object", description: "Filter conditions" },
|
|
96
|
+
sorts: { type: "array", description: "Sort conditions" },
|
|
97
|
+
page_size: { type: "number", description: "Number of results" }
|
|
98
|
+
},
|
|
99
|
+
required: ["database_id"]
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "create_database_entry",
|
|
104
|
+
description: "Create an entry in a Notion database",
|
|
105
|
+
inputSchema: {
|
|
106
|
+
type: "object",
|
|
107
|
+
properties: {
|
|
108
|
+
database_id: { type: "string", description: "The database ID" },
|
|
109
|
+
properties: { type: "object", description: "Entry properties" }
|
|
110
|
+
},
|
|
111
|
+
required: ["database_id", "properties"]
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "get_block_children",
|
|
116
|
+
description: "Get children blocks of a Notion block",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: "object",
|
|
119
|
+
properties: {
|
|
120
|
+
block_id: { type: "string", description: "The block ID" },
|
|
121
|
+
page_size: { type: "number", description: "Number of results" }
|
|
122
|
+
},
|
|
123
|
+
required: ["block_id"]
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "append_blocks",
|
|
128
|
+
description: "Append blocks to a Notion block",
|
|
129
|
+
inputSchema: {
|
|
130
|
+
type: "object",
|
|
131
|
+
properties: {
|
|
132
|
+
block_id: { type: "string", description: "The block ID" },
|
|
133
|
+
children: { type: "array", description: "Array of block objects to append" }
|
|
134
|
+
},
|
|
135
|
+
required: ["block_id", "children"]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}));
|
|
140
|
+
var SearchPagesSchema = z.object({
|
|
141
|
+
query: z.string(),
|
|
142
|
+
page_size: z.number().optional()
|
|
143
|
+
});
|
|
144
|
+
var GetPageSchema = z.object({ page_id: z.string() });
|
|
145
|
+
var CreatePageSchema = z.object({
|
|
146
|
+
parent_type: z.enum(["database_id", "page_id"]),
|
|
147
|
+
parent_id: z.string(),
|
|
148
|
+
title: z.string(),
|
|
149
|
+
properties: z.record(z.string(), z.unknown()).optional()
|
|
150
|
+
});
|
|
151
|
+
var UpdatePageSchema = z.object({
|
|
152
|
+
page_id: z.string(),
|
|
153
|
+
properties: z.record(z.string(), z.unknown())
|
|
154
|
+
});
|
|
155
|
+
var QueryDatabaseSchema = z.object({
|
|
156
|
+
database_id: z.string(),
|
|
157
|
+
filter: z.record(z.string(), z.unknown()).optional(),
|
|
158
|
+
sorts: z.array(z.unknown()).optional(),
|
|
159
|
+
page_size: z.number().optional()
|
|
160
|
+
});
|
|
161
|
+
var CreateDatabaseEntrySchema = z.object({
|
|
162
|
+
database_id: z.string(),
|
|
163
|
+
properties: z.record(z.string(), z.unknown())
|
|
164
|
+
});
|
|
165
|
+
var GetBlockChildrenSchema = z.object({
|
|
166
|
+
block_id: z.string(),
|
|
167
|
+
page_size: z.number().optional()
|
|
168
|
+
});
|
|
169
|
+
var AppendBlocksSchema = z.object({
|
|
170
|
+
block_id: z.string(),
|
|
171
|
+
children: z.array(z.unknown())
|
|
172
|
+
});
|
|
173
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
174
|
+
const { name, arguments: args } = request.params;
|
|
175
|
+
try {
|
|
176
|
+
switch (name) {
|
|
177
|
+
case "search_pages": {
|
|
178
|
+
const { query, page_size } = SearchPagesSchema.parse(args);
|
|
179
|
+
const result = await notionRequest("POST", "/search", {
|
|
180
|
+
query,
|
|
181
|
+
page_size: page_size ?? 10
|
|
182
|
+
});
|
|
183
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
184
|
+
}
|
|
185
|
+
case "get_page": {
|
|
186
|
+
const { page_id } = GetPageSchema.parse(args);
|
|
187
|
+
const result = await notionRequest("GET", `/pages/${page_id}`);
|
|
188
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
189
|
+
}
|
|
190
|
+
case "create_page": {
|
|
191
|
+
const { parent_type, parent_id, title, properties } = CreatePageSchema.parse(args);
|
|
192
|
+
const body = {
|
|
193
|
+
parent: { [parent_type]: parent_id },
|
|
194
|
+
properties: {
|
|
195
|
+
title: { title: [{ text: { content: title } }] },
|
|
196
|
+
...properties
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
const result = await notionRequest("POST", "/pages", body);
|
|
200
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
201
|
+
}
|
|
202
|
+
case "update_page": {
|
|
203
|
+
const { page_id, properties } = UpdatePageSchema.parse(args);
|
|
204
|
+
const result = await notionRequest("PATCH", `/pages/${page_id}`, { properties });
|
|
205
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
206
|
+
}
|
|
207
|
+
case "query_database": {
|
|
208
|
+
const { database_id, filter, sorts, page_size } = QueryDatabaseSchema.parse(args);
|
|
209
|
+
const body = {};
|
|
210
|
+
if (filter) body.filter = filter;
|
|
211
|
+
if (sorts) body.sorts = sorts;
|
|
212
|
+
if (page_size) body.page_size = page_size;
|
|
213
|
+
const result = await notionRequest("POST", `/databases/${database_id}/query`, body);
|
|
214
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
215
|
+
}
|
|
216
|
+
case "create_database_entry": {
|
|
217
|
+
const { database_id, properties } = CreateDatabaseEntrySchema.parse(args);
|
|
218
|
+
const result = await notionRequest("POST", "/pages", {
|
|
219
|
+
parent: { database_id },
|
|
220
|
+
properties
|
|
221
|
+
});
|
|
222
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
223
|
+
}
|
|
224
|
+
case "get_block_children": {
|
|
225
|
+
const { block_id, page_size } = GetBlockChildrenSchema.parse(args);
|
|
226
|
+
const qs = page_size ? `?page_size=${page_size}` : "";
|
|
227
|
+
const result = await notionRequest("GET", `/blocks/${block_id}/children${qs}`);
|
|
228
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
229
|
+
}
|
|
230
|
+
case "append_blocks": {
|
|
231
|
+
const { block_id, children } = AppendBlocksSchema.parse(args);
|
|
232
|
+
const result = await notionRequest("PATCH", `/blocks/${block_id}/children`, { children });
|
|
233
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
234
|
+
}
|
|
235
|
+
default:
|
|
236
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
237
|
+
}
|
|
238
|
+
} catch (error) {
|
|
239
|
+
return {
|
|
240
|
+
content: [{ type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
241
|
+
isError: true
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
var transport = new StdioServerTransport();
|
|
246
|
+
await server.connect(transport);
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@striderlabs/mcp-notion",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP connector for Notion API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-notion": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
12
|
+
"dev": "tsup src/index.ts --format esm --watch"
|
|
13
|
+
},
|
|
14
|
+
"files": ["dist"],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "latest",
|
|
17
|
+
"zod": "latest"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"tsup": "latest",
|
|
21
|
+
"typescript": "latest",
|
|
22
|
+
"@types/node": "latest"
|
|
23
|
+
}
|
|
24
|
+
}
|