@xano/developer-mcp 1.0.32 → 1.0.34

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
@@ -198,7 +198,7 @@ console.log(overview.documentation);
198
198
  const syntaxDocs = xanoscriptDocs({ topic: 'syntax' });
199
199
 
200
200
  // Get context-aware docs for a file path
201
- const apiDocs = xanoscriptDocs({ file_path: 'apis/users/create.xs' });
201
+ const apiDocs = xanoscriptDocs({ file_path: 'api/users/create_post.xs' });
202
202
 
203
203
  // Get compact quick reference
204
204
  const quickRef = xanoscriptDocs({ topic: 'database', mode: 'quick_reference' });
@@ -326,7 +326,7 @@ Retrieves XanoScript programming language documentation with context-aware suppo
326
326
  | Parameter | Type | Required | Description |
327
327
  |-----------|------|----------|-------------|
328
328
  | `topic` | string | No | Specific documentation topic to retrieve |
329
- | `file_path` | string | No | File path being edited for context-aware docs (e.g., `apis/users/create.xs`) |
329
+ | `file_path` | string | No | File path being edited for context-aware docs (e.g., `api/users/create_post.xs`) |
330
330
  | `mode` | string | No | `full` (default) or `quick_reference` for compact syntax cheatsheet |
331
331
 
332
332
  **Available Topics:**
@@ -366,7 +366,7 @@ xanoscript_docs()
366
366
  xanoscript_docs({ topic: "functions" })
367
367
 
368
368
  // Context-aware: get all docs relevant to file being edited
369
- xanoscript_docs({ file_path: "apis/users/create.xs" })
369
+ xanoscript_docs({ file_path: "api/users/create_post.xs" })
370
370
 
371
371
  // Compact quick reference (uses less context)
372
372
  xanoscript_docs({ topic: "database", mode: "quick_reference" })
@@ -667,7 +667,7 @@ Compiles TypeScript to JavaScript in the `dist/` directory.
667
667
  - Markdown files for XanoScript language reference
668
668
  - Configured in `src/index.ts` via `XANOSCRIPT_DOCS_V2` with:
669
669
  - **file**: The markdown file containing the documentation
670
- - **applyTo**: Glob patterns for context-aware matching (e.g., `apis/**/*.xs`)
670
+ - **applyTo**: Glob patterns for context-aware matching (e.g., `api/**/*.xs`)
671
671
  - **description**: Human-readable description of the topic
672
672
 
673
673
  **Meta API Documentation** (`src/meta_api_docs/`):
@@ -17,16 +17,59 @@ function: refresh_token
17
17
  ...
18
18
  \`\`\`
19
19
 
20
- When you pull, the CLI splits these into individual \`.xs\` files organized by type.`,
20
+ When you pull, the CLI splits these into individual \`.xs\` files organized by type.
21
+
22
+ ## Directory Structure
23
+
24
+ After \`workspace:pull\`, files are organized using snake_case naming:
25
+
26
+ \`\`\`
27
+ ./xano-code/
28
+ ├── workspace/
29
+ │ ├── my_workspace.xs # Workspace configuration
30
+ │ └── trigger/
31
+ │ └── on_deploy.xs # Workspace triggers
32
+ ├── api/
33
+ │ └── users/ # API group folder (snake_case)
34
+ │ ├── api_group.xs # API group definition
35
+ │ ├── get_all.xs # GET /users
36
+ │ ├── get_one_get.xs # GET /users/:id
37
+ │ ├── create_post.xs # POST /users
38
+ │ └── nested/
39
+ │ └── profile_get.xs # GET /users/nested/profile
40
+ ├── function/
41
+ │ └── validate_token.xs # Reusable functions
42
+ ├── task/
43
+ │ └── daily_cleanup.xs # Scheduled tasks
44
+ ├── table/
45
+ │ ├── users.xs # Table schema
46
+ │ └── trigger/
47
+ │ └── on_user_create.xs # Table triggers
48
+ ├── agent/
49
+ │ ├── support_bot.xs # AI agents
50
+ │ └── trigger/
51
+ │ └── on_message.xs # Agent triggers
52
+ └── mcp_server/
53
+ ├── my_server.xs # MCP server definitions
54
+ └── trigger/
55
+ └── on_connect.xs # MCP server triggers
56
+ \`\`\``,
21
57
  ai_hints: `**Key concepts:**
22
58
  - \`pull\` downloads workspace code and splits into organized .xs files
23
59
  - \`push\` combines .xs files and uploads to Xano
24
- - Files are organized by type: functions/, apis/, tasks/, etc.
60
+ - Files use snake_case naming for folders and filenames
61
+ - API endpoints are nested under their API group folder
25
62
 
26
63
  **Typical workflow:**
27
64
  1. \`xano workspace:pull ./xano-code\` - download
28
- 2. Edit .xs files with your editor/IDE
29
- 3. \`xano workspace:push ./xano-code\` - deploy
65
+ 2. Navigate to \`api/{group}/\` for API endpoints, \`function/\` for functions, etc.
66
+ 3. Edit .xs files with your editor/IDE
67
+ 4. \`xano workspace:push ./xano-code\` - deploy
68
+
69
+ **File naming:**
70
+ - All folders and files use snake_case (e.g., \`my_function.xs\`, \`user_profile/\`)
71
+ - API endpoints include verb suffix (e.g., \`create_post.xs\`, \`get_one_get.xs\`)
72
+ - Triggers are nested under \`{type}/trigger/\` folders
30
73
 
31
74
  **Version control:**
32
75
  - The pulled directory structure is git-friendly
@@ -159,13 +202,14 @@ When you pull, the CLI splits these into individual \`.xs\` files organized by t
159
202
  description: "Edit Xano code locally with your preferred tools",
160
203
  steps: [
161
204
  "Pull workspace: `xano workspace:pull ./code`",
162
- "Edit .xs files in your IDE",
205
+ "Navigate to organized folders: `api/{group}/`, `function/`, `table/`, etc.",
206
+ "Edit .xs files in your IDE (files use snake_case naming)",
163
207
  "Validate changes: Use xanoscript_docs MCP tool",
164
208
  "Push changes: `xano workspace:push ./code`",
165
209
  "Test in Xano dashboard or via API"
166
210
  ],
167
211
  example: `xano workspace:pull ./my-app
