@qase/mcp-server 2.4.0 → 2.4.1

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/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.4.1]
9
+
10
+ ### Fixed
11
+
12
+ - **The bulk results endpoint takes 200 results per request, and nothing said so.** `qase_result_record` advertised no ceiling while its description told agents to "pass several results in one call rather than calling once per test", so a larger batch reached the API and came back as an error with no hint of what the limit was. It now states the cap, and refuses an oversized batch before anything is written. The cap is enforced rather than described: the registry turns a tool's schema into JSON Schema for the protocol but never validates a call against it, so `.max()` alone would have been advertising with nothing behind it — the handler parses its own arguments, which also means an empty results array and an unknown status are now rejected instead of being passed through to the API.
13
+
14
+ - **`qase_ci_report` splits a large batch instead of failing on it.** A finished suite of more than 200 tests is the ordinary case for this tool, and refusing it would push an agent back onto the create-run, record, complete sequence the tool exists to replace. Results are now sent in batches of 200, up to 2000 in one report — a bound on the call rather than an open-ended loop, because a call that outlives the client's timeout is the one failure that says nothing about how far the recording got. Splitting is done here and deliberately not in `qase_result_record`: a retry of a CI report builds a new run, so a half-written attempt leaves a junk run behind, while a retry against an existing run records the first batch a second time and leaves a live run with a believable but wrong pass rate. If a batch does fail part way, the error names the run that exists, how many results reached it, and how to record the rest without creating a second run.
15
+
16
+ - **`qase_ci_report` now honours its own defaults.** `complete` and `is_autotest` were declared as defaulting to true, but nothing ever applied the defaults: arguments reach a handler exactly as the client sent them. A report that omitted `complete` left the run active despite the description promising it would be completed, and one that omitted `is_autotest` created a manual run. Both now default as documented.
17
+
8
18
  ## [2.4.0]
9
19
 
10
20
  ### Added
@@ -5,6 +5,15 @@ import { toResultAsync, createToolError } from '../../utils/errors.js';
5
5
  import { ProjectCodeSchema } from '../../utils/validation.js';
6
6
  import { CiReportOutput } from '../../utils/output-schemas.js';
7
7
  import { richResult, summaryBlock, dataBlock, markdownTable } from '../../utils/rich-response.js';
