Skip to main content
Glama
Derrbal
by Derrbal

get_sections

Retrieve test sections for a specific project and suite with pagination controls to organize and access TestRail test management data efficiently.

Instructions

Get a list of sections for a project and test suite with optional pagination.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_idYesTestRail project ID
suite_idNoTestRail suite ID (optional if project is in single suite mode)
limitNoThe number of sections to return (max 250, default 250)
offsetNoWhere to start counting the sections from (pagination offset)

Implementation Reference

  • The main MCP tool handler function for 'get_sections'. It processes input parameters, constructs filters, calls the service layer getSections, formats the response as JSON text content, and handles errors with specific messages.
    async ({ project_id, suite_id, limit, offset }) => { logger.debug(`Get sections tool called with project_id: ${project_id}, suite_id: ${suite_id}`); try { const filters = { project_id, ...(suite_id !== undefined && { suite_id }), ...(limit !== undefined && { limit }), ...(offset !== undefined && { offset }), }; const result = await getSections(filters); logger.debug(`Get sections tool completed successfully for project_id: ${project_id}. Found ${result.sections.length} sections (total: ${result.size})`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (err) { logger.error({ err }, `Get sections tool failed for project_id: ${project_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 = `Project ${project_id} or suite ${suite_id} not found`; 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 validation for the get_sections tool parameters: project_id (required), suite_id/limit/offset (optional).
    inputSchema: { project_id: z.number().int().positive().describe('TestRail project ID'), suite_id: z.number().int().positive().optional().describe('TestRail suite ID (optional if project is in single suite mode)'), limit: z.number().int().positive().optional().describe('The number of sections to return (max 250, default 250)'), offset: z.number().int().min(0).optional().describe('Where to start counting the sections from (pagination offset)'), },
  • src/server.ts:515-566 (registration)
    MCP server registration of the 'get_sections' tool, including title, description, input schema, and handler function reference.
    server.registerTool( 'get_sections', { title: 'Get TestRail Sections', description: 'Get a list of sections for a project and test suite with optional pagination.', inputSchema: { project_id: z.number().int().positive().describe('TestRail project ID'), suite_id: z.number().int().positive().optional().describe('TestRail suite ID (optional if project is in single suite mode)'), limit: z.number().int().positive().optional().describe('The number of sections to return (max 250, default 250)'), offset: z.number().int().min(0).optional().describe('Where to start counting the sections from (pagination offset)'), }, }, async ({ project_id, suite_id, limit, offset }) => { logger.debug(`Get sections tool called with project_id: ${project_id}, suite_id: ${suite_id}`); try { const filters = { project_id, ...(suite_id !== undefined && { suite_id }), ...(limit !== undefined && { limit }), ...(offset !== undefined && { offset }), }; const result = await getSections(filters); logger.debug(`Get sections tool completed successfully for project_id: ${project_id}. Found ${result.sections.length} sections (total: ${result.size})`); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (err) { logger.error({ err }, `Get sections tool failed for project_id: ${project_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 = `Project ${project_id} or suite ${suite_id} not found`; 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, }; } }, );
  • Service layer adapter for get_sections: maps input filters to client params, calls TestRail client, normalizes response by extracting custom_ fields into a custom object for each section.
    export async function getSections(filters: GetSectionsFilters): Promise<SectionsResponse> { // Transform service filters to client parameters const clientParams: GetSectionsParams = { project_id: filters.project_id, suite_id: filters.suite_id, limit: filters.limit, offset: filters.offset, }; const response: TestRailSectionsResponse = await testRailClient.getSections(clientParams); // Transform each section using the same pattern as other entities const transformedSections: SectionSummary[] = response.sections.map((sectionData) => { const { depth, display_order, id, name, parent_id, suite_id, ...rest } = sectionData; const custom: Record<string, unknown> = {}; for (const [key, value] of Object.entries(rest)) { if (key.startsWith('custom_')) custom[key] = value; } return { depth, display_order, id, name, parent_id, suite_id, custom: Object.keys(custom).length ? custom : undefined, }; }); return { offset: response.offset, limit: response.limit, size: response.size, _links: response._links, sections: transformedSections, }; }
  • Low-level TestRailClient getSections method: constructs API URL with query params for /get_sections/{project_id}, performs HTTP GET, validates paginated response format, handles retries and errors.
    async getSections(params: GetSectionsParams): Promise<TestRailSectionsResponse> { try { // Build query parameters const queryParams = new URLSearchParams(); // Handle suite_id parameter if (params.suite_id !== undefined) { queryParams.append('suite_id', params.suite_id.toString()); } // Handle pagination parameters if (params.limit !== undefined) { queryParams.append('limit', params.limit.toString()); } if (params.offset !== undefined) { queryParams.append('offset', params.offset.toString()); } const queryString = queryParams.toString(); const url = `/get_sections/${params.project_id}${queryString ? `&${queryString}` : ''}`; const res = await this.http.get(url); logger.info({ status: res.status, dataType: typeof res.data, hasSectionsProperty: res.data && typeof res.data === 'object' && 'sections' in res.data, projectId: params.project_id, suiteId: params.suite_id, queryParams: Object.fromEntries(queryParams) }, 'TestRail getSections response info'); if (res.status >= 200 && res.status < 300) { // TestRail get_sections always returns paginated format if (res.data && typeof res.data === 'object' && 'sections' in res.data) { const paginatedResponse = res.data as TestRailSectionsResponse; if (!Array.isArray(paginatedResponse.sections)) { throw Object.assign(new Error('API returned response with non-array sections field'), { response: { status: 200 } // Make it look like a server error }); } logger.info({ totalSections: paginatedResponse.size, returnedSections: paginatedResponse.sections.length, offset: paginatedResponse.offset, limit: paginatedResponse.limit, hasNext: paginatedResponse._links?.next !== null, hasPrev: paginatedResponse._links?.prev !== null }, 'TestRail getSections paginated response'); return paginatedResponse; } else { logger.error({ status: res.status, responseData: res.data, dataType: typeof res.data }, 'TestRail getSections returned unexpected response format'); throw Object.assign(new Error('API returned unexpected response format'), { response: { status: 200 } // Make it look like a server error }); } } 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, params }, 'TestRail getSections 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