Skip to main content
Glama
Jameswlepage

WordPress Trac MCP Server

by Jameswlepage

getChangeset

Retrieve details of a WordPress code changeset or commit, including commit message, author, and diff. Specify a revision number to access specific changes in the WordPress development history.

Instructions

Get information about a specific WordPress code changeset/commit including commit message, author, and diff.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
diffLimitNoMaximum characters of diff to return (default: 2000, max: 10000)
includeDiffNoInclude diff content (default: true)
revisionYesSVN revision number (e.g., 58504)

Implementation Reference

  • Main handler for the 'getChangeset' tool. Fetches the changeset page from WordPress Trac, parses HTML to extract author, date, commit message, changed files, and optionally the diff (truncated if large). Returns structured result with metadata.
    case "getChangeset": { const { revision, includeDiff = true, diffLimit = 2000 } = args; try { const changesetUrl = `https://core.trac.wordpress.org/changeset/${revision}`; // Fetch changeset page const response = await fetch(changesetUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } }); if (!response.ok) { throw new Error(`Changeset ${revision} not found`); } const html = await response.text(); // Parse changeset information from HTML with improved patterns const messageMatch = html.match(/<dd class="message[^"]*"[^>]*>\s*<p[^>]*>(.*?)<\/p>/s) || html.match(/<dd class="message[^"]*"[^>]*>(.*?)<\/dd>/s) || html.match(/<div class="message"[^>]*>\s*<p[^>]*>(.*?)<\/p>/s) || html.match(/<div class="message"[^>]*>(.*?)<\/div>/s); const authorMatch = html.match(/<dd class="author"[^>]*><span class="trac-author"[^>]*>(.*?)<\/span><\/dd>/s) || html.match(/<dt class="property author">Author:<\/dt>\s*<dd class="author">(.*?)<\/dd>/s) || html.match(/<dt>Author:<\/dt>\s*<dd>(.*?)<\/dd>/s); const dateMatch = html.match(/<dd class="date"[^>]*>(.*?)<\/dd>/s) || html.match(/<dt class="property date">Date:<\/dt>\s*<dd class="date">(.*?)<\/dd>/s) || html.match(/<dt>Date:<\/dt>\s*<dd>(.*?)<\/dd>/s); const changeset = { revision, author: authorMatch?.[1] ? authorMatch[1].replace(/<[^>]*>/g, '').trim() : '', date: dateMatch?.[1] ? dateMatch[1].replace(/<[^>]*>/g, '').trim() : '', message: messageMatch?.[1] ? messageMatch[1].replace(/<[^>]*>/g, '').trim() : '', files: [] as string[], diff: '', }; // Extract file list with improved patterns const fileMatches = html.match(/<h2[^>]*>Files:<\/h2>([\s\S]*?)<\/div>/) || html.match(/<div class="files"[^>]*>([\s\S]*?)<\/div>/) || html.match(/<div[^>]*class="[^"]*files[^"]*"[^>]*>([\s\S]*?)<\/div>/); if (fileMatches?.[1]) { const fileListHtml = fileMatches[1]; const filePathMatches = fileListHtml.match(/<a[^>]*href="[^"]*\/browser\/[^"]*"[^>]*>(.*?)<\/a>/g) || fileListHtml.match(/<a[^>]*href="[^"]*"[^>]*>(.*?)<\/a>/g) || fileListHtml.match(/<li[^>]*>(.*?)<\/li>/g); if (filePathMatches) { changeset.files = filePathMatches .map(match => match.replace(/<[^>]*>/g, '').trim()) .filter(path => path && !path.includes('(') && !path.includes('modified') && !path.includes('added') && !path.includes('deleted')) .slice(0, 20); // Limit to first 20 files } } // Get diff if requested if (includeDiff) { try { const diffUrl = `${changesetUrl}?format=diff`; const diffResponse = await fetch(diffUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } }); if (diffResponse.ok) { let diffText = await diffResponse.text(); const maxDiffLength = Math.min(diffLimit, 10000); if (diffText.length > maxDiffLength) { diffText = diffText.substring(0, maxDiffLength) + '\n... [diff truncated] ...'; } changeset.diff = diffText; } } catch (error) { console.warn('Failed to load diff:', error); } } result = { id: revision.toString(), title: `r${revision}: ${changeset.message}`, text: `Changeset r${revision}\nAuthor: ${changeset.author}\nDate: ${changeset.date}\n\nMessage:\n${changeset.message}\n\nFiles changed: ${changeset.files.length}\n${changeset.files.slice(0, 10).join('\n')}${changeset.files.length > 10 ? '\n...' : ''}\n\n${changeset.diff ? `Diff:\n${changeset.diff}` : 'No diff available'}`, url: changesetUrl, metadata: { changeset, totalFiles: changeset.files.length, }, }; } catch (error) { result = { id: revision.toString(), title: `Error loading changeset ${revision}`, text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, url: `https://core.trac.wordpress.org/changeset/${revision}`, metadata: { error: true }, }; } break;
  • Input schema for the getChangeset tool defining parameters: revision (required number), includeDiff (boolean, default true), diffLimit (number, default 2000).
    inputSchema: { type: "object", properties: { revision: { type: "number", description: "SVN revision number (e.g., 58504)", }, includeDiff: { type: "boolean", description: "Include diff content (default: true)", default: true, }, diffLimit: { type: "number", description: "Maximum characters of diff to return (default: 2000, max: 10000)", default: 2000, }, }, required: ["revision"], },
  • src/index.ts:96-119 (registration)
    Registration of the getChangeset tool in the tools/list endpoint response, including name, description, and input schema.
    { name: "getChangeset", description: "Get information about a specific WordPress code changeset/commit including commit message, author, and diff.", inputSchema: { type: "object", properties: { revision: { type: "number", description: "SVN revision number (e.g., 58504)", }, includeDiff: { type: "boolean", description: "Include diff content (default: true)", default: true, }, diffLimit: { type: "number", description: "Maximum characters of diff to return (default: 2000, max: 10000)", default: 2000, }, }, required: ["revision"], }, },
  • Helper function getChangesetForChatGPT that implements similar changeset fetching and parsing logic tailored for ChatGPT's search/fetch tools, including caching.
    async function getChangesetForChatGPT(revision: number, includeDiff: boolean) { try { const changesetUrl = `https://core.trac.wordpress.org/changeset/${revision}`; const response = await fetch(changesetUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } }); if (!response.ok) { throw new Error(`Changeset ${revision} not found`); } const html = await response.text(); const messageMatch = html.match(/<dd class="message[^"]*"[^>]*>\s*<p[^>]*>(.*?)<\/p>/s) || html.match(/<dd class="message[^"]*"[^>]*>(.*?)<\/dd>/s); const authorMatch = html.match(/<dd class="author"[^>]*><span class="trac-author"[^>]*>(.*?)<\/span><\/dd>/s) || html.match(/<dt class="property author">Author:<\/dt>\s*<dd class="author">(.*?)<\/dd>/s); const dateMatch = html.match(/<dd class="date"[^>]*>(.*?)<\/dd>/s) || html.match(/<dt class="property date">Date:<\/dt>\s*<dd class="date">(.*?)<\/dd>/s); const changeset = { revision, author: authorMatch?.[1] ? authorMatch[1].replace(/<[^>]*>/g, '').trim() : '', date: dateMatch?.[1] ? dateMatch[1].replace(/<[^>]*>/g, '').trim() : '', message: messageMatch?.[1] ? messageMatch[1].replace(/<[^>]*>/g, '').trim() : '', diff: '', }; // Get diff if requested if (includeDiff) { try { const diffUrl = `${changesetUrl}?format=diff`; const diffResponse = await fetch(diffUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } }); if (diffResponse.ok) { let diffText = await diffResponse.text(); const maxDiffLength = 2000; if (diffText.length > maxDiffLength) { diffText = diffText.substring(0, maxDiffLength) + '\n... [diff truncated] ...'; } changeset.diff = diffText; } } catch (error) { console.warn('Failed to load diff:', error); } } // Cache the changeset chatgptCache.set(`r${revision}`, changeset); const diffText = changeset.diff ? `\n\nDiff:\n${changeset.diff}` : ''; return { id: `r${revision}`, title: `r${revision}: ${changeset.message}`, text: `Changeset r${revision}\nAuthor: ${changeset.author}\nDate: ${changeset.date}\n\nMessage:\n${changeset.message}${diffText}`, url: changesetUrl, metadata: { changeset }, }; } catch (error) { return { id: `r${revision}`, title: `Error loading changeset ${revision}`, text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`, url: `https://core.trac.wordpress.org/changeset/${revision}`, metadata: { error: true }, }; } }

Other Tools

Related Tools

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/Jameswlepage/trac-mcp'

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