168
- # Edit files...
212
+ # Files organized: api/users/create_post.xs, function/validate_token.xs, etc.
169
213
  xano workspace:push ./my-app`
170
214
  },
171
215
  {
@@ -21,6 +21,11 @@ export const XANOSCRIPT_DOCS_V2 = {
21
21
  applyTo: ["**/*.xs"],
22
22
  description: "Expressions, operators, and filters for all XanoScript code",
23
23
  },
24
+ quickstart: {
25
+ file: "quickstart.md",
26
+ applyTo: ["**/*.xs"],
27
+ description: "Common patterns, quick reference, and common mistakes to avoid",
28
+ },
24
29
  types: {
25
30
  file: "types.md",
26
31
  applyTo: ["functions/**/*.xs", "apis/**/*.xs", "tools/**/*.xs", "agents/**/*.xs"],
@@ -11,6 +11,7 @@ describe("xanoscript module", () => {
11
11
  const expectedTopics = [
12
12
  "readme",
13
13
  "syntax",
14
+ "quickstart",
14
15
  "types",
15
16
  "tables",
16
17
  "functions",
@@ -135,9 +136,10 @@ describe("xanoscript module", () => {
135
136
  const result = getDocsForFilePath("apis/test.xs");
136
137
  expect(result).not.toContain("readme");
137
138
  });
138
- it("should put syntax first if not already matched", () => {
139
+ it("should include syntax and quickstart for .xs files", () => {
139
140
  const result = getDocsForFilePath("some/random/file.xs");
140
- expect(result[0]).toBe("syntax");
141
+ expect(result).toContain("syntax");
142
+ expect(result).toContain("quickstart");
141
143
  });
142
144
  });
143
145
  describe("extractQuickReference", () => {
@@ -4,45 +4,81 @@ XanoScript is the declarative scripting language for [Xano](https://xano.com), a
4
4
 
5
5
  ## Quick Reference
6
6
 
7
- | Construct | File Location | Purpose |
8
- | ------------------ | --------------------- | ----------------------------- |
9
- | `table` | `tables/*.xs` | Database schema definition |
10
- | `function` | `functions/**/*.xs` | Reusable logic blocks |
11
- | `query` | `apis/<group>/*.xs` | HTTP API endpoints |
12
- | `task` | `tasks/*.xs` | Scheduled/cron jobs |
13
- | `*_trigger` | `triggers/**/*.xs` | Event-driven handlers |
14
- | `agent` | `agents/**/*.xs` | AI-powered agents |
15
- | `tool` | `tools/**/*.xs` | Tools for AI agents |
16
- | `mcp_server` | `mcp_servers/**/*.xs` | MCP server definitions |
17
- | `addon` | `addons/*.xs` | Subqueries for related data |
18
- | `middleware` | `middleware/**/*.xs` | Request/response interceptors |
19
- | `branch` | `branch.xs` | Branch-level configuration |
20
- | `workspace` | `workspace.xs` | Workspace-level configuration |
21
- | `realtime_channel` | Configuration | Realtime channel settings |
7
+ | Construct | File Location | Purpose |
8
+ | ------------------- | ------------------------------------ | ----------------------------- |
9
+ | `workspace` | `workspace/{name}.xs` | Workspace-level configuration |
10
+ | `workspace_trigger` | `workspace/trigger/{name}.xs` | Workspace event handlers |
11
+ | `table` | `table/{name}.xs` | Database schema definition |
12
+ | `table_trigger` | `table/trigger/{name}.xs` | Table event handlers |
13
+ | `api_group` | `api/{group}/api_group.xs` | API group definition |
14
+ | `query` | `api/{group}/{endpoint}_{verb}.xs` | HTTP API endpoints |
15
+ | `function` | `function/{name}.xs` | Reusable logic blocks |
16
+ | `task` | `task/{name}.xs` | Scheduled/cron jobs |
17
+ | `agent` | `agent/{name}.xs` | AI-powered agents |
18
+ | `agent_trigger` | `agent/trigger/{name}.xs` | Agent event handlers |
19
+ | `tool` | `tool/{name}.xs` | Tools for AI agents |
20
+ | `mcp_server` | `mcp_server/{name}.xs` | MCP server definitions |
21
+ | `mcp_server_trigger`| `mcp_server/trigger/{name}.xs` | MCP server event handlers |
22
+ | `addon` | `addon/{name}.xs` | Subqueries for related data |
23
+ | `middleware` | `middleware/{name}.xs` | Request/response interceptors |
24
+ | `branch` | `branch.xs` | Branch-level configuration |
25
+ | `realtime_channel` | Configuration | Realtime channel settings |
26
+
27
+ **Naming convention:** All folder and file names use `snake_case` (e.g., `user_profile.xs`, `get_all_users_get.xs`).
22
28
 
23
29
  **Important:** Each `.xs` file must contain exactly one definition. You cannot define multiple tables, functions, queries, or other constructs in a single file.
24
30
 
25
31
  ## Workspace Structure
26
32
 
33
+ After pulling from Xano, files are organized using `snake_case` naming:
34
+
27
35
  ```
