Skip to main content
Glama
Derrbal
by Derrbal

add_case

Create new test cases in TestRail by specifying title, section, type, priority, and custom fields to organize testing requirements systematically.

Instructions

Create a new TestRail test case in a specific section. IMPORTANT: Before creating a case, gather required information using get_projects, get_suites, get_sections, and get_case_fields tools to ensure proper section_id, type_id, and custom field values. Or ask the user to provide the information if not provided.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
titleYesTest case title - should be descriptive and unique within the section
section_idYesSection ID where the case will be created. REQUIRED: Use get_sections tool first to find valid section IDs for your project/suite. Different projects have different section structures.
type_idNoTest case type ID (e.g., 1=Acceptance, 2=Accessibility, 3=Automated, 4=Compatibility, 5=Destructive, 6=Functional, 7=Other, 8=Performance, 9=Regression, 10=Security, 11=Smoke & Sanity, 12=Usability). RECOMMENDED: Use get_cases tool to see what type_id values are used in existing cases in your target section.
priority_idNoPriority ID (1=Low, 2=Medium, 3=High, 4=Critical). RECOMMENDED: Use get_cases tool to see what priority_id values are used in existing cases.
refsNoReferences (e.g., requirement IDs, JIRA tickets, user story numbers). Can be comma-separated for multiple references.
customNoCustom fields (key-value pairs). REQUIRED: Use get_case_fields tool first to discover available custom fields and their valid values. Common fields include: custom_automation_type (1=None, 2=Playwright, 3=ChatGPT, 4=Non-Automated, 5=Partial), custom_environment (1=UAT Only, 2=UAT/Prod, 3=Demo UAT, 4=Live UAT), custom_preconds (preconditions text), custom_steps (test steps text), custom_expected (expected results text). Some custom fields are required by the project configuration.

