@xano/developer-mcp 1.0.8 → 1.0.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/README.md +16 -0
- package/dist/index.js +35 -0
- package/dist/templates/xanoscript-index.js +7 -0
- package/package.json +1 -1
- package/xanoscript_docs/README.md +38 -5
- package/xanoscript_docs/addons.md +256 -0
- package/xanoscript_docs/agents.md +84 -0
- package/xanoscript_docs/database.md +160 -0
- package/xanoscript_docs/debugging.md +342 -0
- package/xanoscript_docs/functions.md +172 -0
- package/xanoscript_docs/integrations.md +376 -7
- package/xanoscript_docs/performance.md +407 -0
- package/xanoscript_docs/realtime.md +382 -0
- package/xanoscript_docs/schema.md +292 -0
- package/xanoscript_docs/security.md +550 -0
- package/xanoscript_docs/streaming.md +318 -0
- package/xanoscript_docs/syntax.md +267 -0
- package/xanoscript_docs/types.md +66 -21
package/README.md
CHANGED
|
@@ -180,6 +180,7 @@ Retrieves XanoScript programming language documentation with context-aware suppo
|
|
|
180
180
|
| `functions` | Reusable function stacks with inputs and responses |
|
|
181
181
|
| `apis` | HTTP endpoint definitions with authentication and CRUD patterns |
|
|
182
182
|
| `tasks` | Scheduled and cron jobs |
|
|
183
|
+
| `triggers` | Event-driven handlers (table, realtime, workspace, agent, MCP) |
|
|
183
184
|
| `database` | All db.* operations: query, get, add, edit, patch, delete |
|
|
184
185
|
| `agents` | AI agent configuration with LLM providers and tools |
|
|
185
186
|
| `tools` | AI tools for agents and MCP servers |
|
|
@@ -188,6 +189,13 @@ Retrieves XanoScript programming language documentation with context-aware suppo
|
|
|
188
189
|
| `integrations` | Cloud storage, Redis, security, and external APIs |
|
|
189
190
|
| `frontend` | Static frontend development and deployment |
|
|
190
191
|
| `ephemeral` | Temporary test environments |
|
|
192
|
+
| `addons` | Reusable subqueries for fetching related data |
|
|
193
|
+
| `debugging` | Logging, inspecting, and debugging XanoScript execution |
|
|
194
|
+
| `performance` | Performance optimization best practices |
|
|
195
|
+
| `realtime` | Real-time channels and events for push updates |
|
|
196
|
+
| `schema` | Runtime schema parsing and validation |
|
|
197
|
+
| `security` | Security best practices for authentication and authorization |
|
|
198
|
+
| `streaming` | Streaming data from files, requests, and responses |
|
|
191
199
|
|
|
192
200
|
**Examples:**
|
|
193
201
|
```
|
|
@@ -234,6 +242,7 @@ The server also exposes XanoScript documentation as MCP resources for direct acc
|
|
|
234
242
|
| `xanoscript://docs/functions` | Reusable function stacks |
|
|
235
243
|
| `xanoscript://docs/apis` | HTTP endpoint definitions |
|
|
236
244
|
| `xanoscript://docs/tasks` | Scheduled and cron jobs |
|
|
245
|
+
| `xanoscript://docs/triggers` | Event-driven handlers |
|
|
237
246
|
| `xanoscript://docs/database` | Database operations |
|
|
238
247
|
| `xanoscript://docs/agents` | AI agent configuration |
|
|
239
248
|
| `xanoscript://docs/tools` | AI tools for agents |
|
|
@@ -242,6 +251,13 @@ The server also exposes XanoScript documentation as MCP resources for direct acc
|
|
|
242
251
|
| `xanoscript://docs/integrations` | External service integrations |
|
|
243
252
|
| `xanoscript://docs/frontend` | Static frontend development |
|
|
244
253
|
| `xanoscript://docs/ephemeral` | Temporary test environments |
|
|
254
|
+
| `xanoscript://docs/addons` | Reusable subqueries for related data |
|
|
255
|
+
| `xanoscript://docs/debugging` | Logging and debugging tools |
|
|
256
|
+
| `xanoscript://docs/performance` | Performance optimization |
|
|
257
|
+
| `xanoscript://docs/realtime` | Real-time channels and events |
|
|
258
|
+
| `xanoscript://docs/schema` | Runtime schema parsing |
|
|
259
|
+
| `xanoscript://docs/security` | Security best practices |
|
|
260
|
+
| `xanoscript://docs/streaming` | Data streaming operations |
|
|
245
261
|
|
|
246
262
|
## npm Scripts
|
|
247
263
|
|
package/dist/index.js
CHANGED
|
@@ -98,6 +98,41 @@ const XANOSCRIPT_DOCS_V2 = {
|
|
|
98
98
|
applyTo: ["ephemeral/**/*.xs"],
|
|
99
99
|
description: "Temporary test environments",
|
|
100
100
|
},
|
|
101
|
+
addons: {
|
|
102
|
+
file: "addons.md",
|
|
103
|
+
applyTo: ["addons/*.xs", "functions/**/*.xs", "apis/**/*.xs"],
|
|
104
|
+
description: "Reusable subqueries for fetching related data",
|
|
105
|
+
},
|
|
106
|
+
debugging: {
|
|
107
|
+
file: "debugging.md",
|
|
108
|
+
applyTo: ["**/*.xs"],
|
|
109
|
+
description: "Logging, inspecting, and debugging XanoScript execution",
|
|
110
|
+
},
|
|
111
|
+
performance: {
|
|
112
|
+
file: "performance.md",
|
|
113
|
+
applyTo: ["functions/**/*.xs", "apis/**/*.xs"],
|
|
114
|
+
description: "Performance optimization best practices",
|
|
115
|
+
},
|
|
116
|
+
realtime: {
|
|
117
|
+
file: "realtime.md",
|
|
118
|
+
applyTo: ["functions/**/*.xs", "apis/**/*.xs", "triggers/**/*.xs"],
|
|
119
|
+
description: "Real-time channels and events for push updates",
|
|
120
|
+
},
|
|
121
|
+
schema: {
|
|
122
|
+
file: "schema.md",
|
|
123
|
+
applyTo: ["functions/**/*.xs", "apis/**/*.xs"],
|
|
124
|
+
description: "Runtime schema parsing and validation",
|
|
125
|
+
},
|
|
126
|
+
security: {
|
|
127
|
+
file: "security.md",
|
|
128
|
+
applyTo: ["functions/**/*.xs", "apis/**/*.xs"],
|
|
129
|
+
description: "Security best practices for authentication and authorization",
|
|
130
|
+
},
|
|
131
|
+
streaming: {
|
|
132
|
+
file: "streaming.md",
|
|
133
|
+
applyTo: ["functions/**/*.xs", "apis/**/*.xs"],
|
|
134
|
+
description: "Streaming data from files, requests, and responses",
|
|
135
|
+
},
|
|
101
136
|
};
|
|
102
137
|
const XANO_OBJECT_TYPES = {
|
|
103
138
|
function: {
|
|
@@ -53,8 +53,15 @@ ${formatRow("task_workflow", "AI workflow for creating tasks")}
|
|
|
53
53
|
|
|
54
54
|
| Keyword | Aliases | Description |
|
|
55
55
|
|---------|---------|-------------|
|
|
56
|
+
${formatRow("addons", "Reusable subqueries for related data")}
|
|
57
|
+
${formatRow("debugging", "Logging and debugging tools")}
|
|
56
58
|
${formatRow("frontend", "Frontend development with Xano")}
|
|
57
59
|
${formatRow("lovable", "Building from Lovable-generated websites")}
|
|
60
|
+
${formatRow("performance", "Performance optimization best practices")}
|
|
61
|
+
${formatRow("realtime", "Real-time channels and events")}
|
|
62
|
+
${formatRow("schema", "Runtime schema parsing and validation")}
|
|
63
|
+
${formatRow("security", "Security best practices")}
|
|
64
|
+
${formatRow("streaming", "Streaming data from files and responses")}
|
|
58
65
|
${formatRow("testing", "Unit testing XanoScript code")}
|
|
59
66
|
${formatRow("tips", "Tips and tricks")}
|
|
60
67
|
${formatRow("ephemeral", "Ephemeral environment setup")}
|
package/package.json
CHANGED
|
@@ -105,19 +105,52 @@ This helps AI tools apply the correct documentation based on the file being edit
|
|
|
105
105
|
|
|
106
106
|
Use `xanoscript_docs({ keyword: "<keyword>" })` to retrieve documentation.
|
|
107
107
|
|
|
108
|
+
### Core Language
|
|
108
109
|
| Topic | Keyword | Description |
|
|
109
110
|
|-------|---------|-------------|
|
|
110
|
-
| Syntax Reference | `syntax` | Expressions, operators, filters |
|
|
111
|
+
| Syntax Reference | `syntax` | Expressions, operators, filters, system variables |
|
|
111
112
|
| Types & Inputs | `input` | Data types, validation, input blocks |
|
|
113
|
+
| Functions | `function` | Reusable function stacks, async, loops |
|
|
114
|
+
| Schema | `schema` | Runtime schema parsing and validation |
|
|
115
|
+
|
|
116
|
+
### Data
|
|
117
|
+
| Topic | Keyword | Description |
|
|
118
|
+
|-------|---------|-------------|
|
|
112
119
|
| Tables | `table` | Database schema definitions |
|
|
113
|
-
|
|
|
120
|
+
| Database Operations | `db_query` | Query, add, edit, delete, bulk operations |
|
|
121
|
+
| Addons | `addon` | Reusable subqueries for related data |
|
|
122
|
+
| Streaming | `streaming` | Stream processing for large files |
|
|
123
|
+
|
|
124
|
+
### APIs & Endpoints
|
|
125
|
+
| Topic | Keyword | Description |
|
|
126
|
+
|-------|---------|-------------|
|
|
114
127
|
| APIs | `api_query` | HTTP endpoint definitions |
|
|
115
128
|
| Tasks | `task` | Scheduled jobs |
|
|
116
|
-
| Triggers | `trigger` | Event-driven handlers
|
|
117
|
-
|
|
|
129
|
+
| Triggers | `trigger` | Event-driven handlers |
|
|
130
|
+
| Realtime | `realtime` | Push events and channels |
|
|
131
|
+
|
|
132
|
+
### AI & Agents
|
|
133
|
+
| Topic | Keyword | Description |
|
|
134
|
+
|-------|---------|-------------|
|
|
118
135
|
| Agents | `agent` | AI agent configuration |
|
|
119
136
|
| Tools | `tool` | AI tools for agents |
|
|
120
137
|
| MCP Servers | `mcp_server` | Model Context Protocol servers |
|
|
138
|
+
|
|
139
|
+
### Integrations
|
|
140
|
+
| Topic | Keyword | Description |
|
|
141
|
+
|-------|---------|-------------|
|
|
142
|
+
| Integrations | `integrations` | Cloud storage, search, Redis, zip, Lambda |
|
|
143
|
+
|
|
144
|
+
### Development
|
|
145
|
+
| Topic | Keyword | Description |
|
|
146
|
+
|-------|---------|-------------|
|
|
121
147
|
| Testing | `testing` | Unit tests and mocking |
|
|
148
|
+
| Debugging | `debugging` | Logging and inspection tools |
|
|
122
149
|
| Frontend | `frontend` | Static frontend development |
|
|
123
|
-
| Ephemeral | `ephemeral` | Temporary environments
|
|
150
|
+
| Ephemeral | `ephemeral` | Temporary environments |
|
|
151
|
+
|
|
152
|
+
### Best Practices
|
|
153
|
+
| Topic | Keyword | Description |
|
|
154
|
+
|-------|---------|-------------|
|
|
155
|
+
| Performance | `performance` | Query optimization, caching, parallelism |
|
|
156
|
+
| Security | `security` | Authentication, authorization, encryption |
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "addons/*.xs, functions/**/*.xs, apis/**/*.xs"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Addons
|
|
6
|
+
|
|
7
|
+
Reusable subqueries for fetching related data in database queries.
|
|
8
|
+
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
```xs
|
|
12
|
+
addon <name> {
|
|
13
|
+
input {
|
|
14
|
+
<type> <name>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
stack {
|
|
18
|
+
db.query <tableName> {
|
|
19
|
+
return = {type: "<return_type>"}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Basic Structure
|
|
28
|
+
|
|
29
|
+
Addons define reusable data fetching logic that can be attached to query results. The stack can only contain a `db.query` block.
|
|
30
|
+
|
|
31
|
+
```xs
|
|
32
|
+
addon comment_count {
|
|
33
|
+
input {
|
|
34
|
+
int post_id
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
stack {
|
|
38
|
+
db.query comment {
|
|
39
|
+
where = $db.comment.post_id == $input.post_id
|
|
40
|
+
return = {type: "count"}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Using Addons in Queries
|
|
49
|
+
|
|
50
|
+
### In db.query
|
|
51
|
+
|
|
52
|
+
```xs
|
|
53
|
+
db.query post {
|
|
54
|
+
where = $db.post.author_id == $auth.id
|
|
55
|
+
addon = [
|
|
56
|
+
{
|
|
57
|
+
name: "comment_count",
|
|
58
|
+
input: {post_id: $output.id},
|
|
59
|
+
as: "items.comment_count"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
} as $posts
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Result Structure
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"items": [
|
|
70
|
+
{
|
|
71
|
+
"id": 1,
|
|
72
|
+
"title": "My Post",
|
|
73
|
+
"comment_count": 42
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Multiple Addons
|
|
80
|
+
|
|
81
|
+
```xs
|
|
82
|
+
db.query post {
|
|
83
|
+
where = $db.post.is_published == true
|
|
84
|
+
addon = [
|
|
85
|
+
{
|
|
86
|
+
name: "comment_count",
|
|
87
|
+
input: {post_id: $output.id},
|
|
88
|
+
as: "items.comments"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "like_count",
|
|
92
|
+
input: {post_id: $output.id},
|
|
93
|
+
as: "items.likes"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "author_details",
|
|
97
|
+
input: {user_id: $output.author_id},
|
|
98
|
+
as: "items.author"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
} as $posts
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Addon Examples
|
|
107
|
+
|
|
108
|
+
### Related List
|
|
109
|
+
|
|
110
|
+
```xs
|
|
111
|
+
addon recent_comments {
|
|
112
|
+
input {
|
|
113
|
+
int post_id
|
|
114
|
+
int limit?=5
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
stack {
|
|
118
|
+
db.query comment {
|
|
119
|
+
where = $db.comment.post_id == $input.post_id
|
|
120
|
+
sort = {created_at: "desc"}
|
|
121
|
+
return = {
|
|
122
|
+
type: "list",
|
|
123
|
+
paging: {per_page: $input.limit}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Count
|
|
131
|
+
|
|
132
|
+
```xs
|
|
133
|
+
addon order_count {
|
|
134
|
+
input {
|
|
135
|
+
int user_id
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
stack {
|
|
139
|
+
db.query order {
|
|
140
|
+
where = $db.order.user_id == $input.user_id
|
|
141
|
+
return = {type: "count"}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Boolean Check (Exists)
|
|
148
|
+
|
|
149
|
+
```xs
|
|
150
|
+
addon has_premium {
|
|
151
|
+
input {
|
|
152
|
+
int user_id
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
stack {
|
|
156
|
+
db.query subscription {
|
|
157
|
+
where = $db.subscription.user_id == $input.user_id
|
|
158
|
+
&& $db.subscription.status == "active"
|
|
159
|
+
&& $db.subscription.expires_at > now
|
|
160
|
+
return = {type: "exists"}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Single Record
|
|
167
|
+
|
|
168
|
+
```xs
|
|
169
|
+
addon author_details {
|
|
170
|
+
input {
|
|
171
|
+
int user_id
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
stack {
|
|
175
|
+
db.query user {
|
|
176
|
+
where = $db.user.id == $input.user_id
|
|
177
|
+
return = {type: "single"}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## addon.call
|
|
186
|
+
|
|
187
|
+
Call an addon directly from a function or API.
|
|
188
|
+
|
|
189
|
+
```xs
|
|
190
|
+
addon.call comment_count {
|
|
191
|
+
input = {post_id: $input.post_id}
|
|
192
|
+
} as $count
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Use Cases
|
|
196
|
+
|
|
197
|
+
```xs
|
|
198
|
+
// Get stats for single record
|
|
199
|
+
addon.call order_count {
|
|
200
|
+
input = {user_id: $auth.id}
|
|
201
|
+
} as $my_order_count
|
|
202
|
+
|
|
203
|
+
// Conditional addon call
|
|
204
|
+
conditional {
|
|
205
|
+
if ($input.include_stats) {
|
|
206
|
+
addon.call order_count {
|
|
207
|
+
input = {user_id: $entity.id}
|
|
208
|
+
} as $count
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Database Addon Attributes
|
|
216
|
+
|
|
217
|
+
Use `dbAddonAttr` for computed fields in queries.
|
|
218
|
+
|
|
219
|
+
```xs
|
|
220
|
+
db.query product {
|
|
221
|
+
eval = {
|
|
222
|
+
discount_price: dbAddonAttr("calculate_discount", {product_id: $db.product.id})
|
|
223
|
+
}
|
|
224
|
+
} as $products
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Organization
|
|
230
|
+
|
|
231
|
+
### File Structure
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
addons/
|
|
235
|
+
├── comment_count.xs
|
|
236
|
+
├── like_count.xs
|
|
237
|
+
├── author_details.xs
|
|
238
|
+
├── order_count.xs
|
|
239
|
+
└── has_premium.xs
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Naming Conventions
|
|
243
|
+
|
|
244
|
+
- Use descriptive names: `comment_count`, not `cc`
|
|
245
|
+
- Use verb_noun for actions: `calculate_discount`
|
|
246
|
+
- Use has_ prefix for boolean checks: `has_premium`
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Best Practices
|
|
251
|
+
|
|
252
|
+
1. **Keep addons focused** - One purpose per addon
|
|
253
|
+
2. **Use input parameters** - Make addons reusable
|
|
254
|
+
3. **Use appropriate return types** - `list`, `single`, `count`, `exists`
|
|
255
|
+
4. **Limit nested queries** - Avoid N+1 query patterns
|
|
256
|
+
5. **Document inputs** - Add descriptions to input fields
|
|
@@ -317,6 +317,89 @@ agent "Research Assistant" {
|
|
|
317
317
|
|
|
318
318
|
---
|
|
319
319
|
|
|
320
|
+
## External MCP Tools
|
|
321
|
+
|
|
322
|
+
Integrate external MCP (Model Context Protocol) servers to extend agent capabilities.
|
|
323
|
+
|
|
324
|
+
### ai.external.mcp.tool.list
|
|
325
|
+
|
|
326
|
+
List available tools from an external MCP server.
|
|
327
|
+
|
|
328
|
+
```xs
|
|
329
|
+
ai.external.mcp.tool.list {
|
|
330
|
+
server_url = "https://mcp.example.com"
|
|
331
|
+
api_key = $env.MCP_API_KEY
|
|
332
|
+
} as $tools
|
|
333
|
+
|
|
334
|
+
// $tools = [
|
|
335
|
+
// { name: "search_web", description: "Search the web", inputSchema: {...} },
|
|
336
|
+
// { name: "fetch_page", description: "Fetch webpage content", inputSchema: {...} }
|
|
337
|
+
// ]
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### ai.external.mcp.tool.run
|
|
341
|
+
|
|
342
|
+
Execute a tool on an external MCP server.
|
|
343
|
+
|
|
344
|
+
```xs
|
|
345
|
+
ai.external.mcp.tool.run {
|
|
346
|
+
server_url = "https://mcp.example.com"
|
|
347
|
+
api_key = $env.MCP_API_KEY
|
|
348
|
+
tool_name = "search_web"
|
|
349
|
+
arguments = { query: "latest AI news" }
|
|
350
|
+
} as $result
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### ai.external.mcp.server_details
|
|
354
|
+
|
|
355
|
+
Get metadata about an external MCP server.
|
|
356
|
+
|
|
357
|
+
```xs
|
|
358
|
+
ai.external.mcp.server_details {
|
|
359
|
+
server_url = "https://mcp.example.com"
|
|
360
|
+
api_key = $env.MCP_API_KEY
|
|
361
|
+
} as $details
|
|
362
|
+
|
|
363
|
+
// $details = {
|
|
364
|
+
// name: "Web Tools",
|
|
365
|
+
// version: "1.0.0",
|
|
366
|
+
// capabilities: ["tools", "resources"],
|
|
367
|
+
// tools: [...]
|
|
368
|
+
// }
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Using External Tools in Agents
|
|
372
|
+
|
|
373
|
+
```xs
|
|
374
|
+
agent "Research Agent" {
|
|
375
|
+
canonical = "research-v1"
|
|
376
|
+
llm = {
|
|
377
|
+
type: "openai"
|
|
378
|
+
api_key: "{{ $env.OPENAI_API_KEY }}"
|
|
379
|
+
model: "gpt-5"
|
|
380
|
+
system_prompt: """
|
|
381
|
+
You are a research assistant with access to web search
|
|
382
|
+
and document analysis tools. Use them to find and analyze information.
|
|
383
|
+
"""
|
|
384
|
+
prompt: "{{ $args.query }}"
|
|
385
|
+
max_steps: 8
|
|
386
|
+
}
|
|
387
|
+
tools = [
|
|
388
|
+
{ name: "search_web" },
|
|
389
|
+
{ name: "fetch_page" },
|
|
390
|
+
{ name: "summarize_document" }
|
|
391
|
+
]
|
|
392
|
+
external_mcp_servers = [
|
|
393
|
+
{
|
|
394
|
+
url: "{{ $env.WEB_MCP_URL }}",
|
|
395
|
+
api_key: "{{ $env.WEB_MCP_KEY }}"
|
|
396
|
+
}
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
320
403
|
## Best Practices
|
|
321
404
|
|
|
322
405
|
1. **Clear system prompts** - Define persona, capabilities, and constraints
|
|
@@ -325,3 +408,4 @@ agent "Research Assistant" {
|
|
|
325
408
|
4. **Don't repeat tool descriptions** - They're auto-injected
|
|
326
409
|
5. **Use environment variables** - Never hardcode API keys
|
|
327
410
|
6. **Test with xano-free first** - Free for development
|
|
411
|
+
7. **Validate external MCP servers** - Check server_details before using
|
|
@@ -405,6 +405,164 @@ db.external.oracle.direct_query { ... }
|
|
|
405
405
|
|
|
406
406
|
---
|
|
407
407
|
|
|
408
|
+
## Bulk Operations
|
|
409
|
+
|
|
410
|
+
Perform batch operations on multiple records efficiently.
|
|
411
|
+
|
|
412
|
+
### db.bulk.add
|
|
413
|
+
|
|
414
|
+
Insert multiple records in a single operation.
|
|
415
|
+
|
|
416
|
+
```xs
|
|
417
|
+
db.bulk.add "product" {
|
|
418
|
+
data = [
|
|
419
|
+
{ name: "Product A", price: 10.00, sku: "SKU-A" },
|
|
420
|
+
{ name: "Product B", price: 20.00, sku: "SKU-B" },
|
|
421
|
+
{ name: "Product C", price: 30.00, sku: "SKU-C" }
|
|
422
|
+
]
|
|
423
|
+
} as $inserted
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### db.bulk.update
|
|
427
|
+
|
|
428
|
+
Update multiple records matching conditions.
|
|
429
|
+
|
|
430
|
+
```xs
|
|
431
|
+
db.bulk.update "product" {
|
|
432
|
+
where = $db.product.category_id == $input.category_id
|
|
433
|
+
data = {
|
|
434
|
+
is_featured: true,
|
|
435
|
+
updated_at: now
|
|
436
|
+
}
|
|
437
|
+
} as $count
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### db.bulk.patch
|
|
441
|
+
|
|
442
|
+
Patch multiple records with variable data.
|
|
443
|
+
|
|
444
|
+
```xs
|
|
445
|
+
var $updates { value = { updated_at: now } }
|
|
446
|
+
|
|
447
|
+
conditional {
|
|
448
|
+
if ($input.discount != null) {
|
|
449
|
+
var.update $updates { value = $updates|set:"discount":$input.discount }
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
db.bulk.patch "product" {
|
|
454
|
+
where = $db.product.category_id == $input.category_id
|
|
455
|
+
data = $updates
|
|
456
|
+
} as $count
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
### db.bulk.delete
|
|
460
|
+
|
|
461
|
+
Delete multiple records matching conditions.
|
|
462
|
+
|
|
463
|
+
```xs
|
|
464
|
+
db.bulk.delete "temp_session" {
|
|
465
|
+
where = $db.temp_session.expires_at < now
|
|
466
|
+
} as $deleted_count
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Bulk with Transaction
|
|
470
|
+
|
|
471
|
+
```xs
|
|
472
|
+
db.transaction {
|
|
473
|
+
stack {
|
|
474
|
+
db.bulk.delete "order_item" {
|
|
475
|
+
where = $db.order_item.order_id == $input.order_id
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
db.bulk.add "order_item" {
|
|
479
|
+
data = $input.items|map:{
|
|
480
|
+
order_id: $input.order_id,
|
|
481
|
+
product_id: $$.product_id,
|
|
482
|
+
quantity: $$.quantity
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Advanced Features
|
|
492
|
+
|
|
493
|
+
### db.set_datasource
|
|
494
|
+
|
|
495
|
+
Switch to a different data source within a function.
|
|
496
|
+
|
|
497
|
+
```xs
|
|
498
|
+
db.set_datasource {
|
|
499
|
+
name = "analytics_db"
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
db.query "metrics" {
|
|
503
|
+
where = $db.metrics.date >= $input.start_date
|
|
504
|
+
} as $metrics
|
|
505
|
+
|
|
506
|
+
db.set_datasource {
|
|
507
|
+
name = "default"
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
### db.schema
|
|
512
|
+
|
|
513
|
+
Get schema information for a table.
|
|
514
|
+
|
|
515
|
+
```xs
|
|
516
|
+
db.schema {
|
|
517
|
+
table = "user"
|
|
518
|
+
} as $schema
|
|
519
|
+
|
|
520
|
+
// $schema contains:
|
|
521
|
+
// - columns: array of column definitions
|
|
522
|
+
// - indexes: array of index definitions
|
|
523
|
+
// - constraints: array of constraints
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Transaction Isolation Levels
|
|
527
|
+
|
|
528
|
+
```xs
|
|
529
|
+
db.transaction {
|
|
530
|
+
isolation = "serializable" // serializable, repeatable_read, read_committed
|
|
531
|
+
stack {
|
|
532
|
+
// Operations run with specified isolation
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Deadlock Handling
|
|
538
|
+
|
|
539
|
+
```xs
|
|
540
|
+
try_catch {
|
|
541
|
+
try {
|
|
542
|
+
db.transaction {
|
|
543
|
+
stack {
|
|
544
|
+
db.edit "inventory" { ... }
|
|
545
|
+
db.edit "order" { ... }
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
conditional {
|
|
551
|
+
if ($error.name == "DeadlockError") {
|
|
552
|
+
// Retry logic
|
|
553
|
+
util.sleep { value = 100 }
|
|
554
|
+
function.run "retry_transaction" { input = $input }
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
throw { name = $error.name, value = $error.message }
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
---
|
|
565
|
+
|
|
408
566
|
## Best Practices
|
|
409
567
|
|
|
410
568
|
1. **Use db.query for searches** - Flexible filtering and pagination
|
|
@@ -412,3 +570,5 @@ db.external.oracle.direct_query { ... }
|
|
|
412
570
|
3. **Use db.patch for dynamic updates** - Accepts variable data
|
|
413
571
|
4. **Use transactions for atomicity** - Ensure all-or-nothing operations
|
|
414
572
|
5. **Use null-safe operators** - `==?` for optional filters
|
|
573
|
+
6. **Use bulk operations for batch processing** - More efficient than loops
|
|
574
|
+
7. **Handle deadlocks gracefully** - Implement retry logic for concurrent writes
|