28
36
  project/
29
- ├── workspace.xs // Workspace configuration (env vars, preferences)
30
- ├── branch.xs // Branch configuration (middleware, history)
31
- ├── tables/ // Database table schemas
32
- ├── functions/ // Reusable functions (supports subfolders)
33
- ├── apis/
34
- │ └── <api-group>/ // API endpoints grouped by domain
35
- ├── tasks/ // Scheduled jobs
36
- ├── triggers/ // Event-driven handlers
37
- ├── agents/ // AI agents
38
- ├── tools/ // AI tools
39
- ├── mcp_servers/ // MCP server definitions
40
- ├── middleware/ // Request/response interceptors
41
- ├── addons/ // Query addons
42
- ├── static/ // Frontend files (HTML, CSS, JS)
43
- └── run/ // Job and service configurations
37
+ ├── branch.xs # Branch configuration
38
+ ├── workspace/
39
+ ├── my_workspace.xs # Workspace configuration
40
+ │ └── trigger/
41
+ │ └── on_deploy.xs # Workspace triggers
42
+ ├── api/
43
+ │ └── users/ # API group folder
44
+ ├── api_group.xs # API group definition
45
+ ├── get_all_get.xs # GET /users
46
+ ├── get_one_get.xs # GET /users/:id
47
+ ├── create_post.xs # POST /users
48
+ │ └── nested/
49
+ │ └── profile_get.xs # Nested endpoint: GET /users/nested/profile
50
+ ├── function/
51
+ └── validate_token.xs # Reusable functions
52
+ ├── task/
53
+ │ └── daily_cleanup.xs # Scheduled jobs
54
+ ├── table/
55
+ │ ├── users.xs # Table schema
56
+ │ └── trigger/
57
+ │ └── on_user_create.xs # Table triggers
58
+ ├── agent/
59
+ │ ├── support_bot.xs # AI agents
60
+ │ └── trigger/
61
+ │ └── on_message.xs # Agent triggers
62
+ ├── tool/
63
+ │ └── search_docs.xs # AI tools
64
+ ├── mcp_server/
65
+ │ ├── my_server.xs # MCP server definitions
66
+ │ └── trigger/
67
+ │ └── on_connect.xs # MCP server triggers
68
+ ├── middleware/
69
+ │ └── auth_check.xs # Request/response interceptors
70
+ ├── addon/
71
+ │ └── user_posts.xs # Query addons
72
+ ├── static/ # Frontend files (HTML, CSS, JS)
73
+ └── run/ # Job and service configurations
44
74
  ```
45
75
 
76
+ **Key conventions:**
77
+ - All folders and files use `snake_case` naming
78
+ - API endpoints include the HTTP verb suffix (e.g., `create_post.xs`, `get_one_get.xs`)
79
+ - Triggers are nested under `{type}/trigger/` folders
80
+ - Nested API paths become nested folders (e.g., `/users/nested/profile` → `api/users/nested/profile_get.xs`)
81
+
46
82
  ## Environment Variables
47
83
 
48
84
  Access with `$env.<name>`. Common built-in variables include `$env.$remote_ip`, `$env.$http_headers`, `$env.$request_method`, `$env.$datasource`, and `$env.$branch`. Custom environment variables are set in the Xano dashboard and accessed as `$env.MY_VAR`.
@@ -100,24 +136,41 @@ Documentation files use frontmatter to specify which file patterns they apply to
100
136
 
101
137
  ```markdown
102
138
  ---
103
- applyTo: "functions/**/*.xs"
139
+ applyTo: "function/**/*.xs"
104
140
  ---
