@xano/developer-mcp 1.0.52 → 1.0.53

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.
@@ -26,6 +26,12 @@ export declare function handleCliDocs(args: CliDocsArgs): string;
26
26
  */
27
27
  export declare const cliDocsToolDefinition: {
28
28
  name: string;
29
+ annotations: {
30
+ readOnlyHint: boolean;
31
+ destructiveHint: boolean;
32
+ idempotentHint: boolean;
33
+ openWorldHint: boolean;
34
+ };
29
35
  description: string;
30
36
  inputSchema: {
31
37
  type: string;
@@ -59,6 +59,12 @@ export function handleCliDocs(args) {
59
59
  */
60
60
  export const cliDocsToolDefinition = {
61
61
  name: "cli_docs",
62
+ annotations: {
63
+ readOnlyHint: true,
64
+ destructiveHint: false,
65
+ idempotentHint: true,
66
+ openWorldHint: false,
67
+ },
62
68
  description: `Get documentation for the Xano CLI. Use this to understand how to use the CLI for local development, code sync, and XanoScript execution.
63
69
 
64
70
  ## Topics
@@ -26,6 +26,12 @@ export declare function handleMetaApiDocs(args: MetaApiDocsArgs): string;
26
26
  */
27
27
  export declare const metaApiDocsToolDefinition: {
28
28
  name: string;
29
+ annotations: {
30
+ readOnlyHint: boolean;
31
+ destructiveHint: boolean;
32
+ idempotentHint: boolean;
33
+ openWorldHint: boolean;
34
+ };
29
35
  description: string;
30
36
  inputSchema: {
31
37
  type: string;
@@ -77,6 +77,12 @@ export function handleMetaApiDocs(args) {
77
77
  */
78
78
  export const metaApiDocsToolDefinition = {
79
79
  name: "meta_api_docs",
80
+ annotations: {
81
+ readOnlyHint: true,
82
+ destructiveHint: false,
83
+ idempotentHint: true,
84
+ openWorldHint: false,
85
+ },
80
86
  description: `Get documentation for Xano's Meta API. Use this to understand how to programmatically manage Xano workspaces, databases, APIs, functions, agents, and more.
81
87
 
82
88
  ## Topics
@@ -42,6 +42,12 @@ export { validateXanoscriptToolDefinition, xanoscriptDocsToolDefinition, mcpVers
42
42
  */
43
43
  export declare const toolDefinitions: ({
44
44
  name: string;
45
+ annotations: {
46
+ readOnlyHint: boolean;
47
+ destructiveHint: boolean;
48
+ idempotentHint: boolean;
49
+ openWorldHint: boolean;
50
+ };
45
51
  description: string;
46
52
  inputSchema: {
47
53
  type: string;
@@ -50,6 +56,12 @@ export declare const toolDefinitions: ({
50
56
  };
51
57
  } | {
52
58
  name: string;
59
+ annotations: {
60
+ readOnlyHint: boolean;
61
+ destructiveHint: boolean;
62
+ idempotentHint: boolean;
63
+ openWorldHint: boolean;
64
+ };
53
65
  description: string;
54
66
  inputSchema: {
55
67
  type: string;
@@ -36,6 +36,12 @@ export declare function mcpVersion(): McpVersionResult;
36
36
  export declare function mcpVersionTool(): ToolResult;
37
37
  export declare const mcpVersionToolDefinition: {
38
38
  name: string;
39
+ annotations: {
40
+ readOnlyHint: boolean;
41
+ destructiveHint: boolean;
42
+ idempotentHint: boolean;
43
+ openWorldHint: boolean;
44
+ };
39
45
  description: string;
40
46
  inputSchema: {
41
47
  type: string;
@@ -84,6 +84,12 @@ export function mcpVersionTool() {
84
84
  // =============================================================================
85
85
  export const mcpVersionToolDefinition = {
86
86
  name: "mcp_version",
87
+ annotations: {
88
+ readOnlyHint: true,
89
+ destructiveHint: false,
90
+ idempotentHint: true,
91
+ openWorldHint: false,
92
+ },
87
93
  description: "Get the current version of the Xano Developer MCP server. " +
88
94
  "Returns the version string from package.json.",
89
95
  inputSchema: {
@@ -109,6 +109,12 @@ export declare function validateXanoscript(args: ValidateXanoscriptArgs): Valida
109
109
  export declare function validateXanoscriptTool(args: ValidateXanoscriptArgs): ToolResult;
110
110
  export declare const validateXanoscriptToolDefinition: {
111
111
  name: string;
112
+ annotations: {
113
+ readOnlyHint: boolean;
114
+ destructiveHint: boolean;
115
+ idempotentHint: boolean;
116
+ openWorldHint: boolean;
117
+ };
112
118
  description: string;
113
119
  inputSchema: {
114
120
  type: string;
@@ -388,6 +388,12 @@ export function validateXanoscriptTool(args) {
388
388
  // =============================================================================
389
389
  export const validateXanoscriptToolDefinition = {
390
390
  name: "validate_xanoscript",
391
+ annotations: {
392
+ readOnlyHint: true,
393
+ destructiveHint: false,
394
+ idempotentHint: true,
395
+ openWorldHint: false,
396
+ },
391
397
  description: "Validate XanoScript code for syntax errors. Supports multiple input methods:\n" +
392
398
  "- code: Raw XanoScript code as a string\n" +
393
399
  "- file_path: Path to a single .xs file (easier than escaping code!)\n" +
@@ -50,11 +50,18 @@ export declare function xanoscriptDocsTool(args?: XanoscriptDocsArgs): ToolResul
50
50
  export declare const xanoscriptDocsToolDefinition: {
51
51
  name: string;
52
52
  description: string;
53
+ annotations: {
54
+ readOnlyHint: boolean;
55
+ destructiveHint: boolean;
56
+ idempotentHint: boolean;
57
+ openWorldHint: boolean;
58
+ };
53
59
  inputSchema: {
54
60
  type: string;
55
61
  properties: {
56
62
  topic: {
57
63
  type: string;
64
+ enum: string[];
58
65
  description: string;
59
66
  };
60
67
  file_path: {
@@ -7,7 +7,7 @@
7
7
  import { readFileSync } from "fs";
8
8
  import { dirname, join } from "path";
9
9
  import { fileURLToPath } from "url";
10
- import { readXanoscriptDocsV2, getTopicDescriptions, } from "../xanoscript.js";
10
+ import { readXanoscriptDocsV2, getTopicNames, getTopicDescriptions, } from "../xanoscript.js";
11
11
  // =============================================================================
12
12
  // Path Resolution
13
13
  // =============================================================================
@@ -105,11 +105,18 @@ export const xanoscriptDocsToolDefinition = {
105
105
  "Call without parameters for overview (README). " +
106
106
  "Use 'topic' for specific documentation, or 'file_path' for context-aware docs based on the file you're editing. " +
107
107
  "Use mode='quick_reference' for compact syntax cheatsheet (recommended for context efficiency).",
108
+ annotations: {
109
+ readOnlyHint: true,
110
+ destructiveHint: false,
111
+ idempotentHint: true,
112
+ openWorldHint: false,
113
+ },
108
114
  inputSchema: {
109
115
  type: "object",
110
116
  properties: {
111
117
  topic: {
112
118
  type: "string",
119
+ enum: getTopicNames(),
113
120
  description: "Documentation topic to retrieve. Call without any parameters to get the README overview. " +
114
121
  "Example: topic='syntax' for language syntax, topic='database' for database operations, topic='types' for type system.\n\n" +
115
122
  "Available topics:\n" + getTopicDescriptions(),
@@ -243,47 +243,38 @@ export function getXanoscriptDocsVersion(docsPath) {
243
243
  export function readXanoscriptDocsV2(docsPath, args) {
244
244
  const mode = args?.mode || "full";
245
245
  const version = getXanoscriptDocsVersion(docsPath);
246
- try {
247
- // Default: return README
248
- if (!args?.topic && !args?.file_path) {
249
- const readme = readFileSync(join(docsPath, "README.md"), "utf-8");
250
- return `${readme}\n\n---\nDocumentation version: ${version}`;
251
- }
252
- // Context-aware: return docs matching file pattern
253
- if (args?.file_path) {
254
- const topics = getDocsForFilePath(args.file_path);
255
- if (topics.length === 0) {
256
- return `No documentation found for file pattern: ${args.file_path}\n\nAvailable topics: ${Object.keys(XANOSCRIPT_DOCS_V2).join(", ")}`;
257
- }
258
- const docs = topics.map((t) => {
259
- const config = XANOSCRIPT_DOCS_V2[t];
260
- const content = readFileSync(join(docsPath, config.file), "utf-8");
261
- return mode === "quick_reference"
262
- ? extractQuickReference(content, t)
263
- : content;
264
- });
265
- const header = `# XanoScript Documentation for: ${args.file_path}\n\nMatched topics: ${topics.join(", ")}\nMode: ${mode}\nVersion: ${version}\n\n---\n\n`;
266
- return header + docs.join("\n\n---\n\n");
246
+ // Default: return README
247
+ if (!args?.topic && !args?.file_path) {
248
+ const readme = readFileSync(join(docsPath, "README.md"), "utf-8");
249
+ return `${readme}\n\n---\nDocumentation version: ${version}`;
250
+ }
251
+ // Context-aware: return docs matching file pattern
252
+ if (args?.file_path) {
253
+ const topics = getDocsForFilePath(args.file_path);
254
+ if (topics.length === 0) {
255
+ throw new Error(`No documentation found for file pattern: ${args.file_path}\n\nAvailable topics: ${Object.keys(XANOSCRIPT_DOCS_V2).join(", ")}`);
267
256
  }
268
- // Topic-based: return specific doc
269
- if (args?.topic) {
270
- const config = XANOSCRIPT_DOCS_V2[args.topic];
271
- if (!config) {
272
- const availableTopics = Object.keys(XANOSCRIPT_DOCS_V2).join(", ");
273
- return `Error: Unknown topic "${args.topic}".\n\nAvailable topics: ${availableTopics}`;
274
- }
257
+ const docs = topics.map((t) => {
258
+ const config = XANOSCRIPT_DOCS_V2[t];
275
259
  const content = readFileSync(join(docsPath, config.file), "utf-8");
276
- const doc = mode === "quick_reference"
277
- ? extractQuickReference(content, args.topic)
260
+ return mode === "quick_reference"
261
+ ? extractQuickReference(content, t)
278
262
  : content;
279
- return `${doc}\n\n---\nDocumentation version: ${version}`;
280
- }
281
- return "Error: Invalid parameters";
263
+ });
264
+ const header = `# XanoScript Documentation for: ${args.file_path}\n\nMatched topics: ${topics.join(", ")}\nMode: ${mode}\nVersion: ${version}\n\n---\n\n`;
265
+ return header + docs.join("\n\n---\n\n");
282
266
  }
283
- catch (error) {
284
- const errorMessage = error instanceof Error ? error.message : String(error);
285
- return `Error reading XanoScript documentation: ${errorMessage}`;
267
+ // Topic-based: return specific doc
268
+ const config = XANOSCRIPT_DOCS_V2[args.topic];
269
+ if (!config) {
270
+ const availableTopics = Object.keys(XANOSCRIPT_DOCS_V2).join(", ");
271
+ throw new Error(`Unknown topic "${args.topic}".\n\nAvailable topics: ${availableTopics}`);
286
272
  }
273
+ const content = readFileSync(join(docsPath, config.file), "utf-8");
274
+ const doc = mode === "quick_reference"
275
+ ? extractQuickReference(content, args.topic)
276
+ : content;
277
+ return `${doc}\n\n---\nDocumentation version: ${version}`;
287
278
  }
288
279
  /**
289
280
  * Get available topic names
@@ -126,7 +126,7 @@ describe("xanoscript module", () => {
126
126
  expect(result).toContain("branch");
127
127
  });
128
128
  it("should match workspace.xs", () => {
129
- const result = getDocsForFilePath("workspace.xs");
129
+ const result = getDocsForFilePath("workspace/workspace.xs");
130
130
  expect(result).toContain("syntax");
131
131
  expect(result).toContain("workspace");
132
132
  });
@@ -236,10 +236,8 @@ Even more content.
236
236
  const result = readXanoscriptDocsV2(DOCS_PATH, { topic: "syntax" });
237
237
  expect(result).toContain("Documentation version:");
238
238
  });
239
- it("should return error for unknown topic", () => {
240
- const result = readXanoscriptDocsV2(DOCS_PATH, { topic: "nonexistent" });
241
- expect(result).toContain('Error: Unknown topic "nonexistent"');
242
- expect(result).toContain("Available topics:");
239
+ it("should throw for unknown topic", () => {
240
+ expect(() => readXanoscriptDocsV2(DOCS_PATH, { topic: "nonexistent" })).toThrow('Unknown topic "nonexistent"');
243
241
  });
244
242
  it("should return context-aware docs for file_path", () => {
245
243
  const result = readXanoscriptDocsV2(DOCS_PATH, {
@@ -272,11 +270,8 @@ Even more content.
272
270
  });
273
271
  expect(quickResult).toContain("Mode: quick_reference");
274
272
  });
275
- it("should return error for invalid docs path", () => {
276
- const result = readXanoscriptDocsV2("/nonexistent/path", {
277
- topic: "syntax",
278
- });
279
- expect(result).toContain("Error reading XanoScript documentation:");
273
+ it("should throw for invalid docs path", () => {
274
+ expect(() => readXanoscriptDocsV2("/nonexistent/path", { topic: "syntax" })).toThrow();
280
275
  });
281
276
  });
282
277
  describe("getTopicNames", () => {
@@ -6,7 +6,9 @@ applyTo: "**/*.xs"
6
6
 
7
7
  > **Purpose:** Quick reference for the 20 most common XanoScript patterns. For detailed documentation, use `xanoscript_docs({ topic: "<topic>" })`.
8
8
 
9
- ## Variable Declaration
9
+ ## Quick Reference
10
+
11
+ ### Variable Declaration
10
12
 
11
13
  ```xs
12
14
  var $name { value = "initial" }
@@ -15,7 +17,7 @@ var $items { value = [] }
15
17
  var $data { value = { key: "value" } }
16
18
  ```
17
19
 
18
- ## Conditionals
20
+ ### Conditionals
19
21
 
20
22
  ```xs
21
23
  conditional {
@@ -33,7 +35,7 @@ conditional {
33
35
 
34
36
  > **Note:** Use `elseif` (one word), not `else if`.
35
37
 
36
- ## Switch
38
+ ### Switch
37
39
 
38
40
  ```xs
39
41
  switch ($input.status) {
@@ -51,7 +53,7 @@ switch ($input.status) {
51
53
 
52
54
  > **Note:** `break` goes **after** the closing `}` of each `case` block. The `default` case does not need `break`.
53
55
 
54
- ## Loops
56
+ ### Loops
55
57
 
56
58
  ```xs
57
59
  // For each loop
@@ -81,7 +83,7 @@ var $names { value = $items|map:$$.name }
81
83
  var $active { value = $items|filter:$$.is_active }
82
84
  ```
83
85
 
84
- ## Database CRUD
86
+ ### Database CRUD
85
87
 
86
88
  ```xs
87
89
  // Get single record by field
@@ -113,7 +115,7 @@ db.edit "user" {
113
115
  db.del "user" { field_name = "id", field_value = $input.user_id }
114
116
  ```
115
117
 
116
- ## API Requests
118
+ ### API Requests
117
119
 
118
120
  ```xs
119
121
  api.request {
@@ -133,7 +135,7 @@ api.request {
133
135
  // $api_result.response.headers → Response headers
134
136
  ```
135
137
 
136
- ## Error Handling
138
+ ### Error Handling
137
139
 
138
140
  ```xs
139
141
  // Precondition (stops execution if false)
@@ -159,7 +161,7 @@ throw {
159
161
  }
160
162
  ```
161
163
 
162
- ## Error Types
164
+ ### Error Types
163
165
 
164
166
  | Type | HTTP Status | Use Case |
165
167
  |------|-------------|----------|
@@ -168,7 +170,7 @@ throw {
168
170
  | `notfound` | 404 | Resource doesn't exist |
169
171
  | `standard` | 500 | General errors |
170
172
 
171
- ## Common Filters
173
+ ### Common Filters
172
174
 
173
175
  ```xs
174
176
  // String
@@ -210,7 +212,7 @@ $num|round:2 // Round to 2 decimals
210
212
  $num|abs // Absolute value
211
213
  ```
212
214
 
213
- ## Authentication Check
215
+ ### Authentication Check
214
216
 
215
217
  ```xs
216
218
  precondition ($auth.id != null) {
@@ -219,7 +221,7 @@ precondition ($auth.id != null) {
219
221
  }
220
222
  ```
221
223
 
222
- ## Function Call
224
+ ### Function Call
223
225
 
224
226
  ```xs
225
227
  function.run "my_function" {
@@ -227,7 +229,7 @@ function.run "my_function" {
227
229
  } as $result
228
230
  ```
229
231
 
230
- ## String Concatenation
232
+ ### String Concatenation
231
233
 
232
234
  ```xs
233
235
  // Basic
@@ -237,7 +239,7 @@ var $msg { value = "Hello, " ~ $input.name ~ "!" }
237
239
  var $msg { value = ($status|to_text) ~ ": " ~ ($data|json_encode) }
238
240
  ```
239
241
 
240
- ## Common Type Names
242
+ ### Common Type Names
241
243
 
242
244
  | Use This | Not This |
243
245
  |----------|----------|
@@ -247,11 +249,11 @@ var $msg { value = ($status|to_text) ~ ": " ~ ($data|json_encode) }
247
249
  | `decimal` | float, number |
248
250
  | `type[]` | array, list |
249
251
 
250
- ## Reserved Variables (Cannot Use)
252
+ ### Reserved Variables (Cannot Use)
251
253
 
252
254
  `$response`, `$output`, `$input`, `$auth`, `$env`, `$db`, `$this`, `$result`, `$index`
253
255
 
254
- ## Input Block Syntax
256
+ ### Input Block Syntax
255
257
 
256
258
  `?` after the **type** = nullable, `?` after the **variable name** = optional (not required).
257
259
 
@@ -113,7 +113,7 @@ debug.stop
113
113
  function "process_order" {
114
114
  input { int order_id }
115
115
  stack {
116
- var $trace_id { value = |uuid }
116
+ security.create_uuid as $trace_id
117
117
 
118
118
  debug.log {
119
119
  label = "TRACE_START"
@@ -298,7 +298,7 @@ precondition ($input.email|contains:"@") {
298
298
  | `db.query` | Filtered list | `db.query "users" { where = $db.users.active == true } as $users` |
299
299
  | `db.add` | Insert | `db.add "users" { data = { name: "John" } } as $new` |
300
300
  | `db.edit` | Update | `db.edit "users" { field_name = "id" field_value = 1 data = { name: "Jane" } }` |
301
- | `db.delete` | Delete | `db.delete "users" { field_name = "id" field_value = 1 }` |
301
+ | `db.del` | Delete | `db.del "users" { field_name = "id" field_value = 1 }` |
302
302
 
303
303
  > **Full reference:** See `xanoscript_docs({ topic: "database" })` for joins, bulk operations, transactions, and more.
304
304
 
@@ -323,9 +323,11 @@ var $data {
323
323
  ### 4. Loop Through Array
324
324
 
325
325
  ```xs
326
- // Using each
327
- each ($items as $item) {
328
- debug.log { value = $item.name }
326
+ // Using foreach
327
+ foreach ($items) {
328
+ each as $item {
329
+ debug.log { value = $item.name }
330
+ }
329
331
  }
330
332
 
331
333
  // Using map filter
@@ -96,7 +96,7 @@ function "refresh_auth" {
96
96
  } as $new_token
97
97
 
98
98
  // Rotate refresh token
99
- var $new_refresh { value = |uuid }
99
+ security.create_uuid as $new_refresh
100
100
 
101
101
  db.edit "refresh_token" {
102
102
  field_name = "id"
@@ -120,7 +120,7 @@ function "refresh_auth" {
120
120
  function "create_session" {
121
121
  input { int user_id }
122
122
  stack {
123
- var $session_id { value = |uuid }
123
+ security.create_uuid as $session_id
124
124
 
125
125
  db.add "session" {
126
126
  data = {
@@ -107,34 +107,34 @@ function "add" {
107
107
  ### Value Assertions
108
108
 
109
109
  ```xs
110
- # Equality
110
+ // Equality
111
111
  expect.to_equal ($response.status) { value = "active" }
112
112
  expect.to_not_equal ($response.status) { value = "deleted" }
113
113
 
114
- # Boolean
114
+ // Boolean
115
115
  expect.to_be_true ($response.is_active)
116
116
  expect.to_be_false ($response.is_deleted)
117
117
 
118
- # Null
118
+ // Null
119
119
  expect.to_be_null ($response.deleted_at)
120
120
  expect.to_not_be_null ($response.created_at)
121
121
 
122
- # Defined
122
+ // Defined
123
123
  expect.to_be_defined ($response.id)
124
124
  expect.to_not_be_defined ($response.optional_field)
125
125
 
126
- # Empty
126
+ // Empty
127
127
  expect.to_be_empty ($response.errors)
128
128
  ```
129
129
 
130
130
  ### Comparison Assertions
131
131
 
132
132
  ```xs
133
- # Numeric comparisons
133
+ // Numeric comparisons
134
134
  expect.to_be_greater_than ($response.total) { value = 100 }
135
135
  expect.to_be_less_than ($response.stock) { value = 10 }
136
136
 
137
- # Range
137
+ // Range
138
138
  expect.to_be_within ($response.temperature) {
139
139
  min = 20
140
140
  max = 30
@@ -144,14 +144,14 @@ expect.to_be_within ($response.temperature) {
144
144
  ### String Assertions
145
145
 
146
146
  ```xs
147
- # Starts/ends with
147
+ // Starts/ends with
148
148
  expect.to_start_with ($response.name) { value = "John" }
149
149
  expect.to_end_with ($response.file) { value = ".pdf" }
150
150
 
151
- # Contains
151
+ // Contains
152
152
  expect.to_contain ($response.tags) { value = "featured" }
153
153
 
154
- # Regex match
154
+ // Regex match
155
155
  expect.to_match ($response.phone) { value = "^\\+1\\d{10}$" }
156
156
  ```
157
157
 
@@ -165,13 +165,13 @@ expect.to_be_in_the_future ($response.expires_at)
165
165
  ### Error Assertions
166
166
 
167
167
  ```xs
168
- # Expects any error
168
+ // Expects any error
169
169
  test "throws on invalid input" {
170
170
  input = { amount: -1 }
171
171
  expect.to_throw
172
172
  }
173
173
 
174
- # Expects specific error
174
+ // Expects specific error
175
175
  test "throws validation error" {
176
176
  input = { amount: -1 }
177
177
  expect.to_throw { value = "InvalidInputError" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/developer-mcp",
3
- "version": "1.0.52",
3
+ "version": "1.0.53",
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",