8
+ const CONTEXT = 'CI report';
9
+ /** What the bulk results endpoint accepts in one request. */
10
+ const RESULTS_PER_CALL = 200;
11
+ /**
12
+ * A ceiling on one tool call: ten requests, not an open-ended loop. Past this
13
+ * the call risks outliving the client's timeout, and a timeout is the one
14
+ * failure that tells the model nothing about how far the recording got.
15
+ */
16
+ const MAX_RESULTS = 2000;
8
17
  const CaseResultSchema = z.object({
9
18
  case_id: z.number().int().positive(),
10
19
  status: z.enum(['passed', 'failed', 'blocked', 'skipped', 'invalid']),
@@ -21,7 +30,12 @@ const Schema = z.object({
21
30
  code: ProjectCodeSchema,
22
31
  title: z.string().min(1).max(255).describe('Run title (e.g., "CI Build #1234")'),
23
32
  environment_id: z.number().int().positive().optional(),
24
- results: z.array(CaseResultSchema).min(1).describe('Test results to record'),
33
+ results: z
34
+ .array(CaseResultSchema)
35
+ .min(1)
36
+ .max(MAX_RESULTS, `One CI report covers at most ${MAX_RESULTS} results — report a larger suite as several ` +
37
+ 'runs, or create the run with qase_run_upsert and record the results in batches.')
38
+ .describe(`Test results to record, 1 to ${MAX_RESULTS} per call`),
25
39
  complete: z
26
40
  .boolean()
27
41
  .optional()
@@ -33,9 +47,21 @@ const Schema = z.object({
33
47
  .default(true)
34
48
  .describe('Mark as automated run (default: true)'),
35
49
  });
36
- async function handler(args) {
50
+ async function handler(rawArgs) {
51
+ // Tool handlers get raw MCP arguments — the registry only turns the schema
52
+ // into JSON Schema for the protocol, so nothing has validated them and no
53
+ // default has been applied yet. Parsing here is what makes `complete` and
54
+ // `is_autotest` actually default to true, and what stops an oversized
55
+ // report before a run is created for it.
56
+ const parsed = Schema.safeParse(rawArgs);
57
+ if (!parsed.success) {
58
+ const details = parsed.error.issues
59
+ .map((issue) => `${issue.path.join('.') || 'arguments'}: ${issue.message}`)
60
+ .join('; ');
61
+ throw createToolError(`Invalid arguments — ${details}`, CONTEXT);
62
+ }
37
63
  const client = getApiClient();
38
- const { code, title, environment_id, results, complete, is_autotest } = args;
64
+ const { code, title, environment_id, results, complete, is_autotest } = parsed.data;
39
65
  // Step 1: Create run
40
66
  const runPayload = {
41
67
  title,
@@ -46,14 +72,33 @@ async function handler(args) {
46
72
  runPayload.environment_id = environment_id;
47
73
  const runRes = await toResultAsync(client.runs.createRun(code, runPayload));
48
74
  const run = runRes.match((r) => r.data.result, (e) => {
49
- throw createToolError(e, 'CI report: run creation failed');
75
+ throw createToolError(e, `${CONTEXT}: run creation failed`);
50
76
  });
51
77
  const runId = run.id;
52
- // Step 2: Bulk record results
53
- const bulkRes = await toResultAsync(client.results.createResultBulk(code, runId, { results: results }));
54
- bulkRes.match(() => { }, (e) => {
55
- throw createToolError(e, 'CI report: result recording failed');
56
- });
78
+ // Step 2: record the results, in batches of what the endpoint accepts. The
79
+ // batch is split here rather than refused because a finished suite of more
80
+ // than RESULTS_PER_CALL tests is the ordinary case, and refusing it would
81
+ // send the agent back to the three-call sequence this tool replaces.
82
+ const batches = [];
83
+ for (let i = 0; i < results.length; i += RESULTS_PER_CALL) {
84
+ batches.push(results.slice(i, i + RESULTS_PER_CALL));
85
+ }
86
+ let recorded = 0;
87
+ for (const batch of batches) {
88
+ const bulkRes = await toResultAsync(client.results.createResultBulk(code, runId, { results: batch }));
89
+ bulkRes.match(() => {
90
+ recorded += batch.length;
91
+ }, (e) => {
92
+ // The run already holds everything recorded so far and there is no way
93
+ // to unwind it, so say what landed and where. Repeating this call would
94
+ // build a second run rather than finishing this one.
95
+ throw createToolError(`${e} — recorded ${recorded} of ${results.length} results before this batch failed. ` +
96
+ `Run ${runId} exists and holds those ${recorded}. Record the remaining ` +
97
+ `${results.length - recorded} with qase_result_record into run ${runId}, ` +
98
+ `${RESULTS_PER_CALL} at a time; calling qase_ci_report again would create a ` +
99
+ 'second run instead of completing this one.', `${CONTEXT}: result recording failed`);
100
+ });
101
+ }
57
102
  // Step 3: Complete run (optional)
58
103
  let runStatus = 'active';
59
104
  if (complete) {
@@ -75,7 +120,8 @@ async function handler(args) {
75
120
  `- **Run ID:** ${runId}`,
76
121
  `- **Project:** ${code}`,
77
122
  `- **Status:** ${runStatus}`,
78
- `- **Total:** ${results.length}`,
123
+ `- **Total:** ${results.length}` +
124
+ (batches.length > 1 ? ` (recorded in ${batches.length} requests)` : ''),
79
125
  '',
80
126
  markdownTable(['Passed', 'Failed', 'Blocked', 'Skipped'], [[String(passed), String(failed), String(blocked), String(skipped)]], ['r', 'r', 'r', 'r']),
81
127
  ];
@@ -86,7 +132,7 @@ async function handler(args) {
86
132
  lines.push(`- Case #${r.case_id}${comment}`);
87
133
  }
88
134
  }
89
- const structured = { run_id: runId, run_status: runStatus, results_recorded: results.length };
135
+ const structured = { run_id: runId, run_status: runStatus, results_recorded: recorded };
90
136
  return richResult([summaryBlock(lines.join('\n')), dataBlock(structured)], structured);
91
137
  }
92
138
  toolRegistry.register({
@@ -97,7 +143,9 @@ toolRegistry.register({
97
143
  'stops early. Each result needs a numeric `case_id` plus a status, and may carry duration, ' +
98
144
  'comment, stacktrace and attachment hashes. Use qase_result_record instead when the run ' +
99
145
  'already exists and results arrive in stages; use qase_run_upsert when you need the run left ' +
100
- 'open. Cost: one tool call covering three API operations. A run with two results measured ' +
146
+ `open. A batch larger than ${RESULTS_PER_CALL} is split across requests for you, up to ` +
147
+ `${MAX_RESULTS} results in one report. Cost: one tool call covering three API operations, ` +
148
+ `plus one extra request per ${RESULTS_PER_CALL} results. A run with two results measured ` +
101
149
  'about 0.7s, against roughly 1.5s for the same work as three separate calls, and it grows ' +
102
150
  'with the number of results rather than with the number of round trips.',
103
151
  schema: Schema,
@@ -1 +1 @@
1
- {"version":3,"file":"ci-report.js","sourceRoot":"","sources":["../../../src/operations-v2/composites/ci-report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ci-report.js","sourceRoot":"","sources":["../../../src/operations-v2/composites/ci-report.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,15 @@ import { getApiClient } from '../../client/index.js';
3
3
  import { toolRegistry, CreateAnnotation, DeleteAnnotation } from '../../utils/registry.js';
4
4
  import { toResultAsync, createToolError } from '../../utils/errors.js';
5
5
  import { ProjectCodeSchema, IdSchema } from '../../utils/validation.js';
6
+ const CONTEXT = 'result operation';
7
+ /**
8
+ * The bulk endpoint takes 200 results per request. Rejected here rather than
9
+ * split into chunks: results are append-only, so a batch that fails half way
10
+ * cannot be rolled back, and the obvious retry records the first chunk twice
11
+ * and leaves the run with a wrong pass rate. qase_ci_report chunks instead,
12
+ * because a retry there makes a new run rather than adding to a real one.
13
+ */
14
+ const MAX_RESULTS = 200;
6
15
  const ResultStepSchema = z.object({
7
16
  position: z.number().int().min(0),
8
17
  status: z.enum(['passed', 'failed', 'blocked', 'skipped']),
@@ -29,43 +38,61 @@ const SingleResultSchema = z.object({
29
38
  const RecordSchema = z.object({
30
39
  code: ProjectCodeSchema,
31
40
  run_id: IdSchema.describe('Run ID to record results into'),
32
- results: z.array(SingleResultSchema).min(1).describe('One or more results to record'),
41
+ results: z
42
+ .array(SingleResultSchema)
43
+ .min(1)
44
+ .max(MAX_RESULTS, `A single call records at most ${MAX_RESULTS} results — split larger batches into ` +
45
+ 'consecutive calls.')
46
+ .describe(`Results to record, 1 to ${MAX_RESULTS} per call`),
33
47
  });
34
48
  const DeleteSchema = z.object({
35
49
  code: ProjectCodeSchema,
36
50
  run_id: IdSchema,
37
51
  hash: z.string().min(1).describe('Result hash to delete'),
38
52
  });
39
- async function record(args) {
53
+ async function record(rawArgs) {
54
+ // Tool handlers get raw MCP arguments — the registry only turns the schema
55
+ // into JSON Schema for the protocol, so nothing has checked them yet. An
56
+ // oversized batch has to fail here to fail at all.
57
+ const parsed = RecordSchema.safeParse(rawArgs);
58
+ if (!parsed.success) {
59
+ const details = parsed.error.issues
60
+ .map((issue) => `${issue.path.join('.') || 'arguments'}: ${issue.message}`)
61
+ .join('; ');
62
+ throw createToolError(`Invalid arguments — ${details}`, CONTEXT);
63
+ }
40
64
  const client = getApiClient();
41
- const { code, run_id, results } = args;
65
+ const { code, run_id, results } = parsed.data;
42
66
  if (results.length === 1) {
43
67
  const single = results[0];
44
68
  const res = await toResultAsync(client.results.createResult(code, run_id, single));
45
69
  return res.match((r) => r.data.result, (e) => {
46
- throw createToolError(e, 'result operation');
70
+ throw createToolError(e, CONTEXT);
47
71
  });
48
72
  }
49
73
  const res = await toResultAsync(client.results.createResultBulk(code, run_id, { results: results }));
50
74
  return res.match(() => ({ success: true, count: results.length }), (e) => {
51
- throw createToolError(e, 'result operation');
75
+ throw createToolError(e, CONTEXT);
52
76
  });
53
77
  }
54
78
  async function del(args) {
55
79
  const client = getApiClient();
56
80
  const result = await toResultAsync(client.results.deleteResult(args.code, args.run_id, args.hash));
57
81
  return result.match(() => ({ success: true, hash: args.hash }), (e) => {
58
- throw createToolError(e, 'result operation');
82
+ throw createToolError(e, CONTEXT);
59
83
  });
60
84
  }
61
85
  toolRegistry.register({
62
86
  name: 'qase_result_record',
63
- description: 'Record one or more results into an existing run. A case says what should be tested; a result ' +
64
- 'says what happened when it ran — status, duration, comment, stacktrace, attachments — so a ' +
65
- 'result always needs a run to live in. Pass several results in one call rather than calling ' +
66
- 'once per test: the tool takes a list and sends them together. If the run does not exist yet ' +
67
- 'and this is a finished CI job, qase_ci_report is the single call that creates the run, ' +
68
- 'records the results and completes it. Status is a label, one of "passed", "failed", ' +
87
+ description: `Record up to ${MAX_RESULTS} results into an existing run. A case says what should be tested; ` +
88
+ 'a result says what happened when it ran — status, duration, comment, stacktrace, ' +
89
+ 'attachments — so a result always needs a run to live in. Pass several results in one call ' +
90
+ 'rather than calling once per test: the tool takes a list and sends them together. ' +
91
+ `${MAX_RESULTS} is the ceiling for one call, and a longer list is refused before anything is ` +
92
+ 'written split it into consecutive calls rather than dropping the tail. If the run does ' +
93
+ 'not exist yet and this is a finished CI job, qase_ci_report is the single call that creates ' +
94
+ 'the run, records the results and completes it, and it splits a larger batch for you. ' +
95
+ 'Status is a label, one of "passed", "failed", ' +
69
96
  '"blocked", "skipped" or "invalid" — unlike the case enums, numeric IDs are not accepted ' +
70
97
  'here. Cost: one API call for the whole list, about 0.5s for a small ' +
71
98
  'batch, growing with payload rather than with the number of results.',
@@ -1 +1 @@
1
- {"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/operations-v2/write/results.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/operations-v2/write/results.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.4.0";
1
+ export declare const VERSION = "2.4.1";
2
2
  //# sourceMappingURL=version.d.ts.map
package/build/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild script — do not edit manually
2
- export const VERSION = '2.4.0';
2
+ export const VERSION = '2.4.1';
3
3
  //# sourceMappingURL=version.js.map
package/docs/tools.md CHANGED
@@ -42,7 +42,7 @@ Every tool's schema uses "label or numeric ID" strings for Qase's configurable e
42
42
  | `qase_run_upsert` | Create or update a test run. If `id` is provided, updates; if omitted, creates. | `code`, `id` (optional), `title` (1-255 chars), `description`, `environment_id`, `milestone_id`, `plan_id`, `cases` (case ID array), `tags`, `is_autotest`, `start_time`/`end_time` (RFC3339), `custom_field` | core |
43
43
  | `qase_run_complete` | Mark a test run as complete. | `code`, `id` | discoverable |
44
44
  | `qase_run_delete` | Delete a test run. | `code`, `id` | discoverable |
45
- | `qase_result_record` | Record one or more test results into a run. A single entry uses the single-result API, multiple entries use bulk. Each result must include a status; `case_id` is recommended. | `code`, `run_id`, `results` (array, min 1) — each result: `case_id` (optional), `status` (enum: passed, failed, blocked, skipped, invalid), `comment`, `stacktrace`, `time_ms`, `defect` (bool), `steps` (array with `position`, `status`, `comment`, `attachments`), `attachments`, `custom_field` | core |
45
+ | `qase_result_record` | Record one or more test results into a run. A single entry uses the single-result API, multiple entries use bulk. Each result must include a status; `case_id` is recommended. **The bulk endpoint takes at most 200 results per request**, so a longer list is refused before anything is written — split it across consecutive calls. It is refused rather than split automatically because results are append-only: a batch that failed half way could not be unwound, and the natural retry would record the first 200 a second time and leave the run with a wrong pass rate. Use `qase_ci_report` for a finished run, which does split for you. | `code`, `run_id`, `results` (array, 1-200) — each result: `case_id` (optional), `status` (enum: passed, failed, blocked, skipped, invalid), `comment`, `stacktrace`, `time_ms`, `defect` (bool), `steps` (array with `position`, `status`, `comment`, `attachments`), `attachments`, `custom_field` | core |
46
46
  | `qase_result_delete` | Delete a test result by run ID and result hash. | `code`, `run_id`, `hash` | discoverable |
47
47
  | `qase_suite_upsert` | Create or update a test suite. If `id` is provided, updates the existing suite; if omitted, creates a new one. | `code`, `id` (optional), `title` (1-255 chars), `description`, `preconditions`, `parent_id` (for nesting) | discoverable |
48
48
  | `qase_suite_delete` | Delete a test suite. If `delete_cases` is true, removes all cases in the suite; if false or omitted, cases are moved to the parent suite. | `code`, `id`, `delete_cases` (optional bool) | discoverable |
@@ -86,7 +86,7 @@ Composite tools chain several underlying operations into one call, so an agent a
86
86
 
87
87
  | Tool | Description | Key params | Visibility |
88
88
  | --- | --- | --- | --- |
89
- | `qase_ci_report` | Report CI/CD test results in one call: creates a run, records all results, and optionally completes the run. Replaces the 3-4 step manual workflow of create_run → bulk_create_results → complete_run. Designed for CI pipeline integration. | `code`, `title` (1-255 chars), `environment_id` (optional), `results` (array, min 1: `case_id`, `status` (enum: passed, failed, blocked, skipped, invalid), `comment`, `time_ms`, `stacktrace`, `defect`, `attachments`), `complete` (default true), `is_autotest` (default true) | core |
89
+ | `qase_ci_report` | Report CI/CD test results in one call: creates a run, records all results, and optionally completes the run. Replaces the 3-4 step manual workflow of create_run → bulk_create_results → complete_run. Designed for CI pipeline integration. **Batches larger than 200 are split across requests automatically**, up to 2000 results in one report; beyond that, report the suite as several runs. If a batch fails part way the error names the run that exists and how many results reached it, so the rest can be recorded with `qase_result_record` rather than by repeating this call, which would create a second run. | `code`, `title` (1-255 chars), `environment_id` (optional), `results` (array, 1-2000: `case_id`, `status` (enum: passed, failed, blocked, skipped, invalid), `comment`, `time_ms`, `stacktrace`, `defect`, `attachments`), `complete` (default true), `is_autotest` (default true) | core |
90
90
  | `qase_regression_run` | Set up a regression test run in one call. Accepts case selection by suite IDs, explicit case IDs, or plan ID. Creates the run and adds all matching cases. Replaces the multi-step workflow of find cases → create run → add cases. | `code`, `title` (1-255 chars), `description`, `environment_id`, `milestone_id`, `plan_id`, `suite_ids` (array), `include_cases` (array) | core |
91
91
  | `qase_triage_defect` | Create a defect from a test failure. `title`, `actual_result`, and `severity` are all required by the API. The API offers no way to attach runs or results to a defect — the `runs`/`results` arrays seen on a defect are populated by the test runner when a result is reported as a defect — so reference failing results in `actual_result` instead. (`run_id` and `failed_result_ids` were removed in 2.1.0: they were accepted and ignored.) | `code`, `title` (1-255 chars), `actual_result` (required), `severity` (required, enum, see [below](#case-enum-values)), `description`, `tags`, `attachments`, `custom_field` | core |
92
92
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qase/mcp-server",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "mcpName": "io.qase/mcp-server",
5
5
  "description": "Official MCP server for Qase Test Management Platform",
6
6
  "type": "module",
package/server.json CHANGED
@@ -8,12 +8,12 @@
8
8
  "url": "https://github.com/qase-tms/qase-mcp-server",
9
9
  "source": "github"
10
10
  },
11
- "version": "2.4.0",
11
+ "version": "2.4.1",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "identifier": "@qase/mcp-server",
16
- "version": "2.4.0",
16
+ "version": "2.4.1",
17
17
  "transport": {
18
18
  "type": "stdio"
19
19
  },