getTicket
Retrieve detailed information about a WordPress Trac ticket, including description, comments, and metadata, to track development progress and discussions effectively.
Instructions
Get detailed information about a specific WordPress Trac ticket including description, comments, and metadata.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| commentLimit | No | Maximum number of comments to return (default: 10, max: 50) | |
| id | Yes | Trac ticket ID number | |
| includeComments | No | Include ticket comments and discussion (default: true) |
Implementation Reference
- src/index.ts:72-95 (registration)Registration of the 'getTicket' tool in the tools/list response, including its input schema definition.{ name: "getTicket", description: "Get detailed information about a specific WordPress Trac ticket including description, comments, and metadata.", inputSchema: { type: "object", properties: { id: { type: "number", description: "Trac ticket ID number", }, includeComments: { type: "boolean", description: "Include ticket comments and discussion (default: true)", default: true, }, commentLimit: { type: "number", description: "Maximum number of comments to return (default: 10, max: 50)", default: 10, }, }, required: ["id"], }, },
- src/index.ts:379-518 (handler)The execution handler for the 'getTicket' tool. It queries the WordPress Trac query endpoint with CSV format filtered by ticket ID, parses the CSV response, extracts ticket metadata, constructs a formatted response, and handles errors.case "getTicket": { const { id, includeComments = true } = args; try { // Use search approach since CSV parsing is problematic const searchUrl = new URL('https://core.trac.wordpress.org/query'); searchUrl.searchParams.set('format', 'csv'); searchUrl.searchParams.set('id', id.toString()); searchUrl.searchParams.set('max', '1'); const response = await fetch(searchUrl.toString(), { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; WordPress-Trac-MCP-Server/1.0)', 'Accept': 'text/csv,text/plain,*/*', } }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const csvData = await response.text(); // Parse CSV data similar to searchTickets const lines = csvData.replace(/^\uFEFF/, '').trim().split(/\r?\n/); if (lines.length < 2) { throw new Error(`Ticket ${id} not found`); } // Parse each line like in searchTickets for (let i = 1; i < lines.length; i++) { const line = lines[i]?.trim(); if (!line) continue; // Better CSV parsing - handle quoted fields properly const values = []; let currentField = ''; let inQuotes = false; let escapeNext = false; for (let j = 0; j < line.length; j++) { const char = line[j]; if (escapeNext) { currentField += char; escapeNext = false; continue; } if (char === '\\') { escapeNext = true; continue; } if (char === '"') { if (inQuotes) { // Check if this is an escaped quote if (j + 1 < line.length && line[j + 1] === '"') { currentField += '"'; j++; // Skip the next quote } else { inQuotes = false; } } else { inQuotes = true; } } else if (char === ',' && !inQuotes) { values.push(currentField.trim()); currentField = ''; } else { currentField += char; } } values.push(currentField.trim()); if (values.length >= 2 && values[0] && !isNaN(parseInt(values[0]))) { const ticketId = parseInt(values[0]); if (ticketId === id) { // Map fields based on actual headers from search query // Headers: id,Summary,Owner,Type,Status,Priority,Milestone const ticket = { id: parseInt(values[0]), summary: values[1] || '', owner: values[2] || '', type: values[3] || '', status: values[4] || '', priority: values[5] || '', milestone: values[6] || '', reporter: '', // Not available in search query description: 'Full description not available in search query. Visit the ticket URL for complete details.', component: '', // Not available in search query version: '', severity: '', resolution: '', keywords: '', cc: '', focuses: '', }; // Note: Comments are not available through the CSV API let comments: any[] = []; if (includeComments) { comments = [{ author: 'system', timestamp: new Date().toISOString(), comment: 'Comment history not available through CSV API. Visit the ticket URL for full discussion.', }]; } result = { id: id, title: `#${id}: ${ticket.summary}`, text: `Ticket #${id}: ${ticket.summary}\n\nStatus: ${ticket.status}\nComponent: ${ticket.component}\nPriority: ${ticket.priority}\nType: ${ticket.type}\nReporter: ${ticket.reporter}\nOwner: ${ticket.owner}\nMilestone: ${ticket.milestone}\nVersion: ${ticket.version}\nKeywords: ${ticket.keywords}\n\nDescription:\n${ticket.description}\n\nFor full discussion and comments, visit: https://core.trac.wordpress.org/ticket/${id}`, url: `https://core.trac.wordpress.org/ticket/${id}`, metadata: { ticket, comments, totalComments: comments.length, }, }; break; // Found the ticket, exit the loop } } } // If we didn't find the ticket, result will be undefined if (!result) { throw new Error(`Ticket ${id} not found`); } } catch (error) { result = { id: id, title: `Error loading ticket ${id}`, text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, url: `https://core.trac.wordpress.org/ticket/${id}`, metadata: { error: true }, }; } break;
- src/index.ts:1160-1222 (helper)Helper function getTicketForChatGPT used in the ChatGPT-specific MCP handler to fetch and format ticket data, with caching support.async function getTicketForChatGPT(ticketId: number, includeComments: boolean) { try { const searchUrl = new URL('https://core.trac.wordpress.org/query'); searchUrl.searchParams.set('format', 'csv'); searchUrl.searchParams.set('id', ticketId.toString()); searchUrl.searchParams.set('max', '1'); const response = await fetch(searchUrl.toString(), { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; WordPress-Trac-MCP-Server/1.0)', 'Accept': 'text/csv,text/plain,*/*', } }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const csvData = await response.text(); const lines = csvData.replace(/^\uFEFF/, '').trim().split(/\r?\n/); if (lines.length < 2) { throw new Error(`Ticket ${ticketId} not found`); } const values = parseCSVLine(lines[1] || ''); if (values.length >= 2 && values[0] && parseInt(values[0]) === ticketId) { const ticket = { id: parseInt(values[0]), summary: values[1] || '', owner: values[2] || '', type: values[3] || '', status: values[4] || '', priority: values[5] || '', milestone: values[6] || '', }; // Cache the ticket chatgptCache.set(ticketId.toString(), ticket); const commentNote = includeComments ? "\n\nNote: Full comments and description available on the ticket page." : ""; return { id: ticketId.toString(), title: `#${ticketId}: ${ticket.summary}`, text: `Ticket #${ticketId}: ${ticket.summary}\n\nStatus: ${ticket.status}\nType: ${ticket.type}\nPriority: ${ticket.priority}\nOwner: ${ticket.owner}\nMilestone: ${ticket.milestone}${commentNote}`, url: `https://core.trac.wordpress.org/ticket/${ticketId}`, metadata: { ticket }, }; } else { throw new Error(`Ticket ${ticketId} not found`); } } catch (error) { return { id: ticketId.toString(), title: `Error loading ticket ${ticketId}`, text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, url: `https://core.trac.wordpress.org/ticket/${ticketId}`, metadata: { error: true }, }; } }