105
141
  ```
106
142
 
107
143
  This helps AI tools apply the correct documentation based on the file being edited.
108
144
 
145
+ ## Getting Started
146
+
147
+ For common patterns and quick examples, use:
148
+ ```
149
+ xanoscript_docs({ topic: "quickstart" })
150
+ ```
151
+
152
+ This includes:
153
+ - Variable declaration patterns
154
+ - Conditional logic (if/elseif/else)
155
+ - API requests with error handling
156
+ - Database CRUD operations
157
+ - Common mistakes to avoid
158
+
159
+ ---
160
+
109
161
  ## Documentation Index
110
162
 
111
163
  Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
112
164
 
113
165
  ### Core Language
114
166
 
115
- | Topic | Description |
116
- | ----------- | ------------------------------------------------- |
117
- | `syntax` | Expressions, operators, filters, system variables |
118
- | `types` | Data types, validation, input blocks |
119
- | `functions` | Reusable function stacks, async, loops |
120
- | `schema` | Runtime schema parsing and validation |
167
+ | Topic | Description |
168
+ | ------------ | ---------------------------------------------------- |
169
+ | `quickstart` | Common patterns, quick examples, mistakes to avoid |
170
+ | `syntax` | Expressions, operators, filters, system variables |
171
+ | `types` | Data types, validation, input blocks |
172
+ | `functions` | Reusable function stacks, async, loops |
173
+ | `schema` | Runtime schema parsing and validation |
121
174
 
122
175
  ### Data
123
176
 
@@ -174,3 +227,47 @@ Use `xanoscript_docs({ topic: "<topic>" })` to retrieve documentation.
174
227
  | ------------- | ------------------------------------------------------------ |
175
228
  | `performance` | Performance optimization best practices |
176
229
  | `security` | Security best practices for authentication and authorization |
230
+
231
+ ---
232
+
233
+ ## Example Implementations
234
+
235
+ Common integration patterns you can reference:
236
+
237
+ ### External API Integrations
238
+ - **OpenAI/ChatGPT**: Use `api.request` with POST to `/v1/chat/completions`
239
+ - **Stripe**: Use `api.request` with form-encoded params for payments
240
+ - **SendGrid/Resend**: Use `api.request` or `util.send_email` for emails
241
+ - **Slack/Discord**: Use `api.request` with webhook URLs
242
+ - **Twilio**: Use `api.request` with Basic auth for SMS
243
+
244
+ ### Common Pattern: API Integration Function
245
+
246
+ ```xs
247
+ function "call_external_api" {
248
+ input {
249
+ text endpoint
250
+ object payload
251
+ }
252
+ stack {
253
+ api.request {
254
+ url = $env.API_BASE_URL ~ $input.endpoint
255
+ method = "POST"
256
+ params = $input.payload
257
+ headers = [
258
+ "Content-Type: application/json",
259
+ "Authorization: Bearer " ~ $env.API_KEY
260
+ ]
261
+ timeout = 30
262
+ } as $api_result
263
+
264
+ precondition ($api_result.response.status >= 200 && $api_result.response.status < 300) {
265
+ error_type = "standard"
266
+ error = "API error: " ~ ($api_result.response.status|to_text)
267
+ }
268
+ }
269
+ response = $api_result.response.result
270
+ }
271
+ ```
272
+
273
+ For more patterns, see `xanoscript_docs({ topic: "quickstart" })` or `xanoscript_docs({ topic: "integrations" })`.
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "addons/*.xs, functions/**/*.xs, apis/**/*.xs"
2
+ applyTo: "addon/**/*.xs, function/**/*.xs, api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Addons
@@ -231,7 +231,7 @@ db.query product {
231
231
  ### File Structure
232
232
 
233
233
  ```
234
- addons/
234
+ addon/
235
235
  ├── comment_count.xs
236
236
  ├── like_count.xs
