add_attachment_to_run
Add a file or directory (auto-zipped) as an attachment to a TestRail test run. Maximum upload size is 256MB.
Instructions
Add an attachment to a test run in TestRail. If the file_path points to a directory, it will be automatically zipped before uploading. Maximum upload size is 256MB.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| run_id | Yes | The ID of the test run to attach the file to | |
| file_path | Yes | The path to the file or directory to attach. Directories will be automatically zipped. |
Implementation Reference
- src/tools/add_attachment_to_run.ts:15-62 (handler)The main tool definition for 'add_attachment_to_run'. Contains the handler function that validates file existence, auto-zips directories using archiver, calls the client method, and cleans up temporary zip files.
export const addAttachmentToRunTool: ToolDefinition<typeof parameters, TestRailClient> = { name: "add_attachment_to_run", description: "Add an attachment to a test run in TestRail. If the file_path points to a directory, it will be automatically zipped before uploading. Maximum upload size is 256MB.", parameters, handler: async ({ run_id, file_path }, client: TestRailClient) => { if (!fs.existsSync(file_path)) { throw new Error(`File or directory not found: ${file_path}`); } const stats = fs.statSync(file_path); let uploadPath: string = file_path; let filename: string = path.basename(file_path); let isTemporary = false; if (stats.isDirectory()) { const basename = path.basename(file_path); const tempDir = os.tmpdir(); const zipPath = path.join(tempDir, `${basename}-${Date.now()}.zip`); await new Promise<void>((resolve, reject) => { const output = fs.createWriteStream(zipPath); const archive = archiver('zip', { zlib: { level: 9 } }); output.on('close', () => resolve()); archive.on('error', (err) => reject(err)); archive.pipe(output); archive.directory(file_path, basename); archive.finalize(); }); uploadPath = zipPath; filename = `${basename}.zip`; isTemporary = true; } try { const result = await client.addAttachmentToRun(run_id, uploadPath, filename); return AttachmentSchema.parse(result); } finally { if (isTemporary && fs.existsSync(uploadPath)) { fs.unlinkSync(uploadPath); } } }, }; - Input schema for the tool: run_id (number) and file_path (string). Validated with Zod.
const parameters = { run_id: z.number().describe("The ID of the test run to attach the file to"), file_path: z.string().describe("The path to the file or directory to attach. Directories will be automatically zipped."), } - src/client/testrail.ts:191-202 (helper)Client method addAttachmentToRun that reads the file, creates a FormData blob, and sends a POST request to the TestRail API endpoint.
async addAttachmentToRun(runId: number, filePath: string, filename: string): Promise<Attachment> { const fileBuffer = await fs.promises.readFile(filePath); const blob = new Blob([fileBuffer]); const formData = new FormData(); formData.append('attachment', blob, filename); const headers: HeadersInit = { 'Authorization': this.auth, }; return this._executeRequest<Attachment>('POST', `${API_BASE_V2}/add_attachment_to_run/${runId}`, headers, formData); } - src/index.ts:21-21 (registration)Import of the addAttachmentToRunTool from its source file.
import { addAttachmentToRunTool } from "./tools/add_attachment_to_run.js"; - src/index.ts:74-74 (registration)Registration of addAttachmentToRunTool in the tools array that gets registered with the MCP server.
addAttachmentToRunTool,