update_test_cycle
Update a test cycle's metadata (summary, description, priority, status, dates, custom fields) by providing the cycle ID or key. A successful update returns 204.
Instructions
Update a test cycle's metadata (summary, description, priority, status, dates, custom fields). Pass the internal id or key. Returns 204 on success.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Test cycle ID | |
| summary | No | ||
| description | No | ||
| priority | No | ||
| status | No | ||
| assignee | No | ||
| plannedStartDate | No | ISO 8601 date | |
| plannedEndDate | No | ISO 8601 date | |
| customFields | No |
Implementation Reference
- src/index.ts:405-408 (handler)The handler function for the 'update_test_cycle' tool. It destructures 'id' from the rest of the input, makes a PUT request to /testcycles/{id} with the remaining fields as JSON body, and returns a success message.
async ({ id, ...rest }) => { await qtmFetch(`/testcycles/${id}`, { method: "PUT", body: JSON.stringify(rest) }); return ok({ message: `Test cycle ${id} updated` }); } - src/index.ts:394-403 (schema)The schema definition for 'update_test_cycle'. Accepts: id (string|number), and optional fields summary, description, priority, status, assignee, plannedStartDate, plannedEndDate (ISO 8601), and customFields (array of CustomField objects).
{ id: ID.describe("Test cycle ID"), summary: z.string().optional(), description: z.string().optional(), priority: z.string().optional(), status: z.string().optional(), assignee: z.string().optional(), plannedStartDate: z.string().optional().describe("ISO 8601 date"), plannedEndDate: z.string().optional().describe("ISO 8601 date"), customFields: z.array(CustomField).optional(), - src/index.ts:172-184 (registration)The 'tool' helper function that wraps server.registerTool(). It registers the tool with its name, description, input schema, and callback on the McpServer instance.
const tool = <Shape extends z.ZodRawShape>( name: string, description: string, inputSchema: Shape, // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (args: z.infer<z.ZodObject<Shape>>) => Promise<any> ) => server.registerTool( name, { description, inputSchema }, // eslint-disable-next-line @typescript-eslint/no-explicit-any callback as any ); - src/index.ts:391-409 (registration)The tool registration call for 'update_test_cycle', invoking the 'tool()' wrapper with name='update_test_cycle', description, schema, and handler callback. This connects the handler to the MCP server.
tool( "update_test_cycle", "Update a test cycle's metadata (summary, description, priority, status, dates, custom fields). Pass the internal id or key. Returns 204 on success.", { id: ID.describe("Test cycle ID"), summary: z.string().optional(), description: z.string().optional(), priority: z.string().optional(), status: z.string().optional(), assignee: z.string().optional(), plannedStartDate: z.string().optional().describe("ISO 8601 date"), plannedEndDate: z.string().optional().describe("ISO 8601 date"), customFields: z.array(CustomField).optional(), }, async ({ id, ...rest }) => { await qtmFetch(`/testcycles/${id}`, { method: "PUT", body: JSON.stringify(rest) }); return ok({ message: `Test cycle ${id} updated` }); } ); - src/index.ts:25-66 (helper)The qtmFetch helper function used by the update_test_cycle handler to make the PUT API call to QMetry.
async function qtmFetch( path: string, options: RequestInit = {}, attempt = 1 ): Promise<unknown> { const url = `${BASE_URL}${path}`; const headers: Record<string, string> = { apiKey: API_KEY ?? "", "Content-Type": "application/json", Accept: "application/json", ...(options.headers as Record<string, string> | undefined), }; const response = await fetch(url, { ...options, headers }); // Exponential back-off for rate limiting (max 3 attempts) if (response.status === 429 && attempt < 3) { const retryAfter = Number.parseInt( response.headers.get("Retry-After") ?? "1", 10 ); const delay = Math.max(retryAfter * 1000, 1000) * attempt; await new Promise((r) => setTimeout(r, delay)); return qtmFetch(path, options, attempt + 1); } const text = await response.text(); let body: unknown; try { body = text ? JSON.parse(text) : null; } catch { body = text; } if (!response.ok) { throw new Error( `HTTP ${response.status} ${response.statusText}: ${JSON.stringify(body)}` ); } return body; }