237
237
  ├── author_details.xs
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "agents/**/*.xs"
2
+ applyTo: "agent/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Agents
@@ -186,7 +186,7 @@ agent "Classifier" {
186
186
 
187
187
  ## Tools
188
188
 
189
- Reference tools by name from `tools/` directory:
189
+ Reference tools by name from `tool/` directory:
190
190
 
191
191
  ```xs
192
192
  tools = [
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "apis/**/*.xs"
2
+ applyTo: "api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # APIs
@@ -77,16 +77,18 @@ api_group Authentication {
77
77
  ### File Structure
78
78
 
79
79
  ```
80
- apis/
80
+ api/
81
81
  ├── users/
82
- │ ├── api_group.xs // Defines group (canonical = "myapp-users")
83
- │ ├── list.xs // GET /myapp-users/list
84
- │ └── by-id.xs // GET/PATCH/DELETE /myapp-users/{id}
82
+ │ ├── api_group.xs # Defines group (canonical = "myapp-users")
83
+ │ ├── list_get.xs # GET /myapp-users/list
84
+ │ └── by_id_get.xs # GET /myapp-users/{id}
85
85
  └── products/
86
- ├── api_group.xs // Defines group (canonical = "myapp-products")
87
- └── search.xs // GET /myapp-products/search
86
+ ├── api_group.xs # Defines group (canonical = "myapp-products")
87
+ └── search_get.xs # GET /myapp-products/search
88
88
  ```
89
89
 
90
+ **Naming convention:** Endpoint files use `{name}_{verb}.xs` format (e.g., `list_get.xs`, `create_post.xs`).
91
+
90
92
  Full URL: `/<canonical>/<query name>` (e.g., `/myapp-users/profile`)
91
93
 
92
94
  ---
@@ -222,10 +222,11 @@ Branch configuration files are typically named `branch.xs` and placed at the wor
222
222
 
223
223
  ```
224
224
  project/
225
- ├── branch.xs // Branch configuration
226
- ├── tables/
227
- ├── functions/
228
- └── apis/
225
+ ├── branch.xs # Branch configuration
226
+ ├── workspace/
227
+ ├── table/
228
+ ├── function/
229
+ └── api/
229
230
  ```
230
231
 
231
232
  ---
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs, tasks/*.xs, tools/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs, task/**/*.xs, tool/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Database Operations
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs"
2
+ applyTo: "function/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Functions
@@ -62,7 +62,7 @@ function "calculate_total" {
62
62
  Functions can be organized in subfolders:
63
63
 
64
64
  ```
65
- functions/
65
+ function/
66
66
  ├── math/
67
67
  │ ├── add.xs
68
68
  │ └── multiply.xs
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs, tasks/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs, task/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Integrations
@@ -575,22 +575,92 @@ util.send_email {
575
575
 
576
576
  ---
577
577
 
578
- ## External APIs
578
+ ## External APIs (api.request)
579
579
 
580
580
  Make HTTP requests to external APIs.
581
581
 
582
+ ### Quick Reference
583
+
582
584
  ```xs
583
585
  api.request {
584
- url = "https://api.example.com/data"
585
- method = "POST"
586
- params = { key: "value" }
586
+ url = "https://api.example.com/endpoint"
587
+ method = "POST" // GET, POST, PUT, PATCH, DELETE
588
+ params = $payload // Request body for POST/PUT/PATCH
587
589
  headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
588
- timeout = 30
590
+ timeout = 30 // Timeout in seconds
589
591
  } as $api_result
592
+
593
+ // Access response
594
+ $api_result.response.status // HTTP status code (200, 404, etc.)
595
+ $api_result.response.result // Response body (auto-parsed JSON)
596
+ $api_result.response.headers // Response headers array
590
597
  ```
591
598
 
599
+ > **Important:** The `params` parameter is used for the **request body** (POST/PUT/PATCH), not query parameters. This naming is counterintuitive but consistent across XanoScript.
600
+
592
601
  > **Note:** The `headers` parameter expects an array of text strings, where each string contains the header name and value separated by a colon (e.g., `["Content-Type: application/json", "X-Custom-Header: value"]`).
593
602
 
603
+ ### GET Request
604
+
605
+ ```xs
606
+ api.request {
607
+ url = "https://api.example.com/users?page=1&limit=10"
608
+ method = "GET"
609
+ headers = ["Authorization: Bearer " ~ $env.API_KEY]
610
+ } as $api_result
611
+
612
+ var $users { value = $api_result.response.result }
613
+ ```
614
+
615
+ ### POST Request with JSON Body
616
+
617
+ ```xs
618
+ var $payload {
619
+ value = {
620
+ name: $input.name,
621
+ email: $input.email
622
+ }
623
+ }
624
+
625
+ api.request {
626
+ url = "https://api.example.com/users"
627
+ method = "POST"
628
+ params = $payload
629
+ headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
630
+ } as $api_result
631
+
632
+ // Check for success
633
+ precondition ($api_result.response.status == 201) {
634
+ error_type = "standard"
635
+ error = "Failed to create user: " ~ ($api_result.response.result|json_encode)
636
+ }
637
+ ```
638
+
639
+ ### Error Handling Pattern
640
+
641
+ ```xs
642
+ api.request {
643
+ url = "https://api.example.com/data"
644
+ method = "GET"
645
+ timeout = 30
646
+ } as $api_result
647
+
648
+ conditional {
649
+ if ($api_result.response.status >= 200 && $api_result.response.status < 300) {
650
+ var $data { value = $api_result.response.result }
651
+ }
652
+ elseif ($api_result.response.status == 404) {
653
+ throw { name = "NotFound", value = "Resource not found" }
654
+ }
655
+ else {
656
+ throw {
657
+ name = "APIError",
658
+ value = "API returned status " ~ ($api_result.response.status|to_text)
659
+ }
660
+ }
661
+ }
662
+ ```
663
+
594
664
  ### Response Structure
595
665
 
596
666
  The `api.request` statement returns an object with both request and response details:
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "mcp_servers/**/*.xs"
2
+ applyTo: "mcp_server/**/*.xs"
3
3
  ---
4
4
 
5
5
  # MCP Servers
@@ -52,7 +52,7 @@ mcp_server "Customer Support" {
52
52
 
53
53
  ## Tools Block
54
54
 
55
- Reference tools from `tools/` directory by name:
55
+ Reference tools from `tool/` directory by name:
56
56
 
57
57
  ```xs
58
58
  tools = [
@@ -62,7 +62,7 @@ tools = [
62
62
  ]
63
63
  ```
64
64
 
65
- Tool names must exactly match `.xs` file names in `tools/`.
65
+ Tool names must exactly match `.xs` file names in `tool/`.
66
66
 
67
67
  ---
68
68
 
@@ -146,19 +146,19 @@ mcp_server "CRM" {
146
146
 
147
147
  ### By Domain
148
148
  ```
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
149
+ mcp_server/
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
- mcp_servers/
159
- ├── public.xs // Public-facing tools
160
- ├── authenticated.xs // Requires auth
161
- └── admin.xs // Admin-only tools
158
+ mcp_server/
159
+ ├── public.xs # Public-facing tools
160
+ ├── authenticated.xs # Requires auth
161
+ └── admin.xs # Admin-only tools
162
162
  ```
163
163
 
164
164
  ---
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Performance Optimization
@@ -0,0 +1,340 @@
1
+ ---
2
+ applyTo: "**/*.xs"
3
+ ---
4
+
5
+ # Quickstart & Common Patterns
6
+
7
+ Essential patterns for XanoScript development. Use this as a quick reference for frequently-used code patterns.
8
+
9
+ ## Quick Reference
10
+
11
+ ### Variable Declaration
12
+ ```xs
13
+ var $name { value = "initial value" }
14
+ var $count { value = 0 }
15
+ var $data { value = { key: "value" } }
16
+ ```
17
+
18
+ ### Conditional Logic
19
+ ```xs
20
+ conditional {
21
+ if (`$status == "active"`) {
22
+ var $result { value = "Active user" }
23
+ }
24
+ elseif (`$status == "pending"`) {
25
+ var $result { value = "Pending approval" }
26
+ }
27
+ else {
28
+ var $result { value = "Unknown status" }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ### API Request with Error Handling
34
+ ```xs
35
+ api.request {
36
+ url = "https://api.example.com/data"
37
+ method = "POST"
38
+ params = $payload
39
+ headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
40
+ } as $api_result
41
+
42
+ precondition ($api_result.response.status == 200) {
43
+ error_type = "standard"
44
+ error = "API request failed"
45
+ }
46
+
47
+ var $data { value = $api_result.response.result }
48
+ ```
49
+
50
+ ### String Concatenation
51
+ ```xs
52
+ var $greeting { value = "Hello, " ~ $input.name ~ "!" }
53
+
54
+ // With filters (use parentheses)
55
+ var $message { value = "Status: " ~ ($status|to_text) ~ " - " ~ ($data|json_encode) }
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Common Patterns
61
+
62
+ ### 1. Input Validation
63
+
64
+ ```xs
65
+ // Required field check
66
+ precondition ($input.email != null && $input.email != "") {
67
+ error_type = "inputerror"
68
+ error = "Email is required"
69
+ }
70
+
71
+ // Format validation
72
+ precondition ($input.email|contains:"@") {
73
+ error_type = "inputerror"
74
+ error = "Invalid email format"
75
+ }
76
+ ```
77
+
78
+ ### 2. Database CRUD
79
+
80
+ ```xs
81
+ // Create
82
+ db.add "user" {
83
+ data = { name: $input.name, email: $input.email }
84
+ } as $new_user
85
+
86
+ // Read one
87
+ db.get "user" {
88
+ where = $db.user.id == $input.id
89
+ } as $user
90
+
91
+ // Read many
92
+ db.query "user" {
93
+ where = $db.user.is_active == true
94
+ order = [{ field: created_at, direction: desc }]
95
+ paging = { limit: 10, offset: 0 }
96
+ } as $users
97
+
98
+ // Update
99
+ db.edit "user" {
100
+ where = $db.user.id == $input.id
101
+ data = { name: $input.name }
102
+ }
103
+
104
+ // Delete
105
+ db.delete "user" {
106
+ where = $db.user.id == $input.id
107
+ }
108
+ ```
109
+
110
+ ### 3. Optional Field Handling
111
+
112
+ ```xs
113
+ // Build object with optional fields
114
+ var $data { value = { required_field: $input.required } }
115
+
116
+ conditional {
117
+ if ($input.optional_field != null) {
118
+ var.update $data { value = $data|set:"optional_field":$input.optional_field }
119
+ }
120
+ }
121
+
122
+ // Or use set_ifnotnull
123
+ var $data {
124
+ value = { required: $input.required }|set_ifnotnull:"optional":$input.optional
125
+ }
126
+ ```
127
+
128
+ ### 4. Loop Through Array
129
+
130
+ ```xs
131
+ // Using each
132
+ each ($items as $item) {
133
+ debug.log { value = $item.name }
134
+ }
135
+
136
+ // Using map filter
137
+ var $names { value = $items|map:$$.name }
138
+
139
+ // Using filter
140
+ var $active_items { value = $items|filter:$$.is_active == true }
141
+ ```
142
+
143
+ ### 5. Error Handling with Try-Catch
144
+
145
+ ```xs
146
+ try_catch {
147
+ try {
148
+ api.request {
149
+ url = "https://api.example.com/risky"
150
+ method = "GET"
151
+ } as $result
152
+ }
153
+ catch {
154
+ debug.log { value = "Request failed, using fallback" }
155
+ var $result { value = { response: { result: null } } }
156
+ }
157
+ }
158
+ ```
159
+
160
+ ### 6. Authentication Check
161
+
162
+ ```xs
163
+ // Require authenticated user
164
+ precondition ($auth.id != null) {
165
+ error_type = "accessdenied"
166
+ error = "Authentication required"
167
+ }
168
+
169
+ // Check user owns resource
170
+ db.get "post" {
171
+ where = $db.post.id == $input.post_id
172
+ } as $post
173
+
174
+ precondition ($post.user_id == $auth.id) {
175
+ error_type = "accessdenied"
176
+ error = "You can only edit your own posts"
177
+ }
178
+ ```
179
+
180
+ ### 7. Pagination
181
+
182
+ ```xs
183
+ var $page { value = $input.page ?? 1 }
184
+ var $limit { value = $input.limit ?? 20 }
185
+ var $offset { value = ($page - 1) * $limit }
186
+
187
+ db.query "item" {
188
+ where = $db.item.is_active == true
189
+ order = [{ field: created_at, direction: desc }]
190
+ paging = { limit: $limit, offset: $offset }
191
+ count = true
192
+ } as $result
193
+
194
+ response = {
195
+ items: $result.items,
196
+ total: $result.count,
197
+ page: $page,
198
+ pages: ($result.count / $limit)|ceil
199
+ }
200
+ ```
201
+
202
+ ### 8. Building Complex Objects
203
+
204
+ ```xs
205
+ // Step by step
206
+ var $response { value = {} }
207
+ var.update $response { value = $response|set:"user":$user }
208
+ var.update $response { value = $response|set:"posts":$posts }
209
+ var.update $response { value = $response|set:"stats":{ count: $posts|count } }
210
+
211
+ // Or all at once
212
+ var $response {
213
+ value = {
214
+ user: $user,
215
+ posts: $posts,
216
+ stats: { count: $posts|count }
217
+ }
218
+ }
219
+ ```
220
+
221
+ ### 9. Date/Time Operations
222
+
223
+ ```xs
224
+ // Current timestamp
225
+ var $now { value = now }
226
+
227
+ // Format for display
228
+ var $formatted { value = now|format_timestamp:"Y-m-d H:i:s":"UTC" }
229
+
230
+ // Relative time
231
+ var $yesterday { value = now|transform_timestamp:"-1 day" }
232
+ var $next_week { value = now|transform_timestamp:"+7 days" }
233
+
234
+ // Compare dates
235
+ db.query "event" {
236
+ where = $db.event.start_date >= now
237
+ } as $upcoming_events
238
+ ```
239
+
240
+ ### 10. JSON API Response
241
+
242
+ ```xs
243
+ api.request {
244
+ url = "https://api.openai.com/v1/chat/completions"
245
+ method = "POST"
246
+ params = {
247
+ model: "gpt-4",
248
+ messages: [{ role: "user", content: $input.prompt }]
249
+ }
250
+ headers = [
251
+ "Content-Type: application/json",
252
+ "Authorization: Bearer " ~ $env.OPENAI_API_KEY
253
+ ]
254
+ } as $api_result
255
+
256
+ conditional {
257
+ if ($api_result.response.status == 200) {
258
+ var $answer { value = $api_result.response.result.choices|first|get:"message"|get:"content" }
259
+ }
260
+ else {
261
+ throw {
262
+ name = "APIError",
263
+ value = "OpenAI API error: " ~ ($api_result.response.status|to_text)
264
+ }
265
+ }
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## Common Mistakes
272
+
273
+ ### 1. Using `else if` instead of `elseif`
274
+ ```xs
275
+ // ❌ Wrong
276
+ conditional {
277
+ if (...) { }
278
+ else if (...) { } // Parse error!
279
+ }
280
+
281
+ // ✅ Correct
282
+ conditional {
283
+ if (...) { }
284
+ elseif (...) { }
285
+ }
286
+ ```
287
+
288
+ ### 2. Missing parentheses in filter concatenation
289
+ ```xs
290
+ // ❌ Wrong
291
+ var $msg { value = $status|to_text ~ " - " ~ $data|json_encode }
292
+
293
+ // ✅ Correct
294
+ var $msg { value = ($status|to_text) ~ " - " ~ ($data|json_encode) }
295
+ ```
296
+
297
+ ### 3. Using `body` instead of `params` for api.request
298
+ ```xs
299
+ // ❌ Wrong
300
+ api.request {
301
+ url = "..."
302
+ method = "POST"
303
+ body = $payload // "body" is not valid!
304
+ }
305
+
306
+ // ✅ Correct
307
+ api.request {
308
+ url = "..."
309
+ method = "POST"
310
+ params = $payload // Use "params" for request body
311
+ }
312
+ ```
313
+
314
+ ### 4. Using `default` filter (doesn't exist)
315
+ ```xs
316
+ // ❌ Wrong
317
+ var $value { value = $input.optional|default:"fallback" }
318
+
319
+ // ✅ Correct
320
+ var $value { value = $input.optional|first_notnull:"fallback" }
321
+ // or
322
+ var $value { value = $input.optional ?? "fallback" }
323
+ ```
324
+
325
+ ### 5. Using $env in run.job input blocks
326
+ ```xs
327
+ // ❌ Wrong - $env not allowed in input blocks
328
+ run.job "my_job" {
329
+ input {
330
+ text api_key = $env.API_KEY
331
+ }
332
+ }
333
+
334
+ // ✅ Correct - use $env in the stack
335
+ run.job "my_job" {
336
+ stack {
337
+ var $api_key { value = $env.API_KEY }
338
+ }
339
+ }
340
+ ```
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs, triggers/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs, */trigger/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Realtime
@@ -16,9 +16,9 @@ Define job and service configurations for the Xano Job Runner.
16
16
  ### Directory Structure
17
17
  ```
18
18
  run.xs
19
- tables/
20
- functions/
21
- apis/
19
+ table/
20
+ function/
21
+ api/
22
22
  ```
23
23
 
24
24
  ---
@@ -216,9 +216,9 @@ function "process_data" {
216
216
 
217
217
  ```
218
218
  run.xs
219
- tables/
219
+ table/
220
220
  └── users.xs
221
- functions/
221
+ function/
222
222
  └── migrate_users.xs
223
223
  ```
224
224
 
@@ -235,7 +235,7 @@ run.job "Data Migration" {
235
235
  }
236
236
  ```
237
237
 
238
- ### tables/users.xs
238
+ ### table/users.xs
239
239
  ```xs
240
240
  table users {
241
241
  auth = false
@@ -255,7 +255,7 @@ table users {
255
255
  }
256
256
  ```
257
257
 
258
- ### functions/migrate_users.xs
258
+ ### function/migrate_users.xs
259
259
  ```xs
260
260
  function "migrate_users" {
261
261
  input {
@@ -287,12 +287,13 @@ function "migrate_users" {
287
287
 
288
288
  ```
289
289
  run.xs
290
- tables/
290
+ table/
291
291
  └── event.xs
292
- apis/
293
- ├── api_group.xs
294
- ├── list.xs
295
- └── add.xs
292
+ api/
293
+ └── events/
294
+ ├── api_group.xs
295
+ ├── list_get.xs
296
+ └── add_post.xs
296
297
  ```
297
298
 
298
299
  ### run.xs
@@ -306,7 +307,7 @@ run.service "Event Tracker" {
306
307
  }
307
308
  ```
308
309
 
309
- ### tables/event.xs
310
+ ### table/event.xs
310
311
  ```xs
311
312
  table event {
312
313
  auth = false
@@ -322,7 +323,7 @@ table event {
322
323
  }
323
324
  ```
324
325
 
325
- ### apis/list.xs
326
+ ### api/events/list_get.xs
326
327
  ```xs
327
328
  query list verb=GET {
328
329
  api_group = "events"
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Schema Operations
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Security
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Streaming Operations
@@ -21,12 +21,67 @@ Complete reference for XanoScript expressions, operators, and filters.
21
21
  | Filter | Purpose | Example |
22
22
  |--------|---------|---------|
23
23
  | `trim` | Remove whitespace | `$s\|trim` |
24
- | `lower` / `upper` | Case conversion | `$s\|to_lower` |
24
+ | `to_lower` / `to_upper` | Case conversion | `$s\|to_lower` |
25
25
  | `first` / `last` | Array endpoints | `$arr\|first` |
26
26
  | `count` | Array/object length | `$arr\|count` |
27
27
  | `get` | Object property | `$obj\|get:"key"` |
28
28
  | `set` | Set property | `$obj\|set:"key":"val"` |
29
29
  | `json_encode` / `json_decode` | JSON conversion | `$obj\|json_encode` |
30
+ | `to_text` / `to_int` | Type conversion | `$num\|to_text` |
31
+
32
+ > **Note:** There is no `default` filter. Use conditional blocks or `first_notnull`/`first_notempty` instead.
33
+
34
+ ### String Concatenation with Filters
35
+
36
+ When concatenating strings that use filters, wrap each filtered expression in parentheses:
37
+
38
+ ```xs
39
+ // ✅ Correct - parentheses around filtered expressions
40
+ var $message {
41
+ value = ($status|to_text) ~ ": " ~ ($data|json_encode)
42
+ }
43
+
44
+ // ❌ Incorrect - missing parentheses causes parse error
45
+ var $message {
46
+ value = $status|to_text ~ ": " ~ $data|json_encode
47
+ }
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Conditional Blocks
53
+
54
+ Use `conditional` blocks for if/elseif/else logic:
55
+
56
+ ```xs
57
+ conditional {
58
+ if (`$status == "success"`) {
59
+ var $message { value = "All good!" }
60
+ }
61
+ elseif (`$status == "pending"`) {
62
+ var $message { value = "Please wait..." }
63
+ }
64
+ else {
65
+ var $message { value = "Unknown status" }
66
+ }
67
+ }
68
+ ```
69
+
70
+ > **Important:** Use `elseif` (one word), not `else if` or `else { if (...) }`. Nested `if` inside `else` blocks is not supported.
71
+
72
+ ### Conditional as Expression
73
+
74
+ Use conditional blocks inline to return values:
75
+
76
+ ```xs
77
+ var $tier_limit {
78
+ value = conditional {
79
+ if ($auth.tier == "premium") { 1000 }
80
+ elseif ($auth.tier == "pro") { 500 }
81
+ else { 100 }
82
+ }
83
+ }
84
+ ```
30
85
 
31
86
  ---
32
87
 
@@ -431,6 +486,32 @@ var $client_ip { value = $env.$remote_ip }
431
486
  var $method { value = $env.$request_method }
432
487
  var $headers { value = $env.$http_headers }
433
488
  var $current_branch { value = $env.$branch }
489
+
490
+ // Custom environment variables (set in Xano dashboard)
491
+ var $api_key { value = $env.MY_API_KEY }
492
+ ```
493
+
494
+ ### $env Limitations
495
+
496
+ > **Important:** `$env` variables cannot be used in `run.job` or `run.service` input blocks. Input values must be constants.
497
+
498
+ ```xs
499
+ // ❌ Invalid - $env not allowed in run.job input
500
+ run.job "my_job" {
501
+ input {
502
+ text api_key = $env.API_KEY // Error!
503
+ }
504
+ }
505
+
506
+ // ✅ Valid - access $env inside the stack instead
507
+ run.job "my_job" {
508
+ input {
509
+ text api_key // No default value
510
+ }
511
+ stack {
512
+ var $key { value = $env.API_KEY }
513
+ }
514
+ }
434
515
  ```
435
516
 
436
517
  ---
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "tables/*.xs"
2
+ applyTo: "table/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Tables
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "tasks/*.xs"
2
+ applyTo: "task/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Tasks
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Testing
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "tools/**/*.xs"
2
+ applyTo: "tool/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Tools
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "triggers/**/*.xs"
2
+ applyTo: "*/trigger/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Triggers
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "functions/**/*.xs, apis/**/*.xs, tools/**/*.xs, agents/**/*.xs"
2
+ applyTo: "function/**/*.xs, api/**/*.xs, tool/**/*.xs, agent/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Types & Inputs
@@ -175,11 +175,12 @@ Workspace configuration is stored in `workspace.xs` at the root of your project.
175
175
 
176
176
  ```
177
177
  project/
178
- ├── workspace.xs // Workspace configuration
179
- ├── branch.xs // Branch configuration
180
- ├── tables/
181
- ├── functions/
182
- └── apis/
178
+ ├── branch.xs # Branch configuration
179
+ ├── workspace/
180
+ │ └── my_workspace.xs # Workspace configuration
181
+ ├── table/
182
+ ├── function/
183
+ └── api/
183
184
  ```
184
185
 
185
186
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/developer-mcp",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "MCP server and library for Xano development - XanoScript validation, Meta API, Run API, and CLI documentation",
5
5
  "type": "module",
6
6
  "main": "dist/lib.js",