@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/developer-mcp",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "MCP server for Xano Headless API documentation and XanoScript code validation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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
- | Functions | `function` | Reusable function stacks |
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 (table, realtime, workspace, agent, MCP) |
117
- | Database Operations | `db_query` | Query, add, edit, delete |
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