@xano/developer-mcp 1.0.6 → 1.0.8

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
@@ -39,6 +39,18 @@ Add to your Claude Desktop configuration file:
39
39
  }
40
40
  ```
41
41
 
42
+ ## Checking Your Version
43
+
44
+ ```bash
45
+ npx @xano/developer-mcp --version
46
+ ```
47
+
48
+ If installed from source:
49
+
50
+ ```bash
51
+ node dist/index.js --version
52
+ ```
53
+
42
54
  ## Installation from Source
43
55
 
44
56
  ### Prerequisites
package/dist/index.js CHANGED
@@ -11,6 +11,12 @@ import { getSchemeFromContent } from "@xano/xanoscript-language-server/utils.js"
11
11
  import { generateInitWorkspaceTemplate } from "./templates/init-workspace.js";
12
12
  const __filename = fileURLToPath(import.meta.url);
13
13
  const __dirname = dirname(__filename);
14
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
15
+ const SERVER_VERSION = pkg.version;
16
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
17
+ console.log(SERVER_VERSION);
18
+ process.exit(0);
19
+ }
14
20
  const XANOSCRIPT_DOCS_V2 = {
15
21
  readme: {
16
22
  file: "README.md",
@@ -357,7 +363,7 @@ function generateInitWorkspaceDoc() {
357
363
  // =============================================================================
358
364
  const server = new Server({
359
365
  name: "xano-developer-mcp",
360
- version: "1.0.0",
366
+ version: SERVER_VERSION,
361
367
  description: "MCP server for Xano Headless API documentation and XanoScript code validation",
362
368
  }, {
363
369
  capabilities: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/developer-mcp",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "MCP server for Xano Headless API documentation and XanoScript code validation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -16,22 +16,24 @@ XanoScript is the declarative scripting language for [Xano](https://xano.com), a
16
16
  | `mcp_server` | `mcp_servers/**/*.xs` | MCP server definitions |
17
17
  | `addon` | `addons/*.xs` | Subqueries for related data |
18
18
 
19
+ **Important:** Each `.xs` file must contain exactly one definition. You cannot define multiple tables, functions, queries, or other constructs in a single file.
20
+
19
21
  ## Workspace Structure
20
22
 
21
23
  ```
22
24
  project/
23
- ├── tables/ # Database table schemas
24
- ├── functions/ # Reusable functions (supports subfolders)
25
+ ├── tables/ // Database table schemas
26
+ ├── functions/ // Reusable functions (supports subfolders)
25
27
  ├── apis/
26
- │ └── <api-group>/ # API endpoints grouped by domain
27
- ├── tasks/ # Scheduled jobs
28
- ├── triggers/ # Event-driven handlers
29
- ├── agents/ # AI agents
30
- ├── tools/ # AI tools
31
- ├── mcp_servers/ # MCP server definitions
32
- ├── addons/ # Query addons
33
- ├── static/ # Frontend files (HTML, CSS, JS)
34
- └── ephemeral/ # Temporary test environments
28
+ │ └── <api-group>/ // API endpoints grouped by domain
29
+ ├── tasks/ // Scheduled jobs
30
+ ├── triggers/ // Event-driven handlers
31
+ ├── agents/ // AI agents
32
+ ├── tools/ // AI tools
33
+ ├── mcp_servers/ // MCP server definitions
34
+ ├── addons/ // Query addons
35
+ ├── static/ // Frontend files (HTML, CSS, JS)
36
+ └── ephemeral/ // Temporary test environments
35
37
  ```
36
38
 
37
39
  ## Environment Variables
@@ -55,28 +57,36 @@ Custom environment variables are set in the Xano dashboard and accessed as `$env
55
57
  ### Block Structure
56
58
  ```xs
57
59
  <construct> "<name>" {
58
- input { ... } # Parameters (optional)
59
- stack { ... } # Logic
60
- response = $var # Output
60
+ input { ... } // Parameters (optional)
61
+ stack { ... } // Logic
62
+ response = $var // Output
61
63
  }
62
64
  ```
63
65
 
64
66
  ### Variable Access
65
67
  ```xs
66
- $input.field # Input parameters
67
- $var.field # Stack variables
68
- $auth.id # Authenticated user ID
69
- $env.MY_VAR # Environment variable
70
- $db.table.field # Database field reference (in queries)
71
- $this # Current item in loops/maps
68
+ $input.field // Input parameters
69
+ $var.field // Stack variables
70
+ $auth.id // Authenticated user ID
71
+ $env.MY_VAR // Environment variable
72
+ $db.table.field // Database field reference (in queries)
73
+ $this // Current item in loops/maps
72
74
  ```
73
75
 
76
+ ### Comments
77
+ ```xs
78
+ // Single-line comment
79
+ var $total { value = 0 } // Inline comment
80
+ ```
81
+
82
+ **Note:** XanoScript only supports `//` for comments. Other comment styles like `#` are not supported.
83
+
74
84
  ### Filters (Pipe Syntax)
75
85
  ```xs
76
- $value|trim|lower # Chain filters
77
- $input.name|strlen # Get length
78
- $array|first # First element
79
- ($a + $b)|round:2 # Math with precision
86
+ $value|trim|lower // Chain filters
87
+ $input.name|strlen // Get length
88
+ $array|first // First element
89
+ ($a + $b)|round:2 // Math with precision
80
90
  ```
81
91
 
82
92
  ## File Frontmatter
@@ -71,10 +71,10 @@ ai.agent.run "Customer Support" {
71
71
 
72
72
  ```xs
73
73
  llm = {
74
- type: "<provider>" # Required
75
- system_prompt: "..." # Agent persona and rules
76
- prompt: "{{ $args.input }}" # User input template
77
- max_steps: 5 # Max LLM calls per run
74
+ type: "<provider>" // Required
75
+ system_prompt: "..." // Agent persona and rules
76
+ prompt: "{{ $args.input }}" // User input template
77
+ max_steps: 5 // Max LLM calls per run
78
78
  }
79
79
  ```
80
80
 
@@ -94,7 +94,7 @@ llm = {
94
94
  prompt: "{{ $args.message }}"
95
95
  max_steps: 3
96
96
  temperature: 0
97
- search_grounding: false # Google Search grounding
97
+ search_grounding: false // Google Search grounding
98
98
  }
99
99
  ```
100
100
 
@@ -108,7 +108,7 @@ llm = {
108
108
  prompt: "{{ $args.message }}"
109
109
  max_steps: 5
110
110
  temperature: 0.2
111
- thinking_tokens: 10000 # Extended thinking
111
+ thinking_tokens: 10000 // Extended thinking
112
112
  include_thoughts: true
113
113
  }
114
114
  ```
@@ -123,7 +123,7 @@ llm = {
123
123
  prompt: "{{ $args.message }}"
124
124
  max_steps: 5
125
125
  temperature: 0.8
126
- reasoning_effort: "medium" # low, medium, high
126
+ reasoning_effort: "medium" // low, medium, high
127
127
  }
128
128
  ```
129
129
 
@@ -134,7 +134,7 @@ llm = {
134
134
  api_key: "{{ $env.GROQ_API_KEY }}"
135
135
  baseURL: "https://api.groq.com/openai/v1"
136
136
  model: "llama-3.3-70b-versatile"
137
- compatibility: "compatible" # Required for non-OpenAI
137
+ compatibility: "compatible" // Required for non-OpenAI
138
138
  ...
139
139
  }
140
140
  ```
@@ -151,7 +151,7 @@ llm = {
151
151
  prompt: "{{ $args.message }}"
152
152
  max_steps: 8
153
153
  temperature: 0.3
154
- send_reasoning: true # Include thinking blocks
154
+ send_reasoning: true // Include thinking blocks
155
155
  }
156
156
  ```
157
157
 
@@ -218,9 +218,9 @@ llm = {
218
218
 
219
219
  ### Available Variables
220
220
  ```xs
221
- {{ $args.any_arg }} # Runtime arguments
222
- {{ $env.MY_VAR }} # Environment variables
223
- {{ "now"|date("Y-m-d") }} # Current date
221
+ {{ $args.any_arg }} // Runtime arguments
222
+ {{ $env.MY_VAR }} // Environment variables
223
+ {{ "now"|date("Y-m-d") }} // Current date
224
224
  ```
225
225
 
226
226
  ---
@@ -9,19 +9,19 @@ HTTP endpoint definitions in XanoScript.
9
9
  ## Quick Reference
10
10
 
11
11
  ```xs
12
- query "<name>" verb=<METHOD> {
13
- api_group = "<GroupName>" # Required: API group for organization
12
+ query "endpoint-path" verb=<METHOD> {
13
+ api_group = "<GroupName>" // Required: API group for organization
14
14
  description = "What this endpoint does"
15
- auth = "<table>" # Optional: require authentication
15
+ auth = "<table>" // Optional: require authentication
16
16
  input { ... }
17
17
  stack { ... }
18
18
  response = $result
19
19
  }
20
20
  ```
21
21
 
22
- ### Query Name (Required)
22
+ ### Query Name (Required, Non-Empty)
23
23
 
24
- The query name is **required** and cannot be empty. It defines the endpoint path after the API group canonical.
24
+ The query name is **required** and **must be a non-empty string**. Empty names (`query "" verb=...`) are invalid. The name defines the endpoint path after the API group canonical.
25
25
 
26
26
  **Full URL path structure:**
27
27
  ```
@@ -42,8 +42,8 @@ Every endpoint must belong to an API group. Each group is a folder with an `api_
42
42
 
43
43
  ```xs
44
44
  api_group "users" {
45
- canonical = "users" # Required: URL path segment
46
- description = "User management" # Optional
45
+ canonical = "users" // Required: URL path segment
46
+ description = "User management" // Optional
47
47
  }
48
48
  ```
49
49
 
@@ -51,12 +51,12 @@ api_group "users" {
51
51
  ```
52
52
  apis/
53
53
  ├── users/
54
- │ ├── api_group.xs # Defines group (canonical = "users")
55
- │ ├── list.xs # GET /users/list
56
- │ └── by-id.xs # GET/PATCH/DELETE /users/{id}
54
+ │ ├── api_group.xs // Defines group (canonical = "users")
55
+ │ ├── list.xs // GET /users/list
56
+ │ └── by-id.xs // GET/PATCH/DELETE /users/{id}
57
57
  └── products/
58
- ├── api_group.xs # Defines group (canonical = "products")
59
- └── search.xs # GET /products/search
58
+ ├── api_group.xs // Defines group (canonical = "products")
59
+ └── search.xs // GET /products/search
60
60
  ```
61
61
 
62
62
  Full URL: `/<canonical>/<query name>` (e.g., `/users/profile`)
@@ -99,11 +99,11 @@ query "status" verb=GET {
99
99
  ```xs
100
100
  query "profile" verb=GET {
101
101
  api_group = "Users"
102
- auth = "user" # Requires valid JWT
102
+ auth = "user" // Requires valid JWT
103
103
  stack {
104
104
  db.get "user" {
105
105
  field_name = "id"
106
- field_value = $auth.id # User ID from token
106
+ field_value = $auth.id // User ID from token
107
107
  } as $user
108
108
  }
109
109
  response = $user
@@ -35,7 +35,7 @@ db.query "product" {
35
35
 
36
36
  ### Where Operators
37
37
  ```xs
38
- # Comparison
38
+ // Comparison
39
39
  $db.product.price == 100
40
40
  $db.product.price != 0
41
41
  $db.product.price > 50
@@ -43,32 +43,32 @@ $db.product.price >= 50
43
43
  $db.product.price < 100
44
44
  $db.product.price <= 100
45
45
 
46
- # Null-safe (ignore if value is null)
46
+ // Null-safe (ignore if value is null)
47
47
  $db.product.category ==? $input.category
48
48
  $db.product.price >=? $input.min_price
49
49
 
50
- # String matching
51
- $db.product.name includes "phone" # Contains substring
52
- $db.product.tags contains "featured" # Array contains value
50
+ // String matching
51
+ $db.product.name includes "phone" // Contains substring
52
+ $db.product.tags contains "featured" // Array contains value
53
53
  $db.product.tags not contains "hidden"
54
54
 
55
- # Array overlap
55
+ // Array overlap
56
56
  $db.product.tags overlaps ["a", "b"]
57
57
  $db.product.tags not overlaps ["x", "y"]
58
58
 
59
- # Combining conditions
59
+ // Combining conditions
60
60
  $db.product.is_active == true && $db.product.price > 0
61
61
  $db.product.category == "electronics" || $db.product.featured == true
62
62
  ```
63
63
 
64
64
  ### Return Types
65
65
  ```xs
66
- # List (default)
66
+ // List (default)
67
67
  db.query "product" {
68
68
  return = { type: "list" }
69
69
  } as $products
70
70
 
71
- # With pagination
71
+ // With pagination
72
72
  db.query "product" {
73
73
  return = {
74
74
  type: "list",
@@ -76,19 +76,19 @@ db.query "product" {
76
76
  }
77
77
  } as $products
78
78
 
79
- # Single record
79
+ // Single record
80
80
  db.query "product" {
81
81
  where = $db.product.sku == $input.sku
82
82
  return = { type: "single" }
83
83
  } as $product
84
84
 
85
- # Count
85
+ // Count
86
86
  db.query "product" {
87
87
  where = $db.product.is_active == true
88
88
  return = { type: "count" }
89
89
  } as $count
90
90
 
91
- # Exists
91
+ // Exists
92
92
  db.query "product" {
93
93
  where = $db.product.email == $input.email
94
94
  return = { type: "exists" }
@@ -98,9 +98,9 @@ db.query "product" {
98
98
  ### Sorting
99
99
  ```xs
100
100
  db.query "product" {
101
- sort = { created_at: "desc" } # Descending
102
- sort = { name: "asc" } # Ascending
103
- sort = { id: "rand" } # Random
101
+ sort = { created_at: "desc" } // Descending
102
+ sort = { name: "asc" } // Ascending
103
+ sort = { id: "rand" } // Random
104
104
  } as $products
105
105
  ```
106
106
 
@@ -110,7 +110,7 @@ db.query "comment" {
110
110
  join = {
111
111
  post: {
112
112
  table: "post",
113
- type: "inner", # inner, left, right
113
+ type: "inner", // inner, left, right
114
114
  where: $db.comment.post_id == $db.post.id
115
115
  }
116
116
  }
@@ -279,7 +279,7 @@ Delete all records from a table.
279
279
 
280
280
  ```xs
281
281
  db.truncate "temp_data" {
282
- reset = true # Reset auto-increment
282
+ reset = true // Reset auto-increment
283
283
  }
284
284
  ```
285
285
 
@@ -293,7 +293,7 @@ Execute raw SQL (use sparingly).
293
293
  db.direct_query {
294
294
  sql = "SELECT * FROM users WHERE email = ? AND status = ?"
295
295
  arg = [$input.email, "active"]
296
- response_type = "list" # list or single
296
+ response_type = "list" // list or single
297
297
  } as $results
298
298
  ```
299
299
 
@@ -339,9 +339,9 @@ Filters for use in `where` clauses:
339
339
 
340
340
  ### String/Text
341
341
  ```xs
342
- $db.name|to_lower # Case conversion
343
- $db.name|concat:" " # Concatenation
344
- $db.text|substr:0:100 # Substring
342
+ $db.name|to_lower // Case conversion
343
+ $db.name|concat:" " // Concatenation
344
+ $db.text|substr:0:100 // Substring
345
345
  ```
346
346
 
347
347
  ### Numeric
@@ -363,8 +363,8 @@ $db.created_at|timestamp_subtract_hours:24
363
363
 
364
364
  ### Geographic
365
365
  ```xs
366
- $db.location|distance:$input.point # Distance in meters
367
- $db.location|within:$input.point:1000 # Within radius
366
+ $db.location|distance:$input.point // Distance in meters
367
+ $db.location|within:$input.point:1000 // Within radius
368
368
  ```
369
369
 
370
370
  ### Vector (AI/ML)
@@ -385,7 +385,7 @@ $db.content|search_rank:$input.query
385
385
  Connect to external databases:
386
386
 
387
387
  ```xs
388
- # PostgreSQL
388
+ // PostgreSQL
389
389
  db.external.postgres.direct_query {
390
390
  connection_string = $env.EXTERNAL_PG_URL
391
391
  sql = "SELECT * FROM users WHERE id = ?"
@@ -393,13 +393,13 @@ db.external.postgres.direct_query {
393
393
  response_type = "single"
394
394
  } as $user
395
395
 
396
- # MySQL
396
+ // MySQL
397
397
  db.external.mysql.direct_query { ... }
398
398
 
399
- # MS SQL
399
+ // MS SQL
400
400
  db.external.mssql.direct_query { ... }
401
401
 
402
- # Oracle
402
+ // Oracle
403
403
  db.external.oracle.direct_query { ... }
404
404
  ```
405
405
 
@@ -116,8 +116,8 @@ One-time operation with setup and cleanup hooks.
116
116
  ```xs
117
117
  function "$main" {
118
118
  input {
119
- json args # Runtime arguments
120
- json pre # Result from $pre
119
+ json args // Runtime arguments
120
+ json pre // Result from $pre
121
121
  }
122
122
  stack {
123
123
  db.query authors {
@@ -11,10 +11,10 @@ Static frontend development and Lovable/Supabase migration.
11
11
  ### Directory Structure
12
12
  ```
13
13
  static/
14
- ├── index.html # Main entry point
14
+ ├── index.html // Main entry point
15
15
  ├── css/
16
16
  ├── js/
17
- │ └── api.js # Centralized API calls
17
+ │ └── api.js // Centralized API calls
18
18
  └── assets/
19
19
  ```
20
20
 
@@ -15,7 +15,7 @@ function "<name>" {
15
15
  <type> <name> [filters=...] { description = "..." }
16
16
  }
17
17
  stack {
18
- # Logic here
18
+ // Logic here
19
19
  }
20
20
  response = $result
21
21
  }
@@ -110,21 +110,21 @@ stack {
110
110
  ### Loops
111
111
  ```xs
112
112
  stack {
113
- # For loop (count-based)
113
+ // For loop (count-based)
114
114
  for (10) {
115
115
  each as $i {
116
116
  debug.log { value = $i }
117
117
  }
118
118
  }
119
119
 
120
- # Foreach (array iteration)
120
+ // Foreach (array iteration)
121
121
  foreach ($input.items) {
122
122
  each as $item {
123
123
  debug.log { value = $item.name }
124
124
  }
125
125
  }
126
126
 
127
- # While loop
127
+ // While loop
128
128
  while ($counter < 5) {
129
129
  each {
130
130
  math.add $counter { value = 1 }
@@ -161,10 +161,10 @@ For complete error handling reference (preconditions, try-catch, throw, early re
161
161
  Specify what the function returns:
162
162
 
163
163
  ```xs
164
- response = $total # Single variable
165
- response = { success: true, data: $result } # Object literal
166
- response = $items|first # With filter
167
- response = null # No return value
164
+ response = $total // Single variable
165
+ response = { success: true, data: $result } // Object literal
166
+ response = $items|first // With filter
167
+ response = null // No return value
168
168
  ```
169
169
 
170
170
  ---
@@ -182,20 +182,20 @@ cloud.elasticsearch.document {
182
182
 
183
183
  ### Key-Value Operations
184
184
  ```xs
185
- # Set value
185
+ // Set value
186
186
  redis.set {
187
187
  key = "user:123:session"
188
188
  data = $session_data
189
- ttl = 3600 # Expires in 1 hour
189
+ ttl = 3600 // Expires in 1 hour
190
190
  }
191
191
 
192
- # Get value
192
+ // Get value
193
193
  redis.get { key = "user:123:session" } as $session
194
194
 
195
- # Check exists
195
+ // Check exists
196
196
  redis.has { key = "user:123:session" } as $exists
197
197
 
198
- # Delete
198
+ // Delete
199
199
  redis.del { key = "user:123:session" }
200
200
  ```
201
201
 
@@ -147,18 +147,18 @@ mcp_server "CRM" {
147
147
  ### By Domain
148
148
  ```
149
149
  mcp_servers/
150
- ├── support.xs # Customer support tools
151
- ├── ecommerce.xs # Store management
152
- ├── analytics.xs # Reporting and metrics
153
- └── admin.xs # Administrative functions
150
+ ├── support.xs // Customer support tools
151
+ ├── ecommerce.xs // Store management
152
+ ├── analytics.xs // Reporting and metrics
153
+ └── admin.xs // Administrative functions
154
154
  ```
155
155
 
156
156
  ### By Access Level
157
157
  ```
158
158
  mcp_servers/
159
- ├── public.xs # Public-facing tools
160
- ├── authenticated.xs # Requires auth
161
- └── admin.xs # Admin-only tools
159
+ ├── public.xs // Public-facing tools
160
+ ├── authenticated.xs // Requires auth
161
+ └── admin.xs // Admin-only tools
162
162
  ```
163
163
 
164
164
  ---