@kirrosh/zond 0.9.0 → 0.9.2
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/package.json
CHANGED
|
@@ -59,301 +59,91 @@ export function compressEndpointsWithSchemas(
|
|
|
59
59
|
return lines.join("\n");
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
baseUrl?: string;
|
|
65
|
-
apiContext: string;
|
|
66
|
-
outputDir: string;
|
|
67
|
-
securitySchemes: SecuritySchemeInfo[];
|
|
68
|
-
endpointCount: number;
|
|
69
|
-
coverageHeader?: string;
|
|
70
|
-
compact?: boolean;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function buildGenerationGuide(opts: GuideOptions): string {
|
|
74
|
-
const hasAuth = opts.securitySchemes.length > 0;
|
|
75
|
-
|
|
76
|
-
if (opts.compact) {
|
|
77
|
-
const securitySummary = hasAuth
|
|
78
|
-
? `Security: ${opts.securitySchemes.map(s => `${s.name} (${s.type}${s.scheme ? `/${s.scheme}` : ""})`).join(", ")}`
|
|
79
|
-
: "Security: none";
|
|
80
|
-
|
|
81
|
-
return `# Test Generation Guide for ${opts.title}
|
|
82
|
-
${opts.coverageHeader ? `\n${opts.coverageHeader}\n` : ""}
|
|
83
|
-
## API Specification (${opts.endpointCount} endpoints)
|
|
84
|
-
${opts.baseUrl ? `Base URL: ${opts.baseUrl}` : "Base URL: use {{base_url}} environment variable"}
|
|
85
|
-
${securitySummary}
|
|
86
|
-
|
|
87
|
-
${opts.apiContext}
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
> **Note:** Refer to the full YAML format reference, generation algorithm, tag conventions, and practical tips from the initial \`generate_and_save\` call (without \`tag\`). Only the API endpoints above are unique to this chunk.`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return `# Test Generation Guide for ${opts.title}
|
|
95
|
-
${opts.coverageHeader ? `\n${opts.coverageHeader}\n` : ""}
|
|
96
|
-
## API Specification (${opts.endpointCount} endpoints)
|
|
97
|
-
${opts.baseUrl ? `Base URL: ${opts.baseUrl}` : "Base URL: use {{base_url}} environment variable"}
|
|
98
|
-
|
|
99
|
-
${opts.apiContext}
|
|
100
|
-
|
|
101
|
-
${hasAuth ? `---
|
|
102
|
-
|
|
103
|
-
## Environment Setup (Required for Authentication)
|
|
104
|
-
|
|
105
|
-
This API uses authentication. Before running tests, set up your credentials:
|
|
106
|
-
|
|
107
|
-
### Edit the env file
|
|
108
|
-
After \`setup_api\`, the collection directory contains \`.env.yaml\`. Edit it to add your credentials:
|
|
109
|
-
\`\`\`yaml
|
|
110
|
-
base_url: "https://api.example.com"
|
|
111
|
-
api_key: "your-actual-api-key-here"
|
|
112
|
-
auth_token: "your-token-here"
|
|
113
|
-
\`\`\`
|
|
114
|
-
|
|
115
|
-
### How it works
|
|
116
|
-
- Tests **automatically** load the \`"default"\` environment — no need to pass \`envName\` to \`run_tests\`
|
|
117
|
-
- If the env file is in the collection root and tests are in a \`tests/\` subdirectory, the file is still found automatically
|
|
118
|
-
- Use \`{{api_key}}\`, \`{{auth_token}}\`, \`{{base_url}}\` etc. in test headers/bodies
|
|
119
|
-
- **Never hardcode credentials** in YAML files — always use \`{{variable}}\` references
|
|
120
|
-
|
|
121
|
-
` : ""}---
|
|
122
|
-
|
|
123
|
-
## YAML Test Suite Format Reference
|
|
62
|
+
const YAML_FORMAT_CHEATSHEET = `
|
|
63
|
+
## YAML Test Format Reference
|
|
124
64
|
|
|
65
|
+
### Suite structure
|
|
125
66
|
\`\`\`yaml
|
|
126
|
-
name:
|
|
127
|
-
|
|
128
|
-
tags: [smoke
|
|
129
|
-
base_url: "{{base_url}}"
|
|
130
|
-
headers: # optional suite-level headers
|
|
131
|
-
Authorization: "Bearer {{auth_token}}"
|
|
132
|
-
Content-Type: "application/json"
|
|
133
|
-
config: # optional
|
|
134
|
-
timeout: 30000
|
|
135
|
-
retries: 0
|
|
136
|
-
follow_redirects: true
|
|
67
|
+
name: Suite Name # required
|
|
68
|
+
base_url: "{{base_url}}" # or hardcoded URL
|
|
69
|
+
tags: [smoke] # optional: smoke | crud | destructive | auth
|
|
137
70
|
tests:
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
limit: "10"
|
|
144
|
-
headers: # step-level headers (override suite)
|
|
145
|
-
X-Custom: "value"
|
|
146
|
-
expect:
|
|
147
|
-
status: 200 # expected HTTP status: integer OR array [200, 204]
|
|
148
|
-
body: # field-level assertions
|
|
149
|
-
id: { type: "integer", capture: "item_id" }
|
|
150
|
-
name: { equals: "expected" }
|
|
151
|
-
email: { contains: "@", type: "string" }
|
|
152
|
-
count: { gt: 0, lt: 100 }
|
|
153
|
-
items: { exists: true } # exists must be boolean, NEVER string
|
|
154
|
-
pattern: { matches: "^[A-Z]+" }
|
|
155
|
-
headers:
|
|
156
|
-
Content-Type: "application/json"
|
|
157
|
-
duration: 5000 # max response time in ms
|
|
158
|
-
\`\`\`
|
|
159
|
-
|
|
160
|
-
### Assertion Rules
|
|
161
|
-
- \`capture: "var_name"\` — SAVES the value into a variable (use in later steps as {{var_name}})
|
|
162
|
-
- \`equals: value\` — exact match COMPARISON (NEVER use equals to save a value!)
|
|
163
|
-
- \`type: "string"|"number"|"integer"|"boolean"|"array"|"object"\`
|
|
164
|
-
- \`contains: "substring"\` — string substring match
|
|
165
|
-
- \`matches: "regex"\` — regex pattern match
|
|
166
|
-
- \`gt: N\` / \`lt: N\` — numeric comparison
|
|
167
|
-
- \`exists: true|false\` — field presence check (MUST be boolean, not string)
|
|
168
|
-
|
|
169
|
-
### Nested Body Assertions
|
|
170
|
-
Both forms are equivalent and supported:
|
|
171
|
-
|
|
172
|
-
**Dot-notation (flat):**
|
|
173
|
-
\`\`\`yaml
|
|
174
|
-
body:
|
|
175
|
-
"category.name": { equals: "Dogs" }
|
|
176
|
-
"address.city": { type: "string" }
|
|
177
|
-
\`\`\`
|
|
178
|
-
|
|
179
|
-
**Nested YAML (auto-flattened):**
|
|
180
|
-
\`\`\`yaml
|
|
181
|
-
body:
|
|
182
|
-
category:
|
|
183
|
-
name: { equals: "Dogs" }
|
|
184
|
-
address:
|
|
185
|
-
city: { type: "string" }
|
|
71
|
+
- GET /endpoint: # method + path as YAML key
|
|
72
|
+
query: { limit: 10 }
|
|
73
|
+
expect:
|
|
74
|
+
status: 200
|
|
75
|
+
_body: { type: array }
|
|
186
76
|
\`\`\`
|
|
187
77
|
|
|
188
|
-
###
|
|
189
|
-
|
|
190
|
-
|
|
78
|
+
### Assertion operators
|
|
79
|
+
| Operator | Example |
|
|
80
|
+
|----------|---------|
|
|
81
|
+
| equals (default) | \`status: 200\` |
|
|
82
|
+
| not_equals | \`status: { not_equals: 500 }\` |
|
|
83
|
+
| contains | \`name: { contains: "john" }\` |
|
|
84
|
+
| not_contains | \`body: { not_contains: "error" }\` |
|
|
85
|
+
| exists / not_exists | \`id: { exists: true }\` |
|
|
86
|
+
| gt / gte / lt / lte | \`count: { gte: 1 }\` |
|
|
87
|
+
| matches (regex) | \`email: { matches: "^.+@.+$" }\` |
|
|
88
|
+
| type | \`items: { type: array }\` |
|
|
89
|
+
| length | \`items: { length: 5 }\` |
|
|
90
|
+
| length_gt/gte/lt/lte | \`items: { length_gt: 0 }\` |
|
|
91
|
+
|
|
92
|
+
### Body assertions
|
|
93
|
+
- \`_body\` — assert on entire response body: \`_body: { type: array }\`
|
|
94
|
+
- Dot-notation for nested: \`data.user.id: { exists: true }\`
|
|
95
|
+
- Array item access: \`items.0.name: { exists: true }\`
|
|
96
|
+
|
|
97
|
+
### Request body (JSON)
|
|
191
98
|
\`\`\`yaml
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
99
|
+
- POST /resource:
|
|
100
|
+
json: { name: "test", email: "a@b.com" }
|
|
101
|
+
expect:
|
|
102
|
+
status: 201
|
|
196
103
|
\`\`\`
|
|
197
104
|
|
|
198
|
-
### Built-in
|
|
199
|
-
|
|
200
|
-
These are the ONLY generators — do NOT invent others.
|
|
201
|
-
|
|
202
|
-
### Variable Interpolation
|
|
203
|
-
- \`{{variable}}\` in paths, bodies, headers, query params
|
|
204
|
-
- Captured values from previous steps are available in subsequent steps
|
|
205
|
-
- Environment variables from .env.yaml files: \`{{base_url}}\`, \`{{auth_username}}\`, etc.
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## Step-by-Step Generation Algorithm
|
|
210
|
-
|
|
211
|
-
### Step 0: Register the API (REQUIRED FIRST)
|
|
212
|
-
**Always call \`setup_api\` before generating any tests.** This registers the collection in the database so WebUI, coverage tracking, and env loading all work.
|
|
213
|
-
\`\`\`
|
|
214
|
-
setup_api(name: "myapi", specPath: "/path/to/openapi.json", dir: "/path/to/project/apis/myapi")
|
|
215
|
-
\`\`\`
|
|
216
|
-
If you skip this step, WebUI will show "No API collections registered yet" and env variables won't auto-load.
|
|
105
|
+
### Built-in generators
|
|
106
|
+
\`{{$uuid}}\`, \`{{$randomInt}}\`, \`{{$timestamp}}\`, \`{{$isoTimestamp}}\`, \`{{$randomEmail}}\`, \`{{$randomString}}\`
|
|
217
107
|
|
|
218
|
-
|
|
108
|
+
### Variable capture & interpolation
|
|
219
109
|
\`\`\`yaml
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
` : ""}\
|
|
226
|
-
### Step 1: Analyze the API
|
|
227
|
-
- Identify authentication method (${hasAuth ? opts.securitySchemes.map(s => `${s.name}: ${s.type}${s.scheme ? `/${s.scheme}` : ""}`).join(", ") : "none detected"})
|
|
228
|
-
- Group endpoints by resource (e.g., /users/*, /pets/*, /orders/*)
|
|
229
|
-
- Identify CRUD patterns: POST (create) → GET (read) → PUT/PATCH (update) → DELETE
|
|
230
|
-
- Note required fields in request bodies
|
|
231
|
-
|
|
232
|
-
### Step 2: Plan Test Suites
|
|
233
|
-
Before generating, check coverage with \`coverage_analysis\` to avoid duplicating existing tests. Use \`generate_and_save(testsDir=...)\` for incremental generation of uncovered endpoints only.
|
|
234
|
-
|
|
235
|
-
> **Coverage note**: coverage is a static scan of YAML files — an endpoint is "covered" if a test file contains a matching METHOD + path line, regardless of whether tests pass or actually run.
|
|
236
|
-
|
|
237
|
-
Create separate files for each concern:
|
|
238
|
-
${hasAuth ? `- \`${opts.outputDir}auth.yaml\` — Authentication flow\n` : ""}\
|
|
239
|
-
- \`${opts.outputDir}{resource}-crud.yaml\` — CRUD lifecycle per resource
|
|
240
|
-
- \`${opts.outputDir}{resource}-validation.yaml\` — Error cases per resource
|
|
241
|
-
|
|
242
|
-
### Step 3: Generate Each Suite
|
|
243
|
-
|
|
244
|
-
${hasAuth ? `**Auth suite** (\`auth.yaml\`):
|
|
245
|
-
1. Login with valid credentials → capture token
|
|
246
|
-
2. Access protected endpoint with token → 200
|
|
247
|
-
3. Login with invalid credentials → 401/403
|
|
248
|
-
4. Access protected endpoint without token → 401
|
|
249
|
-
|
|
250
|
-
` : ""}\
|
|
251
|
-
**CRUD lifecycle** (\`{resource}-crud.yaml\`):
|
|
252
|
-
1. Create resource (POST) → 201, **always verify key fields in response body** (at minimum: id, name/title)
|
|
253
|
-
2. Read created resource (GET /resource/{{id}}) → 200, verify fields match what was sent
|
|
254
|
-
3. List resources (GET /resource) → 200, verify \`_body: { type: "array" }\` AND \`_body.length: { gt: 0 }\`
|
|
255
|
-
4. Update resource (PUT/PATCH /resource/{{id}}) → 200
|
|
256
|
-
5. Read updated resource → verify changes applied
|
|
257
|
-
6. Delete resource (DELETE /resource/{{id}}) → 200/204
|
|
258
|
-
7. Verify deleted (GET /resource/{{id}}) → 404
|
|
259
|
-
8. For bulk create endpoints (createWithArray/List): create → then GET each to verify they exist
|
|
260
|
-
|
|
261
|
-
**Validation suite** (\`{resource}-validation.yaml\`):
|
|
262
|
-
1. Create with missing required fields → 400/422, verify \`message: { exists: true }\` in error body
|
|
263
|
-
2. Create with invalid field types → 400/422
|
|
264
|
-
3. Get non-existent resource (e.g. id=999999) → 404
|
|
265
|
-
4. Delete non-existent resource → 404
|
|
266
|
-
5. For error responses: always assert error body has meaningful content, not just status code
|
|
267
|
-
|
|
268
|
-
### Step 4: Save, Run, Debug
|
|
269
|
-
1. Use \`save_test_suite\` to save each file — it validates YAML before writing
|
|
270
|
-
2. Use \`run_tests\` to execute — review pass/fail summary
|
|
271
|
-
3. If failures: use \`query_db\` with \`action: "diagnose_failure"\` and the runId to see full request/response details
|
|
272
|
-
4. Fix issues and re-save with \`overwrite: true\`
|
|
273
|
-
|
|
274
|
-
---
|
|
275
|
-
|
|
276
|
-
## Tag Conventions
|
|
277
|
-
|
|
278
|
-
Use standard tags to enable safe filtering:
|
|
279
|
-
|
|
280
|
-
| Tag | HTTP Methods | Safe for |
|
|
281
|
-
|-----|-------------|---------|
|
|
282
|
-
| \`smoke\` | GET only | Production (read-only, zero risk) |
|
|
283
|
-
| \`crud\` | POST/PUT/PATCH | Staging only (state-changing) |
|
|
284
|
-
| \`destructive\` | DELETE | Explicit opt-in, run last |
|
|
285
|
-
| \`auth\` | Any (auth flows) | Run first to capture tokens |
|
|
286
|
-
|
|
287
|
-
Example: \`zond run --tag smoke --safe\` → reads-only, safe against production.
|
|
288
|
-
|
|
289
|
-
---
|
|
290
|
-
|
|
291
|
-
## Practical Tips
|
|
292
|
-
|
|
293
|
-
- **int64 IDs**: For APIs returning large auto-generated IDs (int64), prefer setting fixed IDs in request bodies rather than capturing auto-generated ones, as JSON number precision may cause mismatches.
|
|
294
|
-
- **Nested assertions**: Use dot-notation or nested YAML — both work identically.
|
|
295
|
-
- **Root body type**: Use \`_body: { type: "array" }\` to verify the response body type itself.
|
|
296
|
-
- **List endpoints**: Always check both type AND non-emptiness: \`_body: { type: "array" }\` + \`_body.length: { gt: 0 }\`
|
|
297
|
-
- **Create responses**: Always verify at least the key identifying fields (id, name) in the response body — don't just check status.
|
|
298
|
-
- **Error responses**: Assert that error bodies contain useful info (\`message: { exists: true }\`), not just status codes.
|
|
299
|
-
- **Bulk operations**: After bulk create (createWithArray, createWithList), add GET steps to verify resources were actually created.
|
|
300
|
-
- **204 No Content**: When an endpoint returns 204, omit \`body:\` assertions entirely — an empty response IS the correct behavior. Adding body assertions on 204 will always fail.
|
|
301
|
-
- **Cleanup pattern**: Always delete test data in the same suite. Use a create → read → delete lifecycle so tests are idempotent:
|
|
302
|
-
\`\`\`yaml
|
|
303
|
-
tests:
|
|
304
|
-
- name: Create test resource
|
|
305
|
-
POST: /users
|
|
306
|
-
json: { name: "zond-test-{{$randomString}}" }
|
|
110
|
+
- POST /items:
|
|
111
|
+
json: { name: "test-{{$uuid}}" }
|
|
112
|
+
capture:
|
|
113
|
+
created_id: id # saves response.id
|
|
307
114
|
expect:
|
|
308
115
|
status: 201
|
|
309
|
-
|
|
310
|
-
id: { capture: user_id }
|
|
311
|
-
- name: Read created resource
|
|
312
|
-
GET: /users/{{user_id}}
|
|
116
|
+
- GET /items/{{created_id}}:
|
|
313
117
|
expect:
|
|
314
118
|
status: 200
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
expect:
|
|
318
|
-
status: 204
|
|
319
|
-
\`\`\`
|
|
320
|
-
- **Identifiable test data**: Prefix test data with \`zond-test-\` or use \`{{$uuid}}\` / \`zond-test-{{$randomString}}\` so you can identify and clean up leftover test data if needed.
|
|
321
|
-
|
|
322
|
-
---
|
|
323
|
-
|
|
324
|
-
## Common Mistakes to Avoid
|
|
119
|
+
\`\`\`
|
|
120
|
+
`;
|
|
325
121
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
122
|
+
export interface GuideOptions {
|
|
123
|
+
title: string;
|
|
124
|
+
baseUrl?: string;
|
|
125
|
+
apiContext: string;
|
|
126
|
+
outputDir: string;
|
|
127
|
+
securitySchemes: SecuritySchemeInfo[];
|
|
128
|
+
endpointCount: number;
|
|
129
|
+
coverageHeader?: string;
|
|
130
|
+
includeFormat?: boolean;
|
|
131
|
+
}
|
|
335
132
|
|
|
336
|
-
|
|
133
|
+
export function buildGenerationGuide(opts: GuideOptions): string {
|
|
134
|
+
const hasAuth = opts.securitySchemes.length > 0;
|
|
337
135
|
|
|
338
|
-
|
|
136
|
+
const securitySummary = hasAuth
|
|
137
|
+
? `Security: ${opts.securitySchemes.map(s => `${s.name} (${s.type}${s.scheme ? `/${s.scheme}` : ""})`).join(", ")}`
|
|
138
|
+
: "Security: none";
|
|
339
139
|
|
|
340
|
-
|
|
341
|
-
|------|------|
|
|
342
|
-
| \`setup_api\` | Register a new API (creates dirs, reads spec, sets up env) |
|
|
343
|
-
| \`generate_and_save\` | Get test generation guide (with auto-chunking for large APIs) |
|
|
344
|
-
| \`save_test_suite\` | Save generated YAML (validates before writing) |
|
|
345
|
-
| \`save_test_suites\` | Save multiple YAML files in one call |
|
|
346
|
-
| \`run_tests\` | Execute saved test suites |
|
|
347
|
-
| \`query_db\` | Query runs, collections, results, diagnose failures |
|
|
348
|
-
| \`coverage_analysis\` | Find untested endpoints for incremental generation |
|
|
349
|
-
| \`describe_endpoint\` | Get full details for one endpoint when debugging |
|
|
350
|
-
| \`ci_init\` | Generate CI/CD workflow (GitHub Actions / GitLab CI) to run tests on push |
|
|
140
|
+
const formatSection = opts.includeFormat !== false ? YAML_FORMAT_CHEATSHEET : "";
|
|
351
141
|
|
|
352
|
-
|
|
142
|
+
return `# Test Generation Guide for ${opts.title}
|
|
143
|
+
${opts.coverageHeader ? `\n${opts.coverageHeader}\n` : ""}
|
|
144
|
+
## API Specification (${opts.endpointCount} endpoints)
|
|
145
|
+
${opts.baseUrl ? `Base URL: ${opts.baseUrl}` : "Base URL: use {{base_url}} environment variable"}
|
|
146
|
+
${securitySummary}
|
|
353
147
|
|
|
354
|
-
|
|
355
|
-
1. Use \`ci_init\` to generate a CI workflow (auto-detects platform or use platform param)
|
|
356
|
-
2. Help them commit and push to their repository
|
|
357
|
-
3. Tests will run automatically on push, PR, and on schedule
|
|
358
|
-
`;
|
|
148
|
+
${opts.apiContext}${formatSection}`;
|
|
359
149
|
}
|
package/src/mcp/descriptions.ts
CHANGED
|
@@ -56,7 +56,8 @@ export const TOOL_DESCRIPTIONS = {
|
|
|
56
56
|
"Read an OpenAPI spec, auto-chunk by tags if large (>30 endpoints), " +
|
|
57
57
|
"and return a focused test generation guide. For large APIs returns a chunking plan — " +
|
|
58
58
|
"call again with tag parameter for each chunk. Use testsDir param to only generate for uncovered endpoints. " +
|
|
59
|
-
"After generating YAML, use save_test_suites to save files, then run_tests to verify."
|
|
59
|
+
"After generating YAML, use save_test_suites to save files, then run_tests to verify. " +
|
|
60
|
+
"Includes YAML format cheatsheet by default; pass includeFormat: false for subsequent tag chunks to save tokens.",
|
|
60
61
|
|
|
61
62
|
ci_init:
|
|
62
63
|
"Generate a CI/CD workflow file for running API tests automatically on push, PR, and schedule. " +
|
|
@@ -21,8 +21,9 @@ export function registerGenerateAndSaveTool(server: McpServer) {
|
|
|
21
21
|
methodFilter: z.optional(z.array(z.string())).describe("Only include endpoints with these HTTP methods (e.g. [\"GET\"] for smoke tests)"),
|
|
22
22
|
testsDir: z.optional(z.string()).describe("Path to existing tests directory — filters to uncovered endpoints only"),
|
|
23
23
|
overwrite: z.optional(z.boolean()).describe("Hint for save_test_suites overwrite behavior (default: false)"),
|
|
24
|
+
includeFormat: z.optional(z.boolean()).describe("Include YAML format reference (default: true, set false for subsequent tag chunks)"),
|
|
24
25
|
},
|
|
25
|
-
}, async ({ specPath, outputDir, tag, methodFilter, testsDir, overwrite }) => {
|
|
26
|
+
}, async ({ specPath, outputDir, tag, methodFilter, testsDir, overwrite, includeFormat }) => {
|
|
26
27
|
try {
|
|
27
28
|
const doc = await readOpenApiSpec(specPath);
|
|
28
29
|
let endpoints = extractEndpoints(doc);
|
|
@@ -82,6 +83,7 @@ export function registerGenerateAndSaveTool(server: McpServer) {
|
|
|
82
83
|
instruction:
|
|
83
84
|
`This API has ${plan.totalEndpoints} endpoints across ${plan.chunks.length} tags. ` +
|
|
84
85
|
`Call generate_and_save with tag parameter for each chunk sequentially. ` +
|
|
86
|
+
`Pass includeFormat: false for subsequent chunks to save tokens. ` +
|
|
85
87
|
`Example: generate_and_save(specPath: '${specPath}', tag: '${plan.chunks[0].tag}')`,
|
|
86
88
|
};
|
|
87
89
|
if (coverageInfo) {
|
|
@@ -106,7 +108,7 @@ export function registerGenerateAndSaveTool(server: McpServer) {
|
|
|
106
108
|
securitySchemes,
|
|
107
109
|
endpointCount: endpoints.length,
|
|
108
110
|
coverageHeader,
|
|
109
|
-
|
|
111
|
+
includeFormat: includeFormat ?? true,
|
|
110
112
|
});
|
|
111
113
|
|
|
112
114
|
const saveInstructions = `
|