@matimo/notion 0.1.0-alpha.10
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/LICENSE +21 -0
- package/README.md +335 -0
- package/definition.yaml +34 -0
- package/package.json +18 -0
- package/tools/notion_create_comment/definition.yaml +97 -0
- package/tools/notion_create_page/definition.yaml +127 -0
- package/tools/notion_create_page/index.ts +259 -0
- package/tools/notion_get_user/definition.yaml +55 -0
- package/tools/notion_list_databases/definition.yaml +70 -0
- package/tools/notion_query_database/definition.yaml +100 -0
- package/tools/notion_search/definition.yaml +87 -0
- package/tools/notion_update_page/definition.yaml +117 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tallclub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# @matimo/notion — Notion Tools for Matimo
|
|
2
|
+
|
|
3
|
+
Notion workspace integration tools for Matimo's universal AI tools ecosystem. Query databases, create pages, manage content, search workspaces, add comments, and retrieve user information through YAML-defined tools that work with any AI framework.
|
|
4
|
+
|
|
5
|
+
## 📦 Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @matimo/notion
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @matimo/notion
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 🛠️ Available Tools (7 Total)
|
|
14
|
+
|
|
15
|
+
| Tool | Method | Description |
|
|
16
|
+
|------|--------|-------------|
|
|
17
|
+
| **notion_list_databases** | POST | List all databases (data sources) in workspace |
|
|
18
|
+
| **notion_query_database** | POST | Query pages from database with filters and sorting |
|
|
19
|
+
| **notion_create_page** | POST | Create new page in database or as child page |
|
|
20
|
+
| **notion_update_page** | PATCH | Update page properties, icon, status, archive |
|
|
21
|
+
| **notion_search** | POST | Search workspace pages and databases by title |
|
|
22
|
+
| **notion_create_comment** | POST | Add comments to pages, blocks, or discussions |
|
|
23
|
+
| **notion_get_user** | GET | Retrieve user information and profile details |
|
|
24
|
+
|
|
25
|
+
## 🚀 Quick Start
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { MatimoInstance } from '@matimo/core';
|
|
29
|
+
|
|
30
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
31
|
+
|
|
32
|
+
// Query a database
|
|
33
|
+
const results = await matimo.execute('notion_query_database', {
|
|
34
|
+
database_id: 'a1d8501e-1ac1-43e9-a6bd-ea9fe6c8822b'
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
console.log('Found pages:', results.results.length);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 🔐 Authentication Setup
|
|
41
|
+
|
|
42
|
+
### Get Your Notion API Token
|
|
43
|
+
|
|
44
|
+
1. Go to [Notion Integrations](https://www.notion.so/my-integrations)
|
|
45
|
+
2. Click "Create new integration"
|
|
46
|
+
3. Set workspace and name your integration
|
|
47
|
+
4. Grant required capabilities:
|
|
48
|
+
- ✅ Read content
|
|
49
|
+
- ✅ Update content
|
|
50
|
+
- ✅ Insert content
|
|
51
|
+
- ✅ Read user information
|
|
52
|
+
- ✅ Insert comments
|
|
53
|
+
5. Copy your "Internal Integration Secret" (token)
|
|
54
|
+
6. Set environment variable:
|
|
55
|
+
```bash
|
|
56
|
+
export NOTION_API_KEY=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Share Resources with Your Integration
|
|
60
|
+
|
|
61
|
+
For each database/page you want to access:
|
|
62
|
+
1. Click the ••• menu (top-right)
|
|
63
|
+
2. Scroll to "Add connections"
|
|
64
|
+
3. Search for and select your integration
|
|
65
|
+
|
|
66
|
+
## 🤖 How AI Agents Use These Tools
|
|
67
|
+
|
|
68
|
+
AI agents (Claude, ChatGPT, etc.) don't need to know internal API details. They discover tools automatically:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// AI agent discovers all available tools
|
|
72
|
+
const tools = matimo.listTools();
|
|
73
|
+
|
|
74
|
+
// Each tool has:
|
|
75
|
+
// - name: "notion_list_databases" ← Tool identifier
|
|
76
|
+
// - description: "List all databases..." ← What it does
|
|
77
|
+
// - parameters: { ← What inputs it accepts
|
|
78
|
+
// database_id: { type: "string", description: "Get from notion_list_databases..." }
|
|
79
|
+
// }
|
|
80
|
+
// - examples: [...] ← How to use it
|
|
81
|
+
|
|
82
|
+
// AI agent reads descriptions and automatically knows:
|
|
83
|
+
// 1. Use notion_list_databases() first to get database IDs
|
|
84
|
+
// 2. Pass those IDs to notion_query_database() for queries
|
|
85
|
+
// 3. Use returned page IDs with notion_create_page(), etc.
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**No memorization needed.** Tools are self-describing through their schemas, descriptions, and examples.
|
|
89
|
+
|
|
90
|
+
## 📖 Integration Examples
|
|
91
|
+
|
|
92
|
+
### Factory Pattern (Simple)
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { MatimoInstance } from '@matimo/core';
|
|
96
|
+
|
|
97
|
+
const matimo = await MatimoInstance.init({ autoDiscover: true });
|
|
98
|
+
|
|
99
|
+
// AI agent autonomously discovers and uses tools
|
|
100
|
+
// Step 1: List databases
|
|
101
|
+
const databases = await matimo.execute('notion_list_databases', { page_size: 10 });
|
|
102
|
+
const myDb = databases.data.results[0];
|
|
103
|
+
|
|
104
|
+
// Step 2: Query the database
|
|
105
|
+
const pages = await matimo.execute('notion_query_database', {
|
|
106
|
+
database_id: myDb.id,
|
|
107
|
+
page_size: 5
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Step 3: Create a new page
|
|
111
|
+
const newPage = await matimo.execute('notion_create_page', {
|
|
112
|
+
parent: { database_id: myDb.id },
|
|
113
|
+
markdown: '# New Page\n\nContent here'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
console.log('Created:', newPage.data.url);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Decorator Pattern (Class-Based)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { MatimoInstance, setGlobalMatimoInstance, tool } from '@matimo/core';
|
|
123
|
+
|
|
124
|
+
const matimo = await MatimoInstance.init('./tools');
|
|
125
|
+
setGlobalMatimoInstance(matimo);
|
|
126
|
+
|
|
127
|
+
class NotionManager {
|
|
128
|
+
@tool('notion_query_database')
|
|
129
|
+
async queryDatabase(database_id: string, filter?: Record<string, any>) {
|
|
130
|
+
// Auto-executed by decorator
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@tool('notion_create_page')
|
|
134
|
+
async createPage(
|
|
135
|
+
parent: Record<string, string>, // e.g., { database_id: '...' } or { page_id: '...' }
|
|
136
|
+
markdown?: string,
|
|
137
|
+
icon?: Record<string, string>
|
|
138
|
+
) {
|
|
139
|
+
// Auto-executed by decorator
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@tool('notion_search')
|
|
143
|
+
async search(query: string, sort_by?: string) {
|
|
144
|
+
// Auto-executed by decorator
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const manager = new NotionManager();
|
|
149
|
+
const results = await manager.queryDatabase('db-id');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### LangChain Integration (AI Framework)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { MatimoInstance } from '@matimo/core';
|
|
156
|
+
|
|
157
|
+
const matimo = await MatimoInstance.init('./tools');
|
|
158
|
+
|
|
159
|
+
// Get tool schemas for LangChain
|
|
160
|
+
const notionTools = matimo.listTools()
|
|
161
|
+
.filter(t => t.name.startsWith('notion_'))
|
|
162
|
+
.map(tool => ({
|
|
163
|
+
type: 'function',
|
|
164
|
+
function: {
|
|
165
|
+
name: tool.name,
|
|
166
|
+
description: tool.description,
|
|
167
|
+
parameters: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: tool.parameters || {},
|
|
170
|
+
required: Object.entries(tool.parameters || {})
|
|
171
|
+
.filter(([_, p]: [string, any]) => p.required)
|
|
172
|
+
.map(([name]) => name),
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
}));
|
|
176
|
+
|
|
177
|
+
// Use with your LLM/agent
|
|
178
|
+
console.log('Available tools for LangChain:', notionTools.map(t => t.function.name));
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 📚 API Reference
|
|
182
|
+
|
|
183
|
+
### notion_query_database
|
|
184
|
+
|
|
185
|
+
Query pages in a Notion database with optional filtering and sorting.
|
|
186
|
+
|
|
187
|
+
**Parameters:**
|
|
188
|
+
- `database_id` (required): UUID of the database
|
|
189
|
+
- `filter` (optional): JSON filter object (e.g., `{"property": "Status", "status": {"equals": "Done"}}`)
|
|
190
|
+
- `sort` (optional): Array of sort objects
|
|
191
|
+
- `page_size` (optional): Results per page (1-100, default 100)
|
|
192
|
+
- `start_cursor` (optional): Pagination cursor
|
|
193
|
+
|
|
194
|
+
**Returns:** Paginated list of pages with `results`, `has_more`, `next_cursor`
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### notion_create_page
|
|
199
|
+
|
|
200
|
+
Create a new page, optionally with properties and content.
|
|
201
|
+
|
|
202
|
+
**Parameters:**
|
|
203
|
+
- `parent` (required): Object describing where to create the page. Provide ONE of:
|
|
204
|
+
- `{ "database_id": "..." }` to create inside a database
|
|
205
|
+
- `{ "page_id": "..." }` to create as a child page
|
|
206
|
+
- `properties` (optional): JSON properties matching parent schema
|
|
207
|
+
- `markdown` (optional): String content using Markdown (easiest way to add content)
|
|
208
|
+
- `icon` (optional): Object for page icon, e.g. `{ type: 'emoji', emoji: '✅' }`
|
|
209
|
+
- `children` (optional): Array of Notion block objects to add to the page
|
|
210
|
+
|
|
211
|
+
> **Note:** This tool accepts a single `parent` object (for example `{ "database_id": "..." }` or `{ "page_id": "..."`) — do not pass separate `parent_id` / `parent_type` parameters. This matches the tool's YAML definition (`packages/notion/tools/notion_create_page/definition.yaml`).
|
|
212
|
+
|
|
213
|
+
**Returns:** Created page object with `id`, `url`, and `properties`
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### notion_update_page
|
|
218
|
+
|
|
219
|
+
Update page properties, status, archive status, or icon.
|
|
220
|
+
|
|
221
|
+
**Parameters:**
|
|
222
|
+
- `page_id` (required): UUID of page to update
|
|
223
|
+
- `properties` (optional): JSON properties to update
|
|
224
|
+
- `icon` (optional): Object for page icon (e.g., { "type": "emoji", "emoji": "✅" } or { "type": "external", "external": { "url": "https://..." } })
|
|
225
|
+
- `archived` (optional): Archive/unarchive page (boolean)
|
|
226
|
+
- `in_trash` (optional): Move to/restore from trash
|
|
227
|
+
- `is_locked` (optional): Lock/unlock page editing
|
|
228
|
+
|
|
229
|
+
**Returns:** Updated page object
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
### notion_search
|
|
234
|
+
|
|
235
|
+
Search workspace pages and databases by title.
|
|
236
|
+
|
|
237
|
+
**Parameters:**
|
|
238
|
+
- `query` (optional): Search text (omit to return all items)
|
|
239
|
+
- `filter_object` (optional): 'page' or 'data_source'
|
|
240
|
+
- `sort_timestamp` (optional): 'last_edited_time' or 'created_time'
|
|
241
|
+
- `sort_direction` (optional): 'ascending' or 'descending'
|
|
242
|
+
- `page_size` (optional): Results per page (1-100)
|
|
243
|
+
- `start_cursor` (optional): Pagination cursor
|
|
244
|
+
|
|
245
|
+
**Returns:** Paginated list of pages/databases matching search
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### notion_create_comment
|
|
250
|
+
|
|
251
|
+
Add a comment to a page, block, or discussion thread.
|
|
252
|
+
|
|
253
|
+
**Parameters:**
|
|
254
|
+
- `parent` (optional): Object describing the comment target. Provide ONE of:
|
|
255
|
+
- `{ "page_id": "..." }` — comment on a page
|
|
256
|
+
- `{ "block_id": "..." }` — comment on a block
|
|
257
|
+
- omit to reply to a `discussion_id` (use `discussion_id` parameter)
|
|
258
|
+
- `discussion_id` (optional): Discussion thread to reply to (alternative to `parent`)
|
|
259
|
+
- `rich_text` (required): Array of rich text objects representing the comment content
|
|
260
|
+
- `attachments` (optional): Array of file objects to attach to the comment
|
|
261
|
+
- Formatting/annotations should be provided within the `rich_text` objects (bold/italic/code via annotations)
|
|
262
|
+
|
|
263
|
+
**Returns:** Created comment object with `id` and `created_time`
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### notion_get_user
|
|
268
|
+
|
|
269
|
+
Retrieve user information including name, avatar, and email.
|
|
270
|
+
|
|
271
|
+
**Parameters:**
|
|
272
|
+
- `user_id` (required): UUID of user to retrieve
|
|
273
|
+
|
|
274
|
+
**Returns:** User object with `id`, `name`, `avatar_url`, `email`
|
|
275
|
+
|
|
276
|
+
## ⚙️ Environment Variables
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
# Required
|
|
280
|
+
NOTION_API_KEY=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
281
|
+
|
|
282
|
+
# Optional (for OAuth2 - Phase 2)
|
|
283
|
+
NOTION_OAUTH_CLIENT_ID=your_client_id
|
|
284
|
+
NOTION_OAUTH_CLIENT_SECRET=your_client_secret
|
|
285
|
+
NOTION_OAUTH_REDIRECT_URI=https://yourdomain.com/callback
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## 🔧 Troubleshooting
|
|
289
|
+
|
|
290
|
+
### "403 Forbidden" Error
|
|
291
|
+
|
|
292
|
+
**Cause:** Integration lacks required capability or resource not shared.
|
|
293
|
+
|
|
294
|
+
**Solutions:**
|
|
295
|
+
1. Check integration has "Read/Update/Insert content" capabilities in Notion dashboard
|
|
296
|
+
2. Share the database/page with your integration (••• → Add connections → select integration)
|
|
297
|
+
3. Verify token is current (refresh in Notion integrations dashboard)
|
|
298
|
+
|
|
299
|
+
### "404 Not Found" Error
|
|
300
|
+
|
|
301
|
+
**Cause:** Database/page ID is incorrect or integration doesn't have access.
|
|
302
|
+
|
|
303
|
+
**Solutions:**
|
|
304
|
+
1. Verify database ID from Notion URL: `https://www.notion.so/{database_id}`
|
|
305
|
+
2. Ensure resource is shared with integration
|
|
306
|
+
3. Check API key is correct
|
|
307
|
+
|
|
308
|
+
### Filters Not Working
|
|
309
|
+
|
|
310
|
+
**Cause:** Incorrect filter syntax for property type.
|
|
311
|
+
|
|
312
|
+
**Solutions:**
|
|
313
|
+
- Use Notion's property filtering UI as reference
|
|
314
|
+
- Filters depend on property type (status, checkbox, date, etc.)
|
|
315
|
+
- See [Notion Filter Reference](https://developers.notion.com/reference/post-database-query-filter)
|
|
316
|
+
|
|
317
|
+
### Rate Limiting
|
|
318
|
+
|
|
319
|
+
**Info:** Notion API has rate limits (~3-4 requests/second per integration). Implement exponential backoff for production systems.
|
|
320
|
+
|
|
321
|
+
## 📖 Learning Resources
|
|
322
|
+
|
|
323
|
+
- [Notion API Docs](https://developers.notion.com)
|
|
324
|
+
- [Notion Integrations Dashboard](https://www.notion.so/my-integrations)
|
|
325
|
+
- [Working with Databases](https://developers.notion.com/guides/data-apis/working-with-databases)
|
|
326
|
+
- [Creating Pages](https://developers.notion.com/guides/data-apis/working-with-page-content)
|
|
327
|
+
- [Notion Developers Slack](https://join.slack.com/t/notiondevs/shared_invite/zt-20b5996xv-DzJdLiympy6jP0GGzu3AMg)
|
|
328
|
+
|
|
329
|
+
## 🤝 Contributing
|
|
330
|
+
|
|
331
|
+
Found a bug or want to suggest a feature? See [CONTRIBUTING.md](/CONTRIBUTING.md).
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
**Part of the Matimo ecosystem** — Write YAML once, use everywhere.
|
package/definition.yaml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: notion-provider
|
|
2
|
+
type: provider
|
|
3
|
+
version: '1.0.0'
|
|
4
|
+
description: |
|
|
5
|
+
Notion Provider Configuration and authentication metadata.
|
|
6
|
+
This file is used by the OAuth2ProviderLoader to register Notion as an
|
|
7
|
+
OAuth2 provider and to document runtime environment variables.
|
|
8
|
+
|
|
9
|
+
provider:
|
|
10
|
+
name: notion
|
|
11
|
+
displayName: Notion
|
|
12
|
+
endpoints:
|
|
13
|
+
authorizationUrl: https://api.notion.com/v1/oauth/authorize
|
|
14
|
+
tokenUrl: https://api.notion.com/v1/oauth/token
|
|
15
|
+
defaultScopes:
|
|
16
|
+
- read
|
|
17
|
+
- write
|
|
18
|
+
documentation: https://developers.notion.com/docs
|
|
19
|
+
|
|
20
|
+
# Legacy/auxiliary OAuth metadata (kept for backward compatibility with earlier tooling)
|
|
21
|
+
oauth2:
|
|
22
|
+
client_id_env: NOTION_OAUTH_CLIENT_ID
|
|
23
|
+
client_secret_env: NOTION_OAUTH_CLIENT_SECRET
|
|
24
|
+
redirect_uri_env: NOTION_OAUTH_REDIRECT_URI
|
|
25
|
+
|
|
26
|
+
authentication:
|
|
27
|
+
type: bearer
|
|
28
|
+
location: header
|
|
29
|
+
name: Authorization
|
|
30
|
+
|
|
31
|
+
notes:
|
|
32
|
+
env: NOTION_API_KEY
|
|
33
|
+
setup_docs: "https://developers.notion.com/guides/get-started/getting-started"
|
|
34
|
+
caution: "Notion API requires Bearer token authentication. Ensure your integration has the necessary capabilities enabled in the Notion dashboard."
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@matimo/notion",
|
|
3
|
+
"version": "0.1.0-alpha.10",
|
|
4
|
+
"description": "Notion workspace tools for Matimo",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"tools",
|
|
8
|
+
"README.md",
|
|
9
|
+
"definition.yaml"
|
|
10
|
+
],
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"matimo": "0.1.0-alpha.10"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"axios": "^1.13.4",
|
|
16
|
+
"@matimo/core": "0.1.0-alpha.10"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
name: notion_create_comment
|
|
2
|
+
description: Add a comment to a Notion page, block, or discussion thread
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
parameters:
|
|
5
|
+
parent:
|
|
6
|
+
type: object
|
|
7
|
+
required: false
|
|
8
|
+
description: Parent target - provide one of page_id, block_id, or neither if using discussion_id
|
|
9
|
+
discussion_id:
|
|
10
|
+
type: string
|
|
11
|
+
required: false
|
|
12
|
+
description: The ID of existing discussion thread to respond to (alternative to parent)
|
|
13
|
+
rich_text:
|
|
14
|
+
type: array
|
|
15
|
+
required: true
|
|
16
|
+
description: Array of rich text objects representing comment content
|
|
17
|
+
attachments:
|
|
18
|
+
type: array
|
|
19
|
+
required: false
|
|
20
|
+
description: Array of file objects to attach to comment (max 3 allowed)
|
|
21
|
+
display_name:
|
|
22
|
+
type: object
|
|
23
|
+
required: false
|
|
24
|
+
description: Display name configuration for the comment author
|
|
25
|
+
|
|
26
|
+
execution:
|
|
27
|
+
type: http
|
|
28
|
+
method: POST
|
|
29
|
+
url: "https://api.notion.com/v1/comments"
|
|
30
|
+
headers:
|
|
31
|
+
Authorization: "Bearer {NOTION_API_KEY}"
|
|
32
|
+
"Notion-Version": "2025-09-03"
|
|
33
|
+
Content-Type: application/json
|
|
34
|
+
body:
|
|
35
|
+
parent: "{parent}"
|
|
36
|
+
discussion_id: "{discussion_id}"
|
|
37
|
+
rich_text: "{rich_text}"
|
|
38
|
+
attachments: "{attachments}"
|
|
39
|
+
display_name: "{display_name}"
|
|
40
|
+
timeout: 15000
|
|
41
|
+
|
|
42
|
+
authentication:
|
|
43
|
+
type: bearer
|
|
44
|
+
location: header
|
|
45
|
+
name: Authorization
|
|
46
|
+
notes:
|
|
47
|
+
env: NOTION_API_KEY
|
|
48
|
+
caution: "Ensure 'Insert comments' capability is enabled. Either page_id, block_id, or discussion_id required. Cannot start new inline discussions via API - must respond to existing threads or comment on pages/blocks."
|
|
49
|
+
|
|
50
|
+
output_schema:
|
|
51
|
+
type: object
|
|
52
|
+
properties:
|
|
53
|
+
object:
|
|
54
|
+
type: string
|
|
55
|
+
id:
|
|
56
|
+
type: string
|
|
57
|
+
created_time:
|
|
58
|
+
type: string
|
|
59
|
+
last_edited_time:
|
|
60
|
+
type: string
|
|
61
|
+
rich_text:
|
|
62
|
+
type: array
|
|
63
|
+
parent:
|
|
64
|
+
type: object
|
|
65
|
+
required: ["object", "id"]
|
|
66
|
+
|
|
67
|
+
examples:
|
|
68
|
+
- name: "Comment on page with simple text"
|
|
69
|
+
params:
|
|
70
|
+
parent:
|
|
71
|
+
page_id: be633bf1-dfa0-436d-b259-571129a590e5
|
|
72
|
+
rich_text:
|
|
73
|
+
- type: text
|
|
74
|
+
text:
|
|
75
|
+
content: "This looks great! Consider adding more examples."
|
|
76
|
+
expected_result: "Comment posted on the page"
|
|
77
|
+
- name: "Reply to discussion thread"
|
|
78
|
+
params:
|
|
79
|
+
discussion_id: "discussion-thread-id"
|
|
80
|
+
rich_text:
|
|
81
|
+
- type: text
|
|
82
|
+
text:
|
|
83
|
+
content: "I agree with this suggestion"
|
|
84
|
+
annotations:
|
|
85
|
+
bold: true
|
|
86
|
+
expected_result: "Reply added to existing discussion thread"
|
|
87
|
+
- name: "Comment on block with attachment"
|
|
88
|
+
params:
|
|
89
|
+
parent:
|
|
90
|
+
block_id: block-id-uuid
|
|
91
|
+
rich_text:
|
|
92
|
+
- type: text
|
|
93
|
+
text:
|
|
94
|
+
content: "Attached document:"
|
|
95
|
+
attachments:
|
|
96
|
+
- url: https://example.com/document.pdf
|
|
97
|
+
expected_result: "Comment posted on block with file attachment"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
name: notion_create_page
|
|
2
|
+
description: Create a new page in a Notion database or as a child of an existing page
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
parameters:
|
|
5
|
+
parent:
|
|
6
|
+
type: object
|
|
7
|
+
required: true
|
|
8
|
+
description: |
|
|
9
|
+
Where to create the page. Provide ONE of:
|
|
10
|
+
- {"database_id": "..."} to create in a database
|
|
11
|
+
- {"page_id": "..."} to create as a sub-page
|
|
12
|
+
Get database_id from notion_list_databases.
|
|
13
|
+
properties:
|
|
14
|
+
type: object
|
|
15
|
+
required: false
|
|
16
|
+
description: |
|
|
17
|
+
Optional page properties (title, fields, etc).
|
|
18
|
+
Properties must match the parent database schema.
|
|
19
|
+
Simpler: just use 'markdown' parameter instead for content.
|
|
20
|
+
icon:
|
|
21
|
+
type: object
|
|
22
|
+
required: false
|
|
23
|
+
description: Page icon - object with type (emoji, external, file) and icon content
|
|
24
|
+
cover:
|
|
25
|
+
type: object
|
|
26
|
+
required: false
|
|
27
|
+
description: Page cover image - object with type (file, external) and image details
|
|
28
|
+
children:
|
|
29
|
+
type: array
|
|
30
|
+
required: false
|
|
31
|
+
description: Array of block objects to add to the page. Max 100 items
|
|
32
|
+
markdown:
|
|
33
|
+
type: string
|
|
34
|
+
required: false
|
|
35
|
+
description: |
|
|
36
|
+
Page content using Markdown syntax. Simple and works anywhere.
|
|
37
|
+
Example: "# My Title\n\nSome content here"
|
|
38
|
+
EASIEST WAY TO ADD CONTENT - use this instead of 'properties' for simplicity.
|
|
39
|
+
template:
|
|
40
|
+
type: object
|
|
41
|
+
required: false
|
|
42
|
+
description: Template to use for the page. Specify type and optional template_id
|
|
43
|
+
position:
|
|
44
|
+
type: object
|
|
45
|
+
required: false
|
|
46
|
+
description: Position of page in parent. Can specify before_id or after_id
|
|
47
|
+
|
|
48
|
+
execution:
|
|
49
|
+
type: function
|
|
50
|
+
code: './index.ts'
|
|
51
|
+
|
|
52
|
+
authentication:
|
|
53
|
+
type: bearer
|
|
54
|
+
location: header
|
|
55
|
+
name: Authorization
|
|
56
|
+
notes:
|
|
57
|
+
env: NOTION_API_KEY
|
|
58
|
+
caution: "Ensure 'Insert content' capability is enabled on the parent. Properties must match parent database schema. For database parents, properties are required. For page parents, only title is supported via properties. Either children or markdown can be used, not both. When using template, children parameter is not allowed."
|
|
59
|
+
|
|
60
|
+
output_schema:
|
|
61
|
+
type: object
|
|
62
|
+
properties:
|
|
63
|
+
object:
|
|
64
|
+
type: string
|
|
65
|
+
id:
|
|
66
|
+
type: string
|
|
67
|
+
created_time:
|
|
68
|
+
type: string
|
|
69
|
+
last_edited_time:
|
|
70
|
+
type: string
|
|
71
|
+
archived:
|
|
72
|
+
type: boolean
|
|
73
|
+
in_trash:
|
|
74
|
+
type: boolean
|
|
75
|
+
is_locked:
|
|
76
|
+
type: boolean
|
|
77
|
+
url:
|
|
78
|
+
type: string
|
|
79
|
+
public_url:
|
|
80
|
+
type: string
|
|
81
|
+
parent:
|
|
82
|
+
type: object
|
|
83
|
+
properties:
|
|
84
|
+
type: object
|
|
85
|
+
icon:
|
|
86
|
+
type: object
|
|
87
|
+
cover:
|
|
88
|
+
type: object
|
|
89
|
+
required: ["object", "id", "url"]
|
|
90
|
+
|
|
91
|
+
examples:
|
|
92
|
+
- name: "Create page in database"
|
|
93
|
+
params:
|
|
94
|
+
parent:
|
|
95
|
+
database_id: a1d8501e-1ac1-43e9-a6bd-ea9fe6c8822b
|
|
96
|
+
properties:
|
|
97
|
+
Name:
|
|
98
|
+
title:
|
|
99
|
+
- text:
|
|
100
|
+
content: "New Page"
|
|
101
|
+
expected_result: "Creates a new page in the database with the specified properties"
|
|
102
|
+
- name: "Create page under existing page"
|
|
103
|
+
params:
|
|
104
|
+
parent:
|
|
105
|
+
page_id: be633bf1-dfa0-436d-b259-571129a590e5
|
|
106
|
+
children:
|
|
107
|
+
- object: block
|
|
108
|
+
type: paragraph
|
|
109
|
+
paragraph:
|
|
110
|
+
rich_text:
|
|
111
|
+
- type: text
|
|
112
|
+
text:
|
|
113
|
+
content: "Page content"
|
|
114
|
+
expected_result: "Creates a subpage with content blocks"
|
|
115
|
+
- name: "Create page with emoji icon"
|
|
116
|
+
params:
|
|
117
|
+
parent:
|
|
118
|
+
database_id: a1d8501e-1ac1-43e9-a6bd-ea9fe6c8822b
|
|
119
|
+
properties:
|
|
120
|
+
Name:
|
|
121
|
+
title:
|
|
122
|
+
- text:
|
|
123
|
+
content: "Task"
|
|
124
|
+
icon:
|
|
125
|
+
type: emoji
|
|
126
|
+
emoji: "✅"
|
|
127
|
+
expected_result: "Creates a page with an emoji icon"
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { MatimoError, ErrorCode } from '@matimo/core';
|
|
3
|
+
|
|
4
|
+
interface Params {
|
|
5
|
+
parent?: Record<string, unknown>;
|
|
6
|
+
properties?: Record<string, unknown>;
|
|
7
|
+
icon?: Record<string, unknown>;
|
|
8
|
+
cover?: Record<string, unknown>;
|
|
9
|
+
children?: unknown[];
|
|
10
|
+
markdown?: string;
|
|
11
|
+
template?: Record<string, unknown>;
|
|
12
|
+
position?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function markdownToChildren(md: string): unknown[] {
|
|
16
|
+
// Very small converter: split paragraphs and handle headings (#, ##, ###)
|
|
17
|
+
const parts = md.split(/\n\n+/).map((p) => p.trim()).filter(Boolean);
|
|
18
|
+
const blocks: unknown[] = [];
|
|
19
|
+
|
|
20
|
+
for (const part of parts) {
|
|
21
|
+
if (part.startsWith('# ')) {
|
|
22
|
+
blocks.push({
|
|
23
|
+
object: 'block',
|
|
24
|
+
type: 'heading_1',
|
|
25
|
+
heading_1: { rich_text: [{ type: 'text', text: { content: part.replace(/^#\s+/, '') } }] },
|
|
26
|
+
});
|
|
27
|
+
} else if (part.startsWith('## ')) {
|
|
28
|
+
blocks.push({
|
|
29
|
+
object: 'block',
|
|
30
|
+
type: 'heading_2',
|
|
31
|
+
heading_2: { rich_text: [{ type: 'text', text: { content: part.replace(/^##\s+/, '') } }] },
|
|
32
|
+
});
|
|
33
|
+
} else if (part.startsWith('### ')) {
|
|
34
|
+
blocks.push({
|
|
35
|
+
object: 'block',
|
|
36
|
+
type: 'heading_3',
|
|
37
|
+
heading_3: { rich_text: [{ type: 'text', text: { content: part.replace(/^###\s+/, '') } }] },
|
|
38
|
+
});
|
|
39
|
+
} else {
|
|
40
|
+
blocks.push({
|
|
41
|
+
object: 'block',
|
|
42
|
+
type: 'paragraph',
|
|
43
|
+
paragraph: { rich_text: [{ type: 'text', text: { content: part } }] },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return blocks;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default async function createPage(params: Params) {
|
|
52
|
+
const {
|
|
53
|
+
parent: userProvidedParent,
|
|
54
|
+
properties,
|
|
55
|
+
icon,
|
|
56
|
+
cover,
|
|
57
|
+
children,
|
|
58
|
+
markdown,
|
|
59
|
+
template,
|
|
60
|
+
position,
|
|
61
|
+
} = params as Params;
|
|
62
|
+
|
|
63
|
+
const apiKey = process.env.NOTION_API_KEY;
|
|
64
|
+
if (!apiKey) {
|
|
65
|
+
throw new MatimoError('NOTION_API_KEY not set', ErrorCode.AUTH_FAILED, {
|
|
66
|
+
envVar: 'NOTION_API_KEY',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// If no parent provided, auto-discover a database
|
|
71
|
+
let parent = userProvidedParent;
|
|
72
|
+
if (!parent || typeof parent !== 'object') {
|
|
73
|
+
try {
|
|
74
|
+
const response = await axios.get('https://api.notion.com/v1/databases', {
|
|
75
|
+
headers: {
|
|
76
|
+
Authorization: `Bearer ${apiKey}`,
|
|
77
|
+
'Notion-Version': '2025-09-03',
|
|
78
|
+
},
|
|
79
|
+
timeout: 15000,
|
|
80
|
+
params: { page_size: 1 },
|
|
81
|
+
});
|
|
82
|
+
const databases = response.data?.results || [];
|
|
83
|
+
if (databases.length > 0) {
|
|
84
|
+
parent = { database_id: databases[0].id };
|
|
85
|
+
} else {
|
|
86
|
+
throw new MatimoError(
|
|
87
|
+
'No databases found in workspace. Create a database first or provide `parent` parameter.',
|
|
88
|
+
ErrorCode.VALIDATION_FAILED
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
if (axios.isAxiosError(err)) {
|
|
93
|
+
throw new MatimoError(
|
|
94
|
+
`Failed to auto-discover database: ${(err.response?.data as Record<string, unknown>)?.message || err.message}`,
|
|
95
|
+
ErrorCode.EXECUTION_FAILED
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
throw new MatimoError('Failed to auto-discover database', ErrorCode.EXECUTION_FAILED);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Validate parameters according to tool contract:
|
|
103
|
+
// - If creating inside a database (`parent.database_id`), `properties` is required
|
|
104
|
+
// - Either `children` or `markdown` can be provided, not both (empty children array is treated as not provided)
|
|
105
|
+
// - When using `template`, `children` is not allowed
|
|
106
|
+
const isDatabaseParent = parent && typeof parent === 'object' && Object.prototype.hasOwnProperty.call(parent, 'database_id');
|
|
107
|
+
|
|
108
|
+
if (Array.isArray(children) && children.length > 0 && typeof markdown === 'string' && markdown.trim().length > 0) {
|
|
109
|
+
throw new MatimoError('Provide either `children` or `markdown`, not both', ErrorCode.VALIDATION_FAILED, {
|
|
110
|
+
parameters: { children: children.length, markdown: markdown.length },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (template && Array.isArray(children) && children.length > 0) {
|
|
115
|
+
throw new MatimoError('`template` cannot be used together with `children`. Omit `children` when using `template`', ErrorCode.VALIDATION_FAILED, {
|
|
116
|
+
parameters: { template: !!template, children: children.length },
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Allow generating a minimal title property from `markdown` when creating in a database.
|
|
121
|
+
// If caller didn't provide `properties`, we'll attempt several common title property names
|
|
122
|
+
// (e.g., 'Name', 'Title') derived from the first markdown line. If none succeed,
|
|
123
|
+
// we return the API error to the caller.
|
|
124
|
+
const resolvedProperties = properties as Record<string, unknown> | undefined;
|
|
125
|
+
let titleCandidates: string[] | undefined;
|
|
126
|
+
|
|
127
|
+
if (isDatabaseParent) {
|
|
128
|
+
const hasProperties = resolvedProperties && typeof resolvedProperties === 'object' && Object.keys(resolvedProperties).length > 0;
|
|
129
|
+
|
|
130
|
+
if (!hasProperties) {
|
|
131
|
+
if (typeof markdown === 'string' && markdown.trim().length > 0) {
|
|
132
|
+
// Candidate property names to try when the database title property name is unknown
|
|
133
|
+
titleCandidates = ['Name', 'Title', 'title', 'name'].map((k) => k);
|
|
134
|
+
|
|
135
|
+
// We'll construct properties later per candidate when sending the request.
|
|
136
|
+
// Use resolvedProperties only if caller provided it explicitly.
|
|
137
|
+
} else {
|
|
138
|
+
throw new MatimoError('Creating a page in a database requires `properties` (at minimum a title property)', ErrorCode.VALIDATION_FAILED, {
|
|
139
|
+
parent,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Convert markdown to children if provided and children not explicitly set
|
|
146
|
+
let resolvedChildren = children;
|
|
147
|
+
if ((!resolvedChildren || (Array.isArray(resolvedChildren) && resolvedChildren.length === 0)) && markdown) {
|
|
148
|
+
resolvedChildren = markdownToChildren(markdown);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const baseBody: Record<string, unknown> = {
|
|
152
|
+
parent,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (resolvedProperties) baseBody.properties = resolvedProperties;
|
|
156
|
+
if (icon) baseBody.icon = icon;
|
|
157
|
+
if (cover) baseBody.cover = cover;
|
|
158
|
+
if (resolvedChildren) baseBody.children = resolvedChildren;
|
|
159
|
+
if (template) baseBody.template = template;
|
|
160
|
+
if (position) baseBody.position = position;
|
|
161
|
+
|
|
162
|
+
// Helper to send request with a given body
|
|
163
|
+
const sendRequest = async (requestBody: Record<string, unknown>) => {
|
|
164
|
+
return axios.post('https://api.notion.com/v1/pages', requestBody, {
|
|
165
|
+
headers: {
|
|
166
|
+
Authorization: `Bearer ${apiKey}`,
|
|
167
|
+
'Notion-Version': '2025-09-03',
|
|
168
|
+
'Content-Type': 'application/json',
|
|
169
|
+
},
|
|
170
|
+
timeout: 15000,
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// If we have title candidates, try each one until a request succeeds.
|
|
175
|
+
if (titleCandidates && titleCandidates.length > 0) {
|
|
176
|
+
let lastError: unknown = null;
|
|
177
|
+
const firstLine = markdown!.split(/\r?\n/)[0].replace(/^#+\s*/, '').trim() || 'New Page';
|
|
178
|
+
|
|
179
|
+
for (const candidate of titleCandidates) {
|
|
180
|
+
const candidateProps: Record<string, unknown> = {
|
|
181
|
+
[candidate]: {
|
|
182
|
+
title: [
|
|
183
|
+
{
|
|
184
|
+
text: { content: firstLine },
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const tryBody = { ...baseBody, ...{ properties: candidateProps } } as Record<string, unknown>;
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const resp = await sendRequest(tryBody);
|
|
194
|
+
return {
|
|
195
|
+
success: true,
|
|
196
|
+
statusCode: resp.status,
|
|
197
|
+
data: resp.data,
|
|
198
|
+
};
|
|
199
|
+
} catch (err: unknown) {
|
|
200
|
+
lastError = err;
|
|
201
|
+
// If API returns validation error about missing property name, continue to next candidate.
|
|
202
|
+
if (axios.isAxiosError(err)) {
|
|
203
|
+
type NotionError = { message?: string; code?: string; request_id?: string };
|
|
204
|
+
const errData = err.response?.data as NotionError | undefined;
|
|
205
|
+
const message = errData?.message || '';
|
|
206
|
+
if (typeof message === 'string' && /is not a property that exists/i.test(message)) {
|
|
207
|
+
// try next candidate
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// For other errors, break and return immediately
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// All candidates failed — return last error in a structured form
|
|
217
|
+
if (axios.isAxiosError(lastError)) {
|
|
218
|
+
type NotionError = { message?: string; code?: string; request_id?: string };
|
|
219
|
+
const errData = lastError.response?.data as NotionError | undefined;
|
|
220
|
+
const statusCode = lastError.response?.status || 0;
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
statusCode,
|
|
224
|
+
error: errData || (lastError as Error).message,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
statusCode: 0,
|
|
231
|
+
error: String(lastError),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// No candidate loop — send single request using baseBody (which may include provided properties)
|
|
236
|
+
try {
|
|
237
|
+
const resp = await sendRequest(baseBody);
|
|
238
|
+
return {
|
|
239
|
+
success: true,
|
|
240
|
+
statusCode: resp.status,
|
|
241
|
+
data: resp.data,
|
|
242
|
+
};
|
|
243
|
+
} catch (err: unknown) {
|
|
244
|
+
if (axios.isAxiosError(err)) {
|
|
245
|
+
// Wrap HTTP error from Notion in a MatimoError so callers can programmatically inspect it
|
|
246
|
+
type NotionError = { message?: string; code?: string; request_id?: string };
|
|
247
|
+
const errData = err.response?.data as NotionError | undefined;
|
|
248
|
+
const details: Record<string, unknown> = {
|
|
249
|
+
status: err.response?.status,
|
|
250
|
+
code: errData?.code,
|
|
251
|
+
request_id: errData?.request_id,
|
|
252
|
+
};
|
|
253
|
+
throw new MatimoError(errData?.message || 'Notion API error', ErrorCode.EXECUTION_FAILED, details);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Non-HTTP error (network, unexpected) — wrap and throw
|
|
257
|
+
throw new MatimoError(String(err), ErrorCode.UNKNOWN_ERROR);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: notion_get_user
|
|
2
|
+
description: Retrieve information about a Notion user
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
parameters:
|
|
5
|
+
user_id:
|
|
6
|
+
type: string
|
|
7
|
+
required: true
|
|
8
|
+
description: The UUID of the user to retrieve
|
|
9
|
+
|
|
10
|
+
execution:
|
|
11
|
+
type: http
|
|
12
|
+
method: GET
|
|
13
|
+
url: "https://api.notion.com/v1/users/{user_id}"
|
|
14
|
+
headers:
|
|
15
|
+
Authorization: "Bearer {NOTION_API_KEY}"
|
|
16
|
+
"Notion-Version": "2025-09-03"
|
|
17
|
+
timeout: 10000
|
|
18
|
+
|
|
19
|
+
authentication:
|
|
20
|
+
type: bearer
|
|
21
|
+
location: header
|
|
22
|
+
name: Authorization
|
|
23
|
+
notes:
|
|
24
|
+
env: NOTION_API_KEY
|
|
25
|
+
caution: "Ensure 'Read user information' capability is enabled. Returns user details including name, avatar, email (if available). User IDs can be obtained from page.created_by, page.last_edited_by, or database results."
|
|
26
|
+
|
|
27
|
+
output_schema:
|
|
28
|
+
type: object
|
|
29
|
+
properties:
|
|
30
|
+
object:
|
|
31
|
+
type: string
|
|
32
|
+
id:
|
|
33
|
+
type: string
|
|
34
|
+
type:
|
|
35
|
+
type: string
|
|
36
|
+
name:
|
|
37
|
+
type: string
|
|
38
|
+
avatar_url:
|
|
39
|
+
type: string
|
|
40
|
+
person:
|
|
41
|
+
type: object
|
|
42
|
+
properties:
|
|
43
|
+
email:
|
|
44
|
+
type: string
|
|
45
|
+
required: ["object", "id", "type"]
|
|
46
|
+
|
|
47
|
+
examples:
|
|
48
|
+
- name: "Get user information"
|
|
49
|
+
params:
|
|
50
|
+
user_id: "e79a0b74-3aba-4149-9f74-0bb5791a6ee6"
|
|
51
|
+
expected_result: "Returns user details with name, avatar, email"
|
|
52
|
+
- name: "Get bot user info"
|
|
53
|
+
params:
|
|
54
|
+
user_id: "c2f20311-9e54-4d11-8c79-7398424ae41e"
|
|
55
|
+
expected_result: "Returns bot/integration user information"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
name: notion_list_databases
|
|
2
|
+
description: |
|
|
3
|
+
List all databases (data sources) available in your Notion workspace.
|
|
4
|
+
Use this to discover what databases exist before querying them.
|
|
5
|
+
Each database has an id, title, icon, and URL that you can use for further operations.
|
|
6
|
+
version: "1.0.0"
|
|
7
|
+
|
|
8
|
+
parameters:
|
|
9
|
+
page_size:
|
|
10
|
+
type: number
|
|
11
|
+
required: true
|
|
12
|
+
description: How many databases to return (1-100). Set this explicitly to avoid sending a literal placeholder when omitted.
|
|
13
|
+
|
|
14
|
+
execution:
|
|
15
|
+
type: http
|
|
16
|
+
method: POST
|
|
17
|
+
url: "https://api.notion.com/v1/search"
|
|
18
|
+
headers:
|
|
19
|
+
Authorization: "Bearer {NOTION_API_KEY}"
|
|
20
|
+
"Notion-Version": "2025-09-03"
|
|
21
|
+
Content-Type: application/json
|
|
22
|
+
body:
|
|
23
|
+
filter:
|
|
24
|
+
property: object
|
|
25
|
+
value: data_source
|
|
26
|
+
page_size: "{page_size}"
|
|
27
|
+
timeout: 15000
|
|
28
|
+
|
|
29
|
+
authentication:
|
|
30
|
+
type: bearer
|
|
31
|
+
location: header
|
|
32
|
+
name: Authorization
|
|
33
|
+
notes:
|
|
34
|
+
env: NOTION_API_KEY
|
|
35
|
+
caution: "Lists only databases shared with your integration. Respects integration's read capabilities."
|
|
36
|
+
|
|
37
|
+
output_schema:
|
|
38
|
+
type: object
|
|
39
|
+
properties:
|
|
40
|
+
object:
|
|
41
|
+
type: string
|
|
42
|
+
results:
|
|
43
|
+
type: array
|
|
44
|
+
items:
|
|
45
|
+
type: object
|
|
46
|
+
properties:
|
|
47
|
+
id:
|
|
48
|
+
type: string
|
|
49
|
+
title:
|
|
50
|
+
type: array
|
|
51
|
+
icon:
|
|
52
|
+
type: object
|
|
53
|
+
url:
|
|
54
|
+
type: string
|
|
55
|
+
has_more:
|
|
56
|
+
type: boolean
|
|
57
|
+
next_cursor:
|
|
58
|
+
type:
|
|
59
|
+
- string
|
|
60
|
+
- "null"
|
|
61
|
+
|
|
62
|
+
examples:
|
|
63
|
+
- name: "List all databases in workspace"
|
|
64
|
+
params:
|
|
65
|
+
page_size: 10
|
|
66
|
+
expected_result: "Returns array of database objects with id, title, icon, and url"
|
|
67
|
+
- name: "List first database only"
|
|
68
|
+
params:
|
|
69
|
+
page_size: 1
|
|
70
|
+
expected_result: "Returns single database object"
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
name: notion_query_database
|
|
2
|
+
description: Query pages from a Notion database to retrieve content. Use notion_list_databases first to get the database ID.
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
parameters:
|
|
5
|
+
database_id:
|
|
6
|
+
type: string
|
|
7
|
+
required: true
|
|
8
|
+
description: The ID of the database to query. Get from notion_list_databases (item.id)
|
|
9
|
+
sorts:
|
|
10
|
+
type: array
|
|
11
|
+
required: false
|
|
12
|
+
description: Array of sort objects to order results by properties or timestamps
|
|
13
|
+
filter:
|
|
14
|
+
type: object
|
|
15
|
+
required: false
|
|
16
|
+
description: Filter criteria as JSON object to narrow results
|
|
17
|
+
page_size:
|
|
18
|
+
type: number
|
|
19
|
+
required: false
|
|
20
|
+
description: Number of results per request (default 100, max 100)
|
|
21
|
+
start_cursor:
|
|
22
|
+
type: string
|
|
23
|
+
required: false
|
|
24
|
+
description: Cursor for pagination to retrieve next set of results
|
|
25
|
+
archived:
|
|
26
|
+
type: boolean
|
|
27
|
+
required: false
|
|
28
|
+
description: If true, include archived pages in results
|
|
29
|
+
in_trash:
|
|
30
|
+
type: boolean
|
|
31
|
+
required: false
|
|
32
|
+
description: If true, include pages in trash in results
|
|
33
|
+
result_type:
|
|
34
|
+
type: string
|
|
35
|
+
required: false
|
|
36
|
+
description: Filter results by type - page or data_source (for wikis only)
|
|
37
|
+
|
|
38
|
+
execution:
|
|
39
|
+
type: http
|
|
40
|
+
method: POST
|
|
41
|
+
url: "https://api.notion.com/v1/data_sources/{database_id}/query"
|
|
42
|
+
headers:
|
|
43
|
+
Authorization: "Bearer {NOTION_API_KEY}"
|
|
44
|
+
"Notion-Version": "2025-09-03"
|
|
45
|
+
Content-Type: application/json
|
|
46
|
+
body:
|
|
47
|
+
sorts: "{sorts}"
|
|
48
|
+
filter: "{filter}"
|
|
49
|
+
page_size: "{page_size}"
|
|
50
|
+
start_cursor: "{start_cursor}"
|
|
51
|
+
archived: "{archived}"
|
|
52
|
+
in_trash: "{in_trash}"
|
|
53
|
+
result_type: "{result_type}"
|
|
54
|
+
timeout: 15000
|
|
55
|
+
|
|
56
|
+
authentication:
|
|
57
|
+
type: bearer
|
|
58
|
+
location: header
|
|
59
|
+
name: Authorization
|
|
60
|
+
notes:
|
|
61
|
+
env: NOTION_API_KEY
|
|
62
|
+
api_version: "2025-09-03"
|
|
63
|
+
caution: "Uses current Notion API (2025-09-03). Ensure 'Read content' capability is enabled on the integration. Filter and sort are optional - omit if not needed. API returns max 100 items per call."
|
|
64
|
+
|
|
65
|
+
output_schema:
|
|
66
|
+
type: object
|
|
67
|
+
properties:
|
|
68
|
+
object:
|
|
69
|
+
type: string
|
|
70
|
+
type:
|
|
71
|
+
type: string
|
|
72
|
+
results:
|
|
73
|
+
type: array
|
|
74
|
+
has_more:
|
|
75
|
+
type: boolean
|
|
76
|
+
next_cursor:
|
|
77
|
+
type: string
|
|
78
|
+
required: ["object", "results", "has_more"]
|
|
79
|
+
|
|
80
|
+
examples:
|
|
81
|
+
- name: "Query data source - all pages"
|
|
82
|
+
params:
|
|
83
|
+
database_id: "d9824bdc-8445-4327-be8b-5b47500af6ce"
|
|
84
|
+
expected_result: "Returns paginated list of all pages in the database"
|
|
85
|
+
- name: "Query data source - with filter"
|
|
86
|
+
params:
|
|
87
|
+
database_id: "d9824bdc-8445-4327-be8b-5b47500af6ce"
|
|
88
|
+
filter:
|
|
89
|
+
property: Status
|
|
90
|
+
status:
|
|
91
|
+
equals: Done
|
|
92
|
+
expected_result: "Returns pages where the Status property equals 'Done'"
|
|
93
|
+
- name: "Query data source - with sorting"
|
|
94
|
+
params:
|
|
95
|
+
database_id: "d9824bdc-8445-4327-be8b-5b47500af6ce"
|
|
96
|
+
sorts:
|
|
97
|
+
- property: Created
|
|
98
|
+
direction: descending
|
|
99
|
+
page_size: 25
|
|
100
|
+
expected_result: "Returns up to 25 pages sorted by creation date (descending)"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
name: notion_search
|
|
2
|
+
description: Search across all pages and data sources in Notion workspace by title
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
parameters:
|
|
5
|
+
query:
|
|
6
|
+
type: string
|
|
7
|
+
required: false
|
|
8
|
+
description: Search text to find in page/data_source titles - omit to return all shared items
|
|
9
|
+
filter_object:
|
|
10
|
+
type: object
|
|
11
|
+
required: false
|
|
12
|
+
description: Filter results by object type - page or data_source
|
|
13
|
+
sort_direction:
|
|
14
|
+
type: string
|
|
15
|
+
required: false
|
|
16
|
+
description: Sort direction - ascending or descending
|
|
17
|
+
sort_timestamp:
|
|
18
|
+
type: string
|
|
19
|
+
required: false
|
|
20
|
+
description: Sort by timestamp - last_edited_time (default) or created_time
|
|
21
|
+
page_size:
|
|
22
|
+
type: number
|
|
23
|
+
required: false
|
|
24
|
+
description: Number of results per request
|
|
25
|
+
start_cursor:
|
|
26
|
+
type: string
|
|
27
|
+
required: false
|
|
28
|
+
description: Cursor for pagination to retrieve next set of results
|
|
29
|
+
|
|
30
|
+
execution:
|
|
31
|
+
type: http
|
|
32
|
+
method: POST
|
|
33
|
+
url: "https://api.notion.com/v1/search"
|
|
34
|
+
headers:
|
|
35
|
+
Authorization: "Bearer {NOTION_API_KEY}"
|
|
36
|
+
"Notion-Version": "2025-09-03"
|
|
37
|
+
Content-Type: application/json
|
|
38
|
+
body:
|
|
39
|
+
query: "{query}"
|
|
40
|
+
filter: "{filter_object}"
|
|
41
|
+
sort:
|
|
42
|
+
direction: "{sort_direction}"
|
|
43
|
+
timestamp: "{sort_timestamp}"
|
|
44
|
+
page_size: "{page_size}"
|
|
45
|
+
start_cursor: "{start_cursor}"
|
|
46
|
+
timeout: 15000
|
|
47
|
+
|
|
48
|
+
authentication:
|
|
49
|
+
type: bearer
|
|
50
|
+
location: header
|
|
51
|
+
name: Authorization
|
|
52
|
+
notes:
|
|
53
|
+
env: NOTION_API_KEY
|
|
54
|
+
caution: "Omit 'query' parameter to return all pages/data sources shared with integration. Filter and sort are optional. Results respect integration's read capabilities. API version 2025-09-03."
|
|
55
|
+
|
|
56
|
+
output_schema:
|
|
57
|
+
type: object
|
|
58
|
+
properties:
|
|
59
|
+
object:
|
|
60
|
+
type: string
|
|
61
|
+
type:
|
|
62
|
+
type: string
|
|
63
|
+
page_or_data_source:
|
|
64
|
+
type: object
|
|
65
|
+
results:
|
|
66
|
+
type: array
|
|
67
|
+
has_more:
|
|
68
|
+
type: boolean
|
|
69
|
+
next_cursor:
|
|
70
|
+
type: string
|
|
71
|
+
required: ["object", "type", "results", "has_more"]
|
|
72
|
+
|
|
73
|
+
examples:
|
|
74
|
+
- name: "Search for pages by title"
|
|
75
|
+
params:
|
|
76
|
+
query: "meeting notes"
|
|
77
|
+
expected_result: "Returns all pages with 'meeting notes' in title"
|
|
78
|
+
- name: "Search data sources only"
|
|
79
|
+
params:
|
|
80
|
+
filter_object: "data_source"
|
|
81
|
+
sort_timestamp: "last_edited_time"
|
|
82
|
+
sort_direction: "descending"
|
|
83
|
+
expected_result: "Returns recently edited data sources only"
|
|
84
|
+
- name: "Get all shared items"
|
|
85
|
+
params:
|
|
86
|
+
page_size: 50
|
|
87
|
+
expected_result: "Returns first 50 pages and data sources shared with integration"
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
name: notion_update_page
|
|
2
|
+
description: Update properties, icon, cover, or other attributes of an existing Notion page
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
parameters:
|
|
5
|
+
page_id:
|
|
6
|
+
type: string
|
|
7
|
+
required: true
|
|
8
|
+
description: The ID of the page to update (UUID format, dashes optional)
|
|
9
|
+
properties:
|
|
10
|
+
type: object
|
|
11
|
+
required: false
|
|
12
|
+
description: Page properties to update as JSON object - must match parent data source schema
|
|
13
|
+
icon:
|
|
14
|
+
type: object
|
|
15
|
+
required: false
|
|
16
|
+
description: Page icon object with type and content (emoji, external URL, or file)
|
|
17
|
+
cover:
|
|
18
|
+
type: object
|
|
19
|
+
required: false
|
|
20
|
+
description: Page cover image object with type and file/external URL details
|
|
21
|
+
is_locked:
|
|
22
|
+
type: boolean
|
|
23
|
+
required: false
|
|
24
|
+
description: Whether to lock page from editing in Notion UI
|
|
25
|
+
template:
|
|
26
|
+
type: object
|
|
27
|
+
required: false
|
|
28
|
+
description: Template object to apply - type default or template_id with specific template ID
|
|
29
|
+
erase_content:
|
|
30
|
+
type: boolean
|
|
31
|
+
required: false
|
|
32
|
+
description: Whether to erase all existing page content (use with template to replace content)
|
|
33
|
+
archived:
|
|
34
|
+
type: boolean
|
|
35
|
+
required: false
|
|
36
|
+
description: Whether to archive or restore the page
|
|
37
|
+
in_trash:
|
|
38
|
+
type: boolean
|
|
39
|
+
required: false
|
|
40
|
+
description: Whether to move page to trash or restore it
|
|
41
|
+
|
|
42
|
+
execution:
|
|
43
|
+
type: http
|
|
44
|
+
method: PATCH
|
|
45
|
+
url: "https://api.notion.com/v1/pages/{page_id}"
|
|
46
|
+
headers:
|
|
47
|
+
Authorization: "Bearer {NOTION_API_KEY}"
|
|
48
|
+
"Notion-Version": "2025-09-03"
|
|
49
|
+
Content-Type: application/json
|
|
50
|
+
body:
|
|
51
|
+
properties: "{properties}"
|
|
52
|
+
icon: "{icon}"
|
|
53
|
+
cover: "{cover}"
|
|
54
|
+
is_locked: "{is_locked}"
|
|
55
|
+
template: "{template}"
|
|
56
|
+
erase_content: "{erase_content}"
|
|
57
|
+
archived: "{archived}"
|
|
58
|
+
in_trash: "{in_trash}"
|
|
59
|
+
timeout: 15000
|
|
60
|
+
|
|
61
|
+
authentication:
|
|
62
|
+
type: bearer
|
|
63
|
+
location: header
|
|
64
|
+
name: Authorization
|
|
65
|
+
notes:
|
|
66
|
+
env: NOTION_API_KEY
|
|
67
|
+
caution: "Ensure 'Update content' capability is enabled. Only include parameters you want to change. Cannot update parent, created_by, created_time, last_edited_by, last_edited_time, or rollup properties via API."
|
|
68
|
+
|
|
69
|
+
output_schema:
|
|
70
|
+
type: object
|
|
71
|
+
properties:
|
|
72
|
+
object:
|
|
73
|
+
type: string
|
|
74
|
+
id:
|
|
75
|
+
type: string
|
|
76
|
+
created_time:
|
|
77
|
+
type: string
|
|
78
|
+
last_edited_time:
|
|
79
|
+
type: string
|
|
80
|
+
archived:
|
|
81
|
+
type: boolean
|
|
82
|
+
in_trash:
|
|
83
|
+
type: boolean
|
|
84
|
+
is_locked:
|
|
85
|
+
type: boolean
|
|
86
|
+
properties:
|
|
87
|
+
type: object
|
|
88
|
+
required: ["object", "id", "last_edited_time"]
|
|
89
|
+
|
|
90
|
+
examples:
|
|
91
|
+
- name: "Update page title"
|
|
92
|
+
params:
|
|
93
|
+
page_id: "be633bf1-dfa0-436d-b259-571129a590e5"
|
|
94
|
+
properties:
|
|
95
|
+
Name:
|
|
96
|
+
title:
|
|
97
|
+
- text:
|
|
98
|
+
content: Updated Title
|
|
99
|
+
expected_result: "Page title updated to 'Updated Title'"
|
|
100
|
+
- name: "Update page icon"
|
|
101
|
+
params:
|
|
102
|
+
page_id: "be633bf1-dfa0-436d-b259-571129a590e5"
|
|
103
|
+
icon:
|
|
104
|
+
type: emoji
|
|
105
|
+
emoji: "🎉"
|
|
106
|
+
expected_result: "Page icon changed to celebration emoji"
|
|
107
|
+
- name: "Update page with cover and apply template"
|
|
108
|
+
params:
|
|
109
|
+
page_id: "be633bf1-dfa0-436d-b259-571129a590e5"
|
|
110
|
+
cover:
|
|
111
|
+
type: external
|
|
112
|
+
external:
|
|
113
|
+
url: https://example.com/image.png
|
|
114
|
+
template:
|
|
115
|
+
type: default
|
|
116
|
+
erase_content: true
|
|
117
|
+
expected_result: "Page cover set, default template applied, existing content replaced"
|