Implementation Reference

  • Inline handler function for the 'add_case' MCP tool. Validates inputs via Zod schema, constructs CaseCreatePayload, calls addCase service, formats success/error responses.
    server.registerTool( 'add_case', { title: 'Add TestRail Case', description: 'Create a new TestRail test case in a specific section. IMPORTANT: Before creating a case, gather required information using get_projects, get_suites, get_sections, and get_case_fields tools to ensure proper section_id, type_id, and custom field values. Or ask the user to provide the information if not provided.', inputSchema: { title: z.string().min(1).describe('Test case title - should be descriptive and unique within the section'), section_id: z.number().int().positive().describe('Section ID where the case will be created. REQUIRED: Use get_sections tool first to find valid section IDs for your project/suite. Different projects have different section structures.'), type_id: z.number().int().positive().optional().describe('Test case type ID (e.g., 1=Acceptance, 2=Accessibility, 3=Automated, 4=Compatibility, 5=Destructive, 6=Functional, 7=Other, 8=Performance, 9=Regression, 10=Security, 11=Smoke & Sanity, 12=Usability). RECOMMENDED: Use get_cases tool to see what type_id values are used in existing cases in your target section.'), priority_id: z.number().int().positive().optional().describe('Priority ID (1=Low, 2=Medium, 3=High, 4=Critical). RECOMMENDED: Use get_cases tool to see what priority_id values are used in existing cases.'), refs: z.string().nullable().optional().describe('References (e.g., requirement IDs, JIRA tickets, user story numbers). Can be comma-separated for multiple references.'), custom: z.record(z.string(), z.unknown()).optional().describe('Custom fields (key-value pairs). REQUIRED: Use get_case_fields tool first to discover available custom fields and their valid values. Common fields include: custom_automation_type (1=None, 2=Playwright, 3=ChatGPT, 4=Non-Automated, 5=Partial), custom_environment (1=UAT Only, 2=UAT/Prod, 3=Demo UAT, 4=Live UAT), custom_preconds (preconditions text), custom_steps (test steps text), custom_expected (expected results text). Some custom fields are required by the project configuration.'), }, }, async ({ title, section_id, type_id, priority_id, refs, custom }) => { logger.debug(`Add case tool called with section_id: ${section_id}, title: ${title}`); try { const payload: CaseCreatePayload = { title, section_id, type_id, priority_id, refs, custom, }; const result = await addCase(payload); logger.debug(`Add case tool completed successfully. Case ID: ${result.id}`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (err) { logger.error({ err }, `Add case tool failed for section_id: ${section_id}`); const e = err as { type?: string; status?: number; message?: string }; let message = 'Unexpected error'; if (e?.type === 'auth') message = 'Authentication failed: check TESTRAIL_USER/API_KEY'; else if (e?.type === 'not_found') message = `Section ${section_id} not found. Use get_sections tool to find valid section IDs for your project.`; else if (e?.type === 'validation_error') message = `Validation error: ${e.message}. Check custom field values using get_case_fields tool and ensure required fields are provided.`; else if (e?.type === 'permission_denied') message = `Permission denied for section ${section_id}. Try a different project or section using get_projects and get_sections tools.`; else if (e?.type === 'rate_limited') message = 'Rate limited by TestRail; try again later'; else if (e?.type === 'server') message = 'TestRail server error'; else if (e?.type === 'network') message = 'Network error contacting TestRail'; else if (e?.message) message = e.message; return { content: [ { type: 'text', text: message }, ], isError: true, }; } }, );
  • Zod input schema for 'add_case' tool defining required/optional parameters with descriptions and validation rules.
    inputSchema: { title: z.string().min(1).describe('Test case title - should be descriptive and unique within the section'), section_id: z.number().int().positive().describe('Section ID where the case will be created. REQUIRED: Use get_sections tool first to find valid section IDs for your project/suite. Different projects have different section structures.'), type_id: z.number().int().positive().optional().describe('Test case type ID (e.g., 1=Acceptance, 2=Accessibility, 3=Automated, 4=Compatibility, 5=Destructive, 6=Functional, 7=Other, 8=Performance, 9=Regression, 10=Security, 11=Smoke & Sanity, 12=Usability). RECOMMENDED: Use get_cases tool to see what type_id values are used in existing cases in your target section.'), priority_id: z.number().int().positive().optional().describe('Priority ID (1=Low, 2=Medium, 3=High, 4=Critical). RECOMMENDED: Use get_cases tool to see what priority_id values are used in existing cases.'), refs: z.string().nullable().optional().describe('References (e.g., requirement IDs, JIRA tickets, user story numbers). Can be comma-separated for multiple references.'), custom: z.record(z.string(), z.unknown()).optional().describe('Custom fields (key-value pairs). REQUIRED: Use get_case_fields tool first to discover available custom fields and their valid values. Common fields include: custom_automation_type (1=None, 2=Playwright, 3=ChatGPT, 4=Non-Automated, 5=Partial), custom_environment (1=UAT Only, 2=UAT/Prod, 3=Demo UAT, 4=Live UAT), custom_preconds (preconditions text), custom_steps (test steps text), custom_expected (expected results text). Some custom fields are required by the project configuration.'), },
  • Service layer function addCase that transforms high-level payload to TestRailCaseCreateDto (adds custom_ prefix), calls TestRail client, normalizes response to CaseSummary.
    export async function addCase(payload: CaseCreatePayload): Promise<CaseSummary> { // Transform the payload to match TestRail API format const createPayload: TestRailCaseCreateDto = { title: payload.title, section_id: payload.section_id, type_id: payload.type_id, priority_id: payload.priority_id, refs: payload.refs, }; // Add custom fields with proper naming convention if (payload.custom) { for (const [key, value] of Object.entries(payload.custom)) { // Ensure custom field keys have the 'custom_' prefix const fieldKey = key.startsWith('custom_') ? key : `custom_${key}`; createPayload[fieldKey] = value; } } const data: TestRailCaseDto = await testRailClient.addCase(payload.section_id, createPayload); // Normalize the response using the same logic as getCase const { id, title, section_id, type_id, priority_id, refs, created_on, updated_on, ...rest } = data; const custom: Record<string, unknown> = {}; for (const [key, value] of Object.entries(rest)) { if (key.startsWith('custom_')) custom[key] = value; } return { id, title, section_id, type_id, priority_id, refs: refs ?? null, created_on, updated_on, custom: Object.keys(custom).length ? custom : undefined, }; }
  • TypeScript interface CaseCreatePayload defining the structure expected by the addCase service function.
    export interface CaseCreatePayload { title: string; section_id: number; type_id?: number; priority_id?: number; refs?: string | null; custom?: Record<string, unknown>; }
  • HTTP client method that performs POST request to TestRail API endpoint /add_case/{sectionId} to create the case.
    async addCase(sectionId: number, caseData: TestRailCaseCreateDto): Promise<TestRailCaseDto> { try { const res = await this.http.post(`/add_case/${sectionId}`, caseData); if (res.status >= 200 && res.status < 300) { logger.info({ message: 'Successfully created test case', sectionId, caseId: res.data.id, responseSize: JSON.stringify(res.data).length, }); return res.data as TestRailCaseDto; } throw Object.assign(new Error(`HTTP ${res.status}`), { response: res }); } catch (err) { const normalized = this.normalizeError(err); const safeDetails = this.getSafeErrorDetails(err); logger.error({ err: normalized, details: safeDetails, sectionId }, 'TestRail addCase failed'); throw normalized; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Derrbal/testrail-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server