@xano/developer-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/api_docs/addon.md +193 -0
- package/api_docs/agent.md +154 -0
- package/api_docs/api_group.md +236 -0
- package/api_docs/authentication.md +68 -0
- package/api_docs/file.md +190 -0
- package/api_docs/function.md +217 -0
- package/api_docs/history.md +263 -0
- package/api_docs/index.md +104 -0
- package/api_docs/mcp_server.md +139 -0
- package/api_docs/middleware.md +205 -0
- package/api_docs/realtime.md +153 -0
- package/api_docs/table.md +151 -0
- package/api_docs/task.md +191 -0
- package/api_docs/tool.md +216 -0
- package/api_docs/triggers.md +344 -0
- package/api_docs/workspace.md +246 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +495 -0
- package/package.json +49 -0
- package/xanoscript_docs/README.md +1 -0
- package/xanoscript_docs/api_query_examples.md +1255 -0
- package/xanoscript_docs/api_query_guideline.md +129 -0
- package/xanoscript_docs/build_from_lovable.md +715 -0
- package/xanoscript_docs/db_query_guideline.md +427 -0
- package/xanoscript_docs/ephemeral_environment_guideline.md +529 -0
- package/xanoscript_docs/expression_guideline.md +1086 -0
- package/xanoscript_docs/frontend_guideline.md +67 -0
- package/xanoscript_docs/function_examples.md +1406 -0
- package/xanoscript_docs/function_guideline.md +130 -0
- package/xanoscript_docs/functions.md +2155 -0
- package/xanoscript_docs/input_guideline.md +227 -0
- package/xanoscript_docs/mcp_server_examples.md +36 -0
- package/xanoscript_docs/mcp_server_guideline.md +69 -0
- package/xanoscript_docs/query_filter.md +489 -0
- package/xanoscript_docs/table_examples.md +586 -0
- package/xanoscript_docs/table_guideline.md +137 -0
- package/xanoscript_docs/task_examples.md +511 -0
- package/xanoscript_docs/task_guideline.md +103 -0
- package/xanoscript_docs/tips_and_tricks.md +144 -0
- package/xanoscript_docs/tool_examples.md +69 -0
- package/xanoscript_docs/tool_guideline.md +139 -0
- package/xanoscript_docs/unit_testing_guideline.md +328 -0
- package/xanoscript_docs/version.json +3 -0
- package/xanoscript_docs/workspace.md +17 -0
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
# Ephemeral Services and Jobs in XanoScript
|
|
2
|
+
|
|
3
|
+
Ephemeral services and jobs allow you to run experiments in isolated Xano environments without impacting your main workspace. They are useful for testing, prototyping, and running one-off data operations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
| Type | Description | Lifecycle |
|
|
8
|
+
| --------------------- | -------------------------------------------------------------------------- | ------------------------------------------ |
|
|
9
|
+
| **Ephemeral Service** | Creates a temporary Xano workspace with database, functions, and endpoints | Stays running until manually shut down |
|
|
10
|
+
| **Ephemeral Job** | Runs a one-time operation in an isolated environment | Executes once and automatically shuts down |
|
|
11
|
+
|
|
12
|
+
## Directory Structure
|
|
13
|
+
|
|
14
|
+
Ephemeral services and jobs should be organized in the `ephemeral/` directory:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
ephemeral/
|
|
18
|
+
├── my-service/
|
|
19
|
+
│ ├── workspace.xs # Workspace configuration
|
|
20
|
+
│ ├── tables/ # Database tables
|
|
21
|
+
│ ├── functions/ # Custom functions
|
|
22
|
+
│ └── apis/ # API endpoints
|
|
23
|
+
└── my-job/
|
|
24
|
+
├── workspace.xs
|
|
25
|
+
├── tables/
|
|
26
|
+
└── functions/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Creating an Ephemeral Service
|
|
30
|
+
|
|
31
|
+
An ephemeral service creates a fully functional Xano workspace with its own database, API endpoints, and functions. Each file in the service directory defines a different component.
|
|
32
|
+
|
|
33
|
+
### Workspace Configuration
|
|
34
|
+
|
|
35
|
+
Every ephemeral service must have a `workspace.xs` file that defines the workspace name and environment variables:
|
|
36
|
+
|
|
37
|
+
```xs
|
|
38
|
+
workspace test {
|
|
39
|
+
env = {
|
|
40
|
+
api_key: "test"
|
|
41
|
+
phrase: "hello"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Defining Tables
|
|
47
|
+
|
|
48
|
+
Tables define your database schema. Include the `items` property to seed initial data:
|
|
49
|
+
|
|
50
|
+
```xs
|
|
51
|
+
table event {
|
|
52
|
+
auth = false
|
|
53
|
+
|
|
54
|
+
schema {
|
|
55
|
+
int id
|
|
56
|
+
timestamp created_at?=now
|
|
57
|
+
text name
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
index = [
|
|
61
|
+
{type: "primary", field: [{name: "id"}]}
|
|
62
|
+
{type: "btree", field: [{name: "created_at", op: "desc"}]}
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
items = [
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Defining API Groups and Endpoints
|
|
71
|
+
|
|
72
|
+
Create an API group to organize your endpoints:
|
|
73
|
+
|
|
74
|
+
```xs
|
|
75
|
+
// api group comment
|
|
76
|
+
api_group test {
|
|
77
|
+
canonical = "abc123"
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Then define your API endpoints:
|
|
82
|
+
|
|
83
|
+
```xs
|
|
84
|
+
query count verb=GET {
|
|
85
|
+
api_group = "test"
|
|
86
|
+
input {
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
stack {
|
|
90
|
+
db.query event {
|
|
91
|
+
return = {type: "count"}
|
|
92
|
+
} as $cnt
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
response = $cnt
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```xs
|
|
100
|
+
query add verb=GET {
|
|
101
|
+
api_group = "test"
|
|
102
|
+
input {
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
stack {
|
|
106
|
+
db.add event {
|
|
107
|
+
data = {name: ""|uuid}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
response = null
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```xs
|
|
116
|
+
query clear verb=GET {
|
|
117
|
+
api_group = "test"
|
|
118
|
+
input {
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
stack {
|
|
122
|
+
db.truncate event
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
response = null
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Defining Functions
|
|
130
|
+
|
|
131
|
+
Functions can be called by your endpoints or other functions:
|
|
132
|
+
|
|
133
|
+
```xs
|
|
134
|
+
function my_helper {
|
|
135
|
+
input {
|
|
136
|
+
json args
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
stack {
|
|
140
|
+
// Your logic here
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
response = null
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Creating an Ephemeral Job
|
|
148
|
+
|
|
149
|
+
An ephemeral job runs once and then shuts down. Jobs use special reserved function names to control execution flow:
|
|
150
|
+
|
|
151
|
+
| Function | Description |
|
|
152
|
+
| -------- | ----------------------------------------------------------------- |
|
|
153
|
+
| `$main` | **Required.** The primary entry point that executes the job logic |
|
|
154
|
+
| `$pre` | Optional. Runs before `$main`, useful for setup or validation |
|
|
155
|
+
| `$post` | Optional. Runs after `$main`, useful for cleanup or notifications |
|
|
156
|
+
|
|
157
|
+
### Job Lifecycle
|
|
158
|
+
|
|
159
|
+
1. `$pre` function executes (if defined)
|
|
160
|
+
2. `$main` function executes
|
|
161
|
+
3. `$post` function executes (if defined)
|
|
162
|
+
4. Environment shuts down automatically
|
|
163
|
+
|
|
164
|
+
### Example Job Structure
|
|
165
|
+
|
|
166
|
+
**Workspace configuration:**
|
|
167
|
+
|
|
168
|
+
```xs
|
|
169
|
+
workspace test {
|
|
170
|
+
env = {
|
|
171
|
+
api_key: "test"
|
|
172
|
+
phrase: "hello"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Table with seeded data:**
|
|
178
|
+
|
|
179
|
+
```xs
|
|
180
|
+
table authors {
|
|
181
|
+
auth = false
|
|
182
|
+
|
|
183
|
+
schema {
|
|
184
|
+
int id
|
|
185
|
+
timestamp created_at?=now
|
|
186
|
+
text name? filters=trim
|
|
187
|
+
text desc? filters=trim
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
index = [
|
|
191
|
+
{type: "primary", field: [{name: "id"}]}
|
|
192
|
+
{type: "btree", field: [{name: "created_at", op: "desc"}]}
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
items = [
|
|
196
|
+
{"id":1,"created_at":1761410450342,"name":"Kathryn Watson","desc":"aa"}
|
|
197
|
+
{"id":2,"created_at":1761410450344,"name":"Martha Torres","desc":"aa"}
|
|
198
|
+
{"id":3,"created_at":1761410450345,"name":"Raymond Rivera","desc":"aa"}
|
|
199
|
+
{"id":4,"created_at":1761410450345,"name":"Judith Morales","desc":"aa"}
|
|
200
|
+
{"id":5,"created_at":1761410450346,"name":"Philip Shaw","desc":"aa"}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Main entry point:**
|
|
206
|
+
|
|
207
|
+
```xs
|
|
208
|
+
function "$main" {
|
|
209
|
+
input {
|
|
210
|
+
json args
|
|
211
|
+
json pre
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
stack {
|
|
215
|
+
db.add authors {
|
|
216
|
+
data = {name: "test"}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
db.query authors {
|
|
220
|
+
return = {type: "count"}
|
|
221
|
+
} as $cnt
|
|
222
|
+
|
|
223
|
+
precondition ($cnt == 6) {
|
|
224
|
+
error = "Author count check failed"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
response = $cnt
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Pre-execution hook (optional):**
|
|
233
|
+
|
|
234
|
+
```xs
|
|
235
|
+
function "$pre" {
|
|
236
|
+
input {
|
|
237
|
+
json args
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
stack {
|
|
241
|
+
// Setup logic, validation, etc.
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
response = null
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Post-execution hook (optional):**
|
|
249
|
+
|
|
250
|
+
```xs
|
|
251
|
+
function "$post" {
|
|
252
|
+
input {
|
|
253
|
+
json args
|
|
254
|
+
json pre
|
|
255
|
+
json main
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
stack {
|
|
259
|
+
// Send notification, cleanup, etc.
|
|
260
|
+
api.request {
|
|
261
|
+
url = "https://webhook.site/your-webhook-id"
|
|
262
|
+
params = {
|
|
263
|
+
service: true
|
|
264
|
+
pre: $input.pre
|
|
265
|
+
main: $input.main
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
response = null
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Helper functions:**
|
|
275
|
+
|
|
276
|
+
```xs
|
|
277
|
+
function loop {
|
|
278
|
+
input {
|
|
279
|
+
int cnt
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
stack {
|
|
283
|
+
var $total {
|
|
284
|
+
value = $input.cnt
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
var $x1 {
|
|
288
|
+
value = 0
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
for ($total) {
|
|
292
|
+
each as $index {
|
|
293
|
+
math.add $x1 {
|
|
294
|
+
value = 1
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
response = $x1
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Complete Ephemeral Service Example
|
|
305
|
+
|
|
306
|
+
Here's a complete ephemeral service with a database, API group, and endpoints:
|
|
307
|
+
|
|
308
|
+
**`ephemeral/event-tracker/workspace.xs`:**
|
|
309
|
+
|
|
310
|
+
```xs
|
|
311
|
+
workspace event_tracker {
|
|
312
|
+
env = {
|
|
313
|
+
api_key: "test-key"
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**`ephemeral/event-tracker/tables/event.xs`:**
|
|
319
|
+
|
|
320
|
+
```xs
|
|
321
|
+
table event {
|
|
322
|
+
auth = false
|
|
323
|
+
|
|
324
|
+
schema {
|
|
325
|
+
int id
|
|
326
|
+
timestamp created_at?=now
|
|
327
|
+
text name
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
index = [
|
|
331
|
+
{type: "primary", field: [{name: "id"}]}
|
|
332
|
+
{type: "btree", field: [{name: "created_at", op: "desc"}]}
|
|
333
|
+
]
|
|
334
|
+
|
|
335
|
+
items = []
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**`ephemeral/event-tracker/apis/api_group.xs`:**
|
|
340
|
+
|
|
341
|
+
```xs
|
|
342
|
+
api_group events {
|
|
343
|
+
canonical = "events-api"
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**`ephemeral/event-tracker/apis/count.xs`:**
|
|
348
|
+
|
|
349
|
+
```xs
|
|
350
|
+
query count verb=GET {
|
|
351
|
+
api_group = "events"
|
|
352
|
+
input {}
|
|
353
|
+
|
|
354
|
+
stack {
|
|
355
|
+
db.query event {
|
|
356
|
+
return = {type: "count"}
|
|
357
|
+
} as $cnt
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
response = $cnt
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**`ephemeral/event-tracker/apis/add.xs`:**
|
|
365
|
+
|
|
366
|
+
```xs
|
|
367
|
+
query add verb=POST {
|
|
368
|
+
api_group = "events"
|
|
369
|
+
input {
|
|
370
|
+
text name filters=trim
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
stack {
|
|
374
|
+
db.add event {
|
|
375
|
+
data = {name: $input.name}
|
|
376
|
+
} as $new_event
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
response = $new_event
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**`ephemeral/event-tracker/apis/clear.xs`:**
|
|
384
|
+
|
|
385
|
+
```xs
|
|
386
|
+
query clear verb=DELETE {
|
|
387
|
+
api_group = "events"
|
|
388
|
+
input {}
|
|
389
|
+
|
|
390
|
+
stack {
|
|
391
|
+
db.truncate event
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
response = null
|
|
395
|
+
}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
## Complete Ephemeral Job Example
|
|
399
|
+
|
|
400
|
+
Here's a complete ephemeral job that seeds and validates data:
|
|
401
|
+
|
|
402
|
+
**`ephemeral/data-validation/workspace.xs`:**
|
|
403
|
+
|
|
404
|
+
```xs
|
|
405
|
+
workspace data_validation {
|
|
406
|
+
env = {
|
|
407
|
+
webhook_url: "https://webhook.site/your-id"
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**`ephemeral/data-validation/tables/authors.xs`:**
|
|
413
|
+
|
|
414
|
+
```xs
|
|
415
|
+
table authors {
|
|
416
|
+
auth = false
|
|
417
|
+
|
|
418
|
+
schema {
|
|
419
|
+
int id
|
|
420
|
+
timestamp created_at?=now
|
|
421
|
+
text name? filters=trim
|
|
422
|
+
text desc? filters=trim
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
index = [
|
|
426
|
+
{type: "primary", field: [{name: "id"}]}
|
|
427
|
+
{type: "btree", field: [{name: "created_at", op: "desc"}]}
|
|
428
|
+
]
|
|
429
|
+
|
|
430
|
+
items = [
|
|
431
|
+
{"id":1,"created_at":1761410450342,"name":"Kathryn Watson","desc":"aa"}
|
|
432
|
+
{"id":2,"created_at":1761410450344,"name":"Martha Torres","desc":"aa"}
|
|
433
|
+
{"id":3,"created_at":1761410450345,"name":"Raymond Rivera","desc":"aa"}
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**`ephemeral/data-validation/functions/$main.xs`:**
|
|
439
|
+
|
|
440
|
+
```xs
|
|
441
|
+
function "$main" {
|
|
442
|
+
input {
|
|
443
|
+
json args
|
|
444
|
+
json pre
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
stack {
|
|
448
|
+
db.add authors {
|
|
449
|
+
data = {name: "New Author"}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
db.query authors {
|
|
453
|
+
return = {type: "count"}
|
|
454
|
+
} as $cnt
|
|
455
|
+
|
|
456
|
+
precondition ($cnt == 4) {
|
|
457
|
+
error = "Expected 4 authors after insert"
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
response = $cnt
|
|
462
|
+
}
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
**`ephemeral/data-validation/functions/$post.xs`:**
|
|
466
|
+
|
|
467
|
+
```xs
|
|
468
|
+
function "$post" {
|
|
469
|
+
input {
|
|
470
|
+
json args
|
|
471
|
+
json pre
|
|
472
|
+
json main
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
stack {
|
|
476
|
+
api.request {
|
|
477
|
+
url = $env.webhook_url
|
|
478
|
+
params = {
|
|
479
|
+
status: "complete"
|
|
480
|
+
result: $input.main
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
response = null
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
## Using the Chat Tool
|
|
490
|
+
|
|
491
|
+
You can create ephemeral services and jobs directly from VS Code using the `publish_ephemeral_service` chat tool.
|
|
492
|
+
|
|
493
|
+
### Parameters
|
|
494
|
+
|
|
495
|
+
| Parameter | Type | Description |
|
|
496
|
+
| ----------- | ------ | --------------------------------------------------------- |
|
|
497
|
+
| `name` | string | A name for the ephemeral service or job |
|
|
498
|
+
| `directory` | string | The directory containing the XanoScript files to deploy |
|
|
499
|
+
| `mode` | enum | Either `"service"` (stays running) or `"job"` (runs once) |
|
|
500
|
+
|
|
501
|
+
### Example Usage
|
|
502
|
+
|
|
503
|
+
To deploy a service:
|
|
504
|
+
|
|
505
|
+
```
|
|
506
|
+
@publish_ephemeral_service name="my-api" directory="ephemeral/my-service" mode="service"
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
To run a job:
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
@publish_ephemeral_service name="data-migration" directory="ephemeral/my-job" mode="job"
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
The tool will bundle all XanoScript files in the specified directory and deploy them according to the selected mode.
|
|
516
|
+
|
|
517
|
+
## Best Practices
|
|
518
|
+
|
|
519
|
+
1. **Keep services isolated**: Each ephemeral service should be self-contained with its own tables, functions, and endpoints.
|
|
520
|
+
|
|
521
|
+
2. **Seed test data**: Use the `items` property in table definitions to pre-populate data for testing.
|
|
522
|
+
|
|
523
|
+
3. **Use environment variables**: Store configuration values in the workspace `env` block rather than hardcoding them.
|
|
524
|
+
|
|
525
|
+
4. **Clean up after jobs**: Use the `$post` function to send notifications or perform cleanup after job execution.
|
|
526
|
+
|
|
527
|
+
5. **Validate with preconditions**: Use `precondition` statements in jobs to verify expected outcomes.
|
|
528
|
+
|
|
529
|
+
6. **Organize by purpose**: Name your ephemeral directories clearly to indicate their purpose (e.g., `ephemeral/auth-test/`, `ephemeral/data-migration/`).
|