@xano/developer-mcp 1.0.48 → 1.0.50

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.
@@ -178,7 +178,7 @@ export const XANOSCRIPT_DOCS_V2 = {
178
178
  },
179
179
  workspace: {
180
180
  file: "workspace.md",
181
- applyTo: ["workspace.xs"],
181
+ applyTo: ["workspace/**/*.xs"],
182
182
  description: "Workspace-level settings: environment variables, preferences, realtime",
183
183
  },
184
184
  };
@@ -325,6 +325,19 @@ input {
325
325
  }
326
326
  ```
327
327
 
328
+ ### Required Fields Also Reject Empty Strings
329
+
330
+ > **Important for testing:** A required `text` field (no `?` after the name) rejects both `null` **and** empty strings (`""`). Sending `""` triggers a platform-level validation error **before your stack runs** — your preconditions and custom error handling never execute.
331
+
332
+ | Value sent | `text name` | `text? name` | `text name?` | `text? name?` |
333
+ |------------|-------------|--------------|--------------|---------------|
334
+ | `"Alice"` | ✅ valid | ✅ valid | ✅ valid | ✅ valid |
335
+ | `""` | ❌ validation error | ❌ validation error | ✅ valid (empty) | ✅ valid (empty) |
336
+ | `null` | ❌ validation error | ✅ valid | ❌ validation error | ✅ valid |
337
+ | *(omitted)* | ❌ validation error | ❌ validation error | ✅ valid | ✅ valid |
338
+
339
+ To test the "empty input" scenario for a text field, the field must be declared optional (`text name?`). Testing a required field with `""` will always produce a validation error — never your custom logic.
340
+
328
341
  ---
329
342
 
330
343
  ## Foreign Key References
@@ -311,6 +311,65 @@ function "validate_age" {
311
311
 
312
312
  ---
313
313
 
314
+ ## Common Mistakes
315
+
316
+ ### Testing Required Fields with Empty Strings
317
+
318
+ A required input field (no `?` after the name) rejects both `null` and empty strings at the platform level — **before your stack runs**. Writing a test that sends `""` to a required field will always get a validation error, never your custom precondition or error logic.
319
+
320
+ ❌ **Wrong — will always throw a validation error, not your custom error:**
321
+ ```xs
322
+ function "create_user" {
323
+ input { text name } // required: rejects null AND ""
324
+ stack {
325
+ precondition ($input.name != "") {
326
+ error_type = "inputerror"
327
+ error = "Name cannot be blank"
328
+ }
329
+ }
330
+ response = { ok: true }
331
+
332
+ // This test gets a validation error from the input layer, not "Name cannot be blank"
333
+ test "rejects empty name" {
334
+ input = { name: "" }
335
+ expect.to_throw { value = "Name cannot be blank" }
336
+ }
337
+ }
338
+ ```
339
+
340
+ ✅ **Correct — use an optional field if you need to test the empty/omitted case:**
341
+ ```xs
342
+ function "create_user" {
343
+ input { text name? } // optional: accepts "", null, or omission
344
+ stack {
345
+ precondition ($input.name != null && $input.name != "") {
346
+ error_type = "inputerror"
347
+ error = "Name cannot be blank"
348
+ }
349
+ }
350
+ response = { ok: true }
351
+
352
+ test "rejects empty name" {
353
+ input = { name: "" }
354
+ expect.to_throw { value = "Name cannot be blank" }
355
+ }
356
+
357
+ test "rejects null name" {
358
+ input = { name: null }
359
+ expect.to_throw { value = "Name cannot be blank" }
360
+ }
361
+
362
+ test "accepts valid name" {
363
+ input = { name: "Alice" }
364
+ expect.to_equal ($response.ok) { value = true }
365
+ }
366
+ }
367
+ ```
368
+
369
+ For a full breakdown of what each required/optional/nullable combination accepts, see `xanoscript_docs({ topic: "types" })`.
370
+
371
+ ---
372
+
314
373
  ## Complete Example
315
374
 
316
375
  ```xs
@@ -323,6 +323,7 @@ workflow_test "comprehensive_test" {
323
323
  4. **Keep tests independent** — Each workflow test should be self-contained and not depend on other tests
324
324
  5. **Use `function.call`, not `function.run`** — `function.call` handles errors so that `expect` assertions work correctly. `function.run` is for calling functions outside of workflow tests
325
325
  6. **Use assertions over preconditions** — Prefer `expect.*` assertions for clearer test intent
326
+ 7. **Don't test required fields with empty strings** — Required inputs reject both `null` and `""` at the platform level before your stack runs. If you send `""` to a required `text` field, you'll always get a platform validation error — never your custom logic. To test the empty/blank case, the input must be declared optional (`text name?`). See `xanoscript_docs({ topic: "types" })` for the full breakdown.
326
327
 
327
328
  ---
328
329
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- applyTo: "workspace.xs"
2
+ applyTo: "workspace/**/*.xs"
3
3
  ---
4
4
 
5
5
  # Workspace Configuration
@@ -21,6 +21,7 @@ workspace "<name>" {
21
21
  ### Attributes
22
22
  | Attribute | Type | Required | Description |
23
23
  |-----------|------|----------|-------------|
24
+ | `name` | text | **Yes** | Workspace name (matches the filename, e.g. `workspace/my_project.xs` → `"my_project"`) |
24
25
  | `description` | text | No | Human-readable workspace description |
25
26
  | `env` | object | No | Environment variable definitions |
26
27
  | `acceptance` | object | No | Terms and acceptance settings |
@@ -171,7 +172,7 @@ workspace "ecommerce_platform" {
171
172
 
172
173
  ## File Location
173
174
 
174
- Workspace configuration is stored in `workspace.xs` at the root of your project.
175
+ Workspace configuration is stored as `workspace/<name>.xs`, where `<name>` matches the name declared in the `workspace` block.
175
176
 
176
177
  ```
177
178
  project/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/developer-mcp",
3
- "version": "1.0.48",
3
+ "version": "1.0.50",
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",