get_project_context
Retrieve essential project metadata to resolve human-readable names to numeric IDs and understand project structure before using other TestCollab tools.
Instructions
Get project context including project name, description, application type, suite tree, tags, test_case_custom_fields, test_plan_custom_fields, requirements, test plan folders, releases, and project users. Returns the metadata needed to resolve human-readable names (e.g. suite titles, tag names, folder titles, release titles, user names) to numeric IDs used by other tools. Also returns the project description and app_type (web_app, mobile_app, api, desktop_app, other) which should inform the style of test steps you generate.
IMPORTANT: Call this tool at the start of every conversation before using any other TestCollab tool. This avoids errors from unresolved suite names, tag names, or custom field references.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_id | No | Project ID (optional — uses default project if omitted) |
Implementation Reference
- src/resources/project-context.ts:498-764 (handler)The handler function `handleProjectContext` in `src/resources/project-context.ts` implements the core logic for the "get_project_context" tool. It fetches project metadata (suites, tags, custom fields, etc.) and returns them as a JSON response.
export async function handleProjectContext( projectId: number ): Promise<{ contents: Array<{ uri: string; mimeType: string; text: string }> }> { const now = Date.now(); const cacheKey = cacheTtlMs > 0 ? getCacheKey(projectId) : undefined; if (cacheKey) { const cached = contextCache.get(cacheKey); if (cached && cached.expiresAt > now) { if (!hasEntityScopedCustomFields(cached.payload)) { console.log( `${logPrefix} Project context cache invalidated for project ${projectId} due to legacy payload shape` ); contextCache.delete(cacheKey); } else { console.log( `${logPrefix} Project context cache hit for project ${projectId}` ); return { contents: [ { uri: `testcollab://project/${projectId}/context`, mimeType: "application/json", text: JSON.stringify(cached.payload, null, 2), }, ], }; } } } const startTime = Date.now(); console.log(`${logPrefix} Building project context for ${projectId}`); try { const client = getApiClient(); let companyId: number | undefined; let projectName: string | undefined; let projectDescription: string | undefined; let appType: string | undefined; let appTypeOther: string | undefined; try { console.log( `${apiLogPrefix} GET /projects/{id} params: ${JSON.stringify({ projectId, })}` ); const project = await client.getProject(projectId); companyId = getCompanyIdFromProject(project); projectName = normalizeString(getField<string>(project, "name")); projectDescription = normalizeString(getField<string>(project, "description")); appType = normalizeString(getField<string>(project, "app_type")); appTypeOther = normalizeString(getField<string>(project, "app_type_other")); } catch (error) { console.warn( `${logPrefix} Failed to fetch project ${projectId} for company ID`, error ); } console.log( `${apiLogPrefix} GET /suites params: ${JSON.stringify({ projectId, })}` ); console.log( `${apiLogPrefix} GET /tags params: ${JSON.stringify({ projectId, // companyId, })}` ); console.log( `${apiLogPrefix} GET /requirements params: ${JSON.stringify({ projectId, companyId, })}` ); console.log( `${apiLogPrefix} GET /customfields params: ${JSON.stringify({ projectId, companyId, entity: "TestCase", })}` ); console.log( `${apiLogPrefix} GET /customfields params: ${JSON.stringify({ projectId, companyId, entity: "TestPlan", })}` ); console.log( `${apiLogPrefix} GET /testplanfolders params: ${JSON.stringify({ projectId, })}` ); console.log( `${apiLogPrefix} GET /releases params: ${JSON.stringify({ projectId, })}` ); console.log( `${apiLogPrefix} GET /projectusers params: ${JSON.stringify({ projectId, })}` ); const [ suitesList, tagsList, requirementsList, testCaseCustomFieldsList, testPlanCustomFieldsList, testPlanFoldersList, releasesList, projectUsersList, ] = await Promise.all([ client.listSuites(projectId).catch((error) => { console.warn( `${logPrefix} Failed to fetch suites for ${projectId}`, error ); return []; }), client.listTags(projectId).catch((error) => { console.warn( `${logPrefix} Failed to fetch tags for ${projectId}`, error ); return []; }), client.listRequirements(projectId).catch((error) => { console.warn( `${logPrefix} Failed to fetch requirements for ${projectId}`, error ); return []; }), companyId ? client .listProjectCustomFields(projectId, companyId, "TestCase") .catch((error) => { console.warn( `${logPrefix} Failed to fetch TestCase custom fields for ${projectId}`, error ); return []; }) : Promise.resolve([]), companyId ? client .listProjectCustomFields(projectId, companyId, "TestPlan") .catch((error) => { console.warn( `${logPrefix} Failed to fetch TestPlan custom fields for ${projectId}`, error ); return []; }) : Promise.resolve([]), client.listTestPlanFolders(projectId).catch((error) => { console.warn( `${logPrefix} Failed to fetch test plan folders for ${projectId}`, error ); return []; }), client.listReleases(projectId).catch((error) => { console.warn(`${logPrefix} Failed to fetch releases for ${projectId}`, error); return []; }), client.listProjectUsers(projectId).catch((error) => { console.warn( `${logPrefix} Failed to fetch project users for ${projectId}`, error ); return []; }), ]); const suites = buildSuiteTree(Array.isArray(suitesList) ? suitesList : []); const tags = mapTags(Array.isArray(tagsList) ? tagsList : []); const requirements = mapRequirements( Array.isArray(requirementsList) ? requirementsList : [] ); const test_case_custom_fields = mapCustomFields( Array.isArray(testCaseCustomFieldsList) ? testCaseCustomFieldsList : [], "TestCase" ); const test_plan_custom_fields = mapCustomFields( Array.isArray(testPlanCustomFieldsList) ? testPlanCustomFieldsList : [], "TestPlan" ); // Backward-compatibility alias retained for existing consumers. const custom_fields = test_case_custom_fields; const test_plan_folders = mapTestPlanFolders( Array.isArray(testPlanFoldersList) ? testPlanFoldersList : [] ); const releases = mapReleases(Array.isArray(releasesList) ? releasesList : []); const users = mapProjectUsers( Array.isArray(projectUsersList) ? projectUsersList : [] ); const payload: ProjectContextPayload = { project_id: projectId, ...(projectName ? { project_name: projectName } : {}), ...(projectDescription ? { project_description: projectDescription } : {}), ...(appType ? { app_type: appType } : {}), ...(appType === "other" && appTypeOther ? { app_type_other: appTypeOther } : {}), suites, tags, test_case_custom_fields, test_plan_custom_fields, custom_fields, requirements, test_plan_folders, releases, users, }; if (cacheKey) { contextCache.set(cacheKey, { expiresAt: now + cacheTtlMs, payload, }); } const durationMs = Date.now() - startTime; console.log( `${logPrefix} Project context ready for ${projectId} in ${durationMs}ms (suites: ${suites.length}, tags: ${tags.length}, test_case_custom_fields: ${test_case_custom_fields.length}, test_plan_custom_fields: ${test_plan_custom_fields.length}, requirements: ${requirements.length}, test_plan_folders: ${test_plan_folders.length}, releases: ${releases.length}, users: ${users.length})` ); return { contents: [ { uri: `testcollab://project/${projectId}/context`, mimeType: "application/json", text: JSON.stringify(payload, null, 2), }, ], }; } catch (error) { console.error( `${logPrefix} Failed to build project context for ${projectId}:`, error ); return { contents: [ { uri: `testcollab://project/${projectId}/context`, mimeType: "application/json", text: JSON.stringify( { error: "PROJECT_CONTEXT_FETCH_FAILED", message: error instanceof Error ? error.message : "Unknown error", }, null, 2 ), }, ], }; } } - src/tools/index.ts:146-182 (registration)The registration for the "get_project_context" tool occurs in `src/tools/index.ts`. It invokes `handleProjectContext` defined in `src/resources/project-context.ts`.
server.tool( "get_project_context", `Get project context including project name, description, application type, suite tree, tags, test_case_custom_fields, test_plan_custom_fields, requirements, test plan folders, releases, and project users. Returns the metadata needed to resolve human-readable names (e.g. suite titles, tag names, folder titles, release titles, user names) to numeric IDs used by other tools. Also returns the project description and app_type (web_app, mobile_app, api, desktop_app, other) which should inform the style of test steps you generate. IMPORTANT: Call this tool at the start of every conversation before using any other TestCollab tool. This avoids errors from unresolved suite names, tag names, or custom field references.`, { project_id: z.number().optional().describe("Project ID (optional — uses default project if omitted)"), }, async (args) => { const projectId = resolveProjectId(args.project_id); if (!projectId) { return { content: [ { type: "text" as const, text: JSON.stringify({ error: "No project_id provided and no default project configured." }), }, ], }; } const result = await handleProjectContext(projectId); const text = result.contents[0]?.text ?? JSON.stringify({ error: "No context returned" }); return { content: [ { type: "text" as const, text, }, ], }; } );