@xano/developer-mcp 1.0.9 → 1.0.11
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 +5 -10
- package/dist/index.js +5 -83
- package/package.json +1 -1
- package/xanoscript_docs/addons.md +57 -86
package/README.md
CHANGED
|
@@ -212,21 +212,17 @@ xanoscript_docs({ file_path: "apis/users/create.xs" })
|
|
|
212
212
|
xanoscript_docs({ topic: "database", mode: "quick_reference" })
|
|
213
213
|
```
|
|
214
214
|
|
|
215
|
-
### 4. `
|
|
215
|
+
### 4. `mcp_version`
|
|
216
216
|
|
|
217
|
-
Get
|
|
217
|
+
Get the current version of the Xano Developer MCP server.
|
|
218
218
|
|
|
219
219
|
**Parameters:** None
|
|
220
220
|
|
|
221
|
-
**Returns:**
|
|
222
|
-
- Directory structure for local development
|
|
223
|
-
- File naming conventions
|
|
224
|
-
- Registry format for tracking changes
|
|
225
|
-
- Workflows for pulling/pushing XanoScript files via the Headless API
|
|
221
|
+
**Returns:** The version string from package.json.
|
|
226
222
|
|
|
227
223
|
**Example:**
|
|
228
224
|
```
|
|
229
|
-
|
|
225
|
+
mcp_version()
|
|
230
226
|
```
|
|
231
227
|
|
|
232
228
|
## MCP Resources
|
|
@@ -276,7 +272,6 @@ xano-developer-mcp/
|
|
|
276
272
|
│ ├── index.ts # Main MCP server implementation
|
|
277
273
|
│ ├── xanoscript.d.ts # TypeScript declarations
|
|
278
274
|
│ └── templates/
|
|
279
|
-
│ ├── init-workspace.ts # Workspace initialization template
|
|
280
275
|
│ └── xanoscript-index.ts
|
|
281
276
|
├── dist/ # Compiled JavaScript output
|
|
282
277
|
├── scripts/
|
|
@@ -322,7 +317,7 @@ Xano Developer MCP Server
|
|
|
322
317
|
│
|
|
323
318
|
├─► xanoscript_docs → Context-aware docs from /xanoscript_docs/*.md
|
|
324
319
|
│
|
|
325
|
-
├─►
|
|
320
|
+
├─► mcp_version → Returns server version from package.json
|
|
326
321
|
│
|
|
327
322
|
└─► MCP Resources → Direct access to documentation files
|
|
328
323
|
```
|
package/dist/index.js
CHANGED
|
@@ -8,7 +8,6 @@ import { dirname, join } from "path";
|
|
|
8
8
|
import { minimatch } from "minimatch";
|
|
9
9
|
import { xanoscriptParser } from "@xano/xanoscript-language-server/parser/parser.js";
|
|
10
10
|
import { getSchemeFromContent } from "@xano/xanoscript-language-server/utils.js";
|
|
11
|
-
import { generateInitWorkspaceTemplate } from "./templates/init-workspace.js";
|
|
12
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
12
|
const __dirname = dirname(__filename);
|
|
14
13
|
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
@@ -134,69 +133,6 @@ const XANOSCRIPT_DOCS_V2 = {
|
|
|
134
133
|
description: "Streaming data from files, requests, and responses",
|
|
135
134
|
},
|
|
136
135
|
};
|
|
137
|
-
const XANO_OBJECT_TYPES = {
|
|
138
|
-
function: {
|
|
139
|
-
path: "functions",
|
|
140
|
-
endpoint: "function",
|
|
141
|
-
extension: ".xs",
|
|
142
|
-
hasXanoscript: true,
|
|
143
|
-
},
|
|
144
|
-
table: {
|
|
145
|
-
path: "tables",
|
|
146
|
-
endpoint: "table",
|
|
147
|
-
extension: ".xs",
|
|
148
|
-
hasXanoscript: true,
|
|
149
|
-
},
|
|
150
|
-
task: {
|
|
151
|
-
path: "tasks",
|
|
152
|
-
endpoint: "task",
|
|
153
|
-
extension: ".xs",
|
|
154
|
-
hasXanoscript: true,
|
|
155
|
-
},
|
|
156
|
-
api_group: {
|
|
157
|
-
path: "apis",
|
|
158
|
-
endpoint: "api-group",
|
|
159
|
-
extension: ".xs",
|
|
160
|
-
hasXanoscript: true,
|
|
161
|
-
supportsNesting: true,
|
|
162
|
-
},
|
|
163
|
-
tool: {
|
|
164
|
-
path: "tools",
|
|
165
|
-
endpoint: "tool",
|
|
166
|
-
extension: ".xs",
|
|
167
|
-
hasXanoscript: true,
|
|
168
|
-
},
|
|
169
|
-
agent: {
|
|
170
|
-
path: "agents",
|
|
171
|
-
endpoint: "agent",
|
|
172
|
-
extension: ".xs",
|
|
173
|
-
hasXanoscript: true,
|
|
174
|
-
},
|
|
175
|
-
middleware: {
|
|
176
|
-
path: "middlewares",
|
|
177
|
-
endpoint: "middleware",
|
|
178
|
-
extension: ".xs",
|
|
179
|
-
hasXanoscript: true,
|
|
180
|
-
},
|
|
181
|
-
addon: {
|
|
182
|
-
path: "addons",
|
|
183
|
-
endpoint: "addon",
|
|
184
|
-
extension: ".xs",
|
|
185
|
-
hasXanoscript: true,
|
|
186
|
-
},
|
|
187
|
-
mcp_server: {
|
|
188
|
-
path: "mcp_servers",
|
|
189
|
-
endpoint: "mcp-server",
|
|
190
|
-
extension: ".xs",
|
|
191
|
-
hasXanoscript: true,
|
|
192
|
-
},
|
|
193
|
-
realtime_channel: {
|
|
194
|
-
path: "realtime",
|
|
195
|
-
endpoint: "realtime-channel",
|
|
196
|
-
extension: ".xs",
|
|
197
|
-
hasXanoscript: true,
|
|
198
|
-
},
|
|
199
|
-
};
|
|
200
136
|
// =============================================================================
|
|
201
137
|
// API Documentation Configuration
|
|
202
138
|
// =============================================================================
|
|
@@ -383,17 +319,6 @@ function readXanoscriptDocsV2(args) {
|
|
|
383
319
|
}
|
|
384
320
|
}
|
|
385
321
|
// =============================================================================
|
|
386
|
-
// Init Workspace Documentation
|
|
387
|
-
// =============================================================================
|
|
388
|
-
function generateInitWorkspaceDoc() {
|
|
389
|
-
const objectTypes = Object.entries(XANO_OBJECT_TYPES).map(([type, config]) => ({
|
|
390
|
-
type,
|
|
391
|
-
path: config.path,
|
|
392
|
-
endpoint: config.endpoint,
|
|
393
|
-
}));
|
|
394
|
-
return generateInitWorkspaceTemplate(objectTypes);
|
|
395
|
-
}
|
|
396
|
-
// =============================================================================
|
|
397
322
|
// MCP Server Setup
|
|
398
323
|
// =============================================================================
|
|
399
324
|
const server = new Server({
|
|
@@ -507,11 +432,9 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
507
432
|
},
|
|
508
433
|
},
|
|
509
434
|
{
|
|
510
|
-
name: "
|
|
511
|
-
description: "Get
|
|
512
|
-
"Returns
|
|
513
|
-
"and workflows for pulling/pushing XanoScript files via the Headless API. " +
|
|
514
|
-
"Use this when setting up local development for Xano projects.",
|
|
435
|
+
name: "mcp_version",
|
|
436
|
+
description: "Get the current version of the Xano Developer MCP server. " +
|
|
437
|
+
"Returns the version string from package.json.",
|
|
515
438
|
inputSchema: {
|
|
516
439
|
type: "object",
|
|
517
440
|
properties: {},
|
|
@@ -619,13 +542,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
619
542
|
],
|
|
620
543
|
};
|
|
621
544
|
}
|
|
622
|
-
if (request.params.name === "
|
|
623
|
-
const documentation = generateInitWorkspaceDoc();
|
|
545
|
+
if (request.params.name === "mcp_version") {
|
|
624
546
|
return {
|
|
625
547
|
content: [
|
|
626
548
|
{
|
|
627
549
|
type: "text",
|
|
628
|
-
text:
|
|
550
|
+
text: SERVER_VERSION,
|
|
629
551
|
},
|
|
630
552
|
],
|
|
631
553
|
};
|
package/package.json
CHANGED
|
@@ -9,15 +9,16 @@ Reusable subqueries for fetching related data in database queries.
|
|
|
9
9
|
## Quick Reference
|
|
10
10
|
|
|
11
11
|
```xs
|
|
12
|
-
addon
|
|
13
|
-
description = "What this addon fetches"
|
|
12
|
+
addon <name> {
|
|
14
13
|
input {
|
|
15
14
|
<type> <name>
|
|
16
15
|
}
|
|
16
|
+
|
|
17
17
|
stack {
|
|
18
|
-
|
|
18
|
+
db.query <tableName> {
|
|
19
|
+
return = {type: "<return_type>"}
|
|
20
|
+
}
|
|
19
21
|
}
|
|
20
|
-
response = $result
|
|
21
22
|
}
|
|
22
23
|
```
|
|
23
24
|
|
|
@@ -25,21 +26,20 @@ addon "<name>" {
|
|
|
25
26
|
|
|
26
27
|
## Basic Structure
|
|
27
28
|
|
|
28
|
-
Addons define reusable data fetching logic that can be attached to query results.
|
|
29
|
+
Addons define reusable data fetching logic that can be attached to query results. The stack can only contain a `db.query` block.
|
|
29
30
|
|
|
30
31
|
```xs
|
|
31
|
-
addon
|
|
32
|
-
description = "Count of comments for a post"
|
|
32
|
+
addon comment_count {
|
|
33
33
|
input {
|
|
34
34
|
int post_id
|
|
35
35
|
}
|
|
36
|
+
|
|
36
37
|
stack {
|
|
37
|
-
db.query
|
|
38
|
+
db.query comment {
|
|
38
39
|
where = $db.comment.post_id == $input.post_id
|
|
39
|
-
return = {
|
|
40
|
-
}
|
|
40
|
+
return = {type: "count"}
|
|
41
|
+
}
|
|
41
42
|
}
|
|
42
|
-
response = $count
|
|
43
43
|
}
|
|
44
44
|
```
|
|
45
45
|
|
|
@@ -50,12 +50,12 @@ addon "comment_count" {
|
|
|
50
50
|
### In db.query
|
|
51
51
|
|
|
52
52
|
```xs
|
|
53
|
-
db.query
|
|
53
|
+
db.query post {
|
|
54
54
|
where = $db.post.author_id == $auth.id
|
|
55
55
|
addon = [
|
|
56
56
|
{
|
|
57
57
|
name: "comment_count",
|
|
58
|
-
input: {
|
|
58
|
+
input: {post_id: $output.id},
|
|
59
59
|
as: "items.comment_count"
|
|
60
60
|
}
|
|
61
61
|
]
|
|
@@ -79,22 +79,22 @@ db.query "post" {
|
|
|
79
79
|
### Multiple Addons
|
|
80
80
|
|
|
81
81
|
```xs
|
|
82
|
-
db.query
|
|
82
|
+
db.query post {
|
|
83
83
|
where = $db.post.is_published == true
|
|
84
84
|
addon = [
|
|
85
85
|
{
|
|
86
86
|
name: "comment_count",
|
|
87
|
-
input: {
|
|
87
|
+
input: {post_id: $output.id},
|
|
88
88
|
as: "items.comments"
|
|
89
89
|
},
|
|
90
90
|
{
|
|
91
91
|
name: "like_count",
|
|
92
|
-
input: {
|
|
92
|
+
input: {post_id: $output.id},
|
|
93
93
|
as: "items.likes"
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
name: "author_details",
|
|
97
|
-
input: {
|
|
97
|
+
input: {user_id: $output.author_id},
|
|
98
98
|
as: "items.author"
|
|
99
99
|
}
|
|
100
100
|
]
|
|
@@ -108,103 +108,75 @@ db.query "post" {
|
|
|
108
108
|
### Related List
|
|
109
109
|
|
|
110
110
|
```xs
|
|
111
|
-
addon
|
|
112
|
-
description = "Get recent comments for a post"
|
|
111
|
+
addon recent_comments {
|
|
113
112
|
input {
|
|
114
113
|
int post_id
|
|
115
114
|
int limit?=5
|
|
116
115
|
}
|
|
116
|
+
|
|
117
117
|
stack {
|
|
118
|
-
db.query
|
|
118
|
+
db.query comment {
|
|
119
119
|
where = $db.comment.post_id == $input.post_id
|
|
120
|
-
sort = {
|
|
120
|
+
sort = {created_at: "desc"}
|
|
121
121
|
return = {
|
|
122
122
|
type: "list",
|
|
123
|
-
paging: {
|
|
123
|
+
paging: {per_page: $input.limit}
|
|
124
124
|
}
|
|
125
|
-
}
|
|
125
|
+
}
|
|
126
126
|
}
|
|
127
|
-
response = $comments.items
|
|
128
127
|
}
|
|
129
128
|
```
|
|
130
129
|
|
|
131
|
-
###
|
|
130
|
+
### Count
|
|
132
131
|
|
|
133
132
|
```xs
|
|
134
|
-
addon
|
|
135
|
-
description = "Order statistics for a user"
|
|
133
|
+
addon order_count {
|
|
136
134
|
input {
|
|
137
135
|
int user_id
|
|
138
136
|
}
|
|
137
|
+
|
|
139
138
|
stack {
|
|
140
|
-
db.query
|
|
139
|
+
db.query order {
|
|
141
140
|
where = $db.order.user_id == $input.user_id
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
var $stats {
|
|
145
|
-
value = {
|
|
146
|
-
total_orders: $orders|count,
|
|
147
|
-
total_spent: $orders|map:$$.total|sum,
|
|
148
|
-
avg_order: $orders|map:$$.total|avg
|
|
149
|
-
}
|
|
141
|
+
return = {type: "count"}
|
|
150
142
|
}
|
|
151
143
|
}
|
|
152
|
-
response = $stats
|
|
153
144
|
}
|
|
154
145
|
```
|
|
155
146
|
|
|
156
|
-
###
|
|
147
|
+
### Boolean Check (Exists)
|
|
157
148
|
|
|
158
149
|
```xs
|
|
159
|
-
addon
|
|
160
|
-
description = "Get formatted address for a user"
|
|
150
|
+
addon has_premium {
|
|
161
151
|
input {
|
|
162
152
|
int user_id
|
|
163
153
|
}
|
|
154
|
+
|
|
164
155
|
stack {
|
|
165
|
-
db.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
conditional {
|
|
171
|
-
if ($address != null) {
|
|
172
|
-
var $formatted {
|
|
173
|
-
value = {
|
|
174
|
-
street: $address.street,
|
|
175
|
-
city: $address.city,
|
|
176
|
-
state: $address.state,
|
|
177
|
-
zip: $address.zip,
|
|
178
|
-
full: $address.street ~ ", " ~ $address.city ~ ", " ~ $address.state ~ " " ~ $address.zip
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
var $formatted { value = null }
|
|
184
|
-
}
|
|
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"}
|
|
185
161
|
}
|
|
186
162
|
}
|
|
187
|
-
response = $formatted
|
|
188
163
|
}
|
|
189
164
|
```
|
|
190
165
|
|
|
191
|
-
###
|
|
166
|
+
### Single Record
|
|
192
167
|
|
|
193
168
|
```xs
|
|
194
|
-
addon
|
|
195
|
-
description = "Check if user has premium subscription"
|
|
169
|
+
addon author_details {
|
|
196
170
|
input {
|
|
197
171
|
int user_id
|
|
198
172
|
}
|
|
173
|
+
|
|
199
174
|
stack {
|
|
200
|
-
db.query
|
|
201
|
-
where = $db.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return = { type: "exists" }
|
|
205
|
-
} as $has_premium
|
|
175
|
+
db.query user {
|
|
176
|
+
where = $db.user.id == $input.user_id
|
|
177
|
+
return = {type: "single"}
|
|
178
|
+
}
|
|
206
179
|
}
|
|
207
|
-
response = $has_premium
|
|
208
180
|
}
|
|
209
181
|
```
|
|
210
182
|
|
|
@@ -215,8 +187,8 @@ addon "has_premium" {
|
|
|
215
187
|
Call an addon directly from a function or API.
|
|
216
188
|
|
|
217
189
|
```xs
|
|
218
|
-
addon.call
|
|
219
|
-
input = {
|
|
190
|
+
addon.call comment_count {
|
|
191
|
+
input = {post_id: $input.post_id}
|
|
220
192
|
} as $count
|
|
221
193
|
```
|
|
222
194
|
|
|
@@ -224,16 +196,16 @@ addon.call "comment_count" {
|
|
|
224
196
|
|
|
225
197
|
```xs
|
|
226
198
|
// Get stats for single record
|
|
227
|
-
addon.call
|
|
228
|
-
input = {
|
|
229
|
-
} as $
|
|
199
|
+
addon.call order_count {
|
|
200
|
+
input = {user_id: $auth.id}
|
|
201
|
+
} as $my_order_count
|
|
230
202
|
|
|
231
203
|
// Conditional addon call
|
|
232
204
|
conditional {
|
|
233
205
|
if ($input.include_stats) {
|
|
234
|
-
addon.call
|
|
235
|
-
input = {
|
|
236
|
-
} as $
|
|
206
|
+
addon.call order_count {
|
|
207
|
+
input = {user_id: $entity.id}
|
|
208
|
+
} as $count
|
|
237
209
|
}
|
|
238
210
|
}
|
|
239
211
|
```
|
|
@@ -245,9 +217,9 @@ conditional {
|
|
|
245
217
|
Use `dbAddonAttr` for computed fields in queries.
|
|
246
218
|
|
|
247
219
|
```xs
|
|
248
|
-
db.query
|
|
220
|
+
db.query product {
|
|
249
221
|
eval = {
|
|
250
|
-
discount_price: dbAddonAttr("calculate_discount", {
|
|
222
|
+
discount_price: dbAddonAttr("calculate_discount", {product_id: $db.product.id})
|
|
251
223
|
}
|
|
252
224
|
} as $products
|
|
253
225
|
```
|
|
@@ -263,7 +235,7 @@ addons/
|
|
|
263
235
|
├── comment_count.xs
|
|
264
236
|
├── like_count.xs
|
|
265
237
|
├── author_details.xs
|
|
266
|
-
├──
|
|
238
|
+
├── order_count.xs
|
|
267
239
|
└── has_premium.xs
|
|
268
240
|
```
|
|
269
241
|
|
|
@@ -279,7 +251,6 @@ addons/
|
|
|
279
251
|
|
|
280
252
|
1. **Keep addons focused** - One purpose per addon
|
|
281
253
|
2. **Use input parameters** - Make addons reusable
|
|
282
|
-
3. **
|
|
283
|
-
4. **
|
|
284
|
-
5. **
|
|
285
|
-
6. **Document inputs** - Add descriptions to input fields
|
|
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
|