From bd545584052c293dead632998963c692f57de499 Mon Sep 17 00:00:00 2001 From: Kendall Gassner Date: Tue, 9 Sep 2025 21:35:57 +0000 Subject: [PATCH 1/5] Add a MCP tool that helps review alt text in context of surrounding text --- packages/mcp/src/server.ts | 45 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts index 07f179c4ece..14e9ac93df3 100644 --- a/packages/mcp/src/server.ts +++ b/packages/mcp/src/server.ts @@ -629,4 +629,49 @@ The following list of coding guidelines must be followed: }, ) +// ----------------------------------------------------------------------------- +// Accessibility +// ----------------------------------------------------------------------------- +server.tool( + 'review_alt_text', + 'Images MUST have meaningful and logical alt text', + { + surroundingText: z.string().describe('Text surrounding the image, relevant to the image.'), + alt: z.string().describe('The alt text of the image being evaluated'), + image: z + .union([ + z.instanceof(File).describe('The image file being evaluated'), + z.string().url().describe('The URL of the image being evaluated'), + ]) + .describe('The image file or URL being evaluated'), + }, + async ({surroundingText, alt, image}) => { + // Call the LLM through MCP sampling + const response = await server.server.createMessage({ + messages: [ + { + role: 'user', + content: { + type: 'text', + text: `Does this alt text: '${alt}' meet accessibility guidelines and describe the ${image} accurately in context of this surrounding text: '${surroundingText}'?\n\n`, + }, + }, + ], + sampling: {temperature: 0.4}, + maxTokens: 500, + }) + + return { + content: [ + { + type: 'text', + text: response.content.type === 'text' ? response.content.text : 'Unable to generate summary', + }, + ], + altTextEvaluation: response.content.text, + nextSteps: `if the evaluation was bad provide more meaninguful alt text.`, + } + }, +) + export {server} From 4ecc67f5382d9fd94b55b7a4321ad26daa2ce818 Mon Sep 17 00:00:00 2001 From: Kendall Gassner Date: Tue, 9 Sep 2025 22:26:51 +0000 Subject: [PATCH 2/5] add changeset --- .changeset/strong-lions-tan.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/strong-lions-tan.md diff --git a/.changeset/strong-lions-tan.md b/.changeset/strong-lions-tan.md new file mode 100644 index 00000000000..16c6a5a8308 --- /dev/null +++ b/.changeset/strong-lions-tan.md @@ -0,0 +1,5 @@ +--- +'@primer/mcp': minor +--- + +Adds review_alt_text tool to the Primer MCP From 101b43cc57b64cea25ca90db0838e53968810f5e Mon Sep 17 00:00:00 2001 From: Kendall Gassner Date: Wed, 10 Sep 2025 16:35:35 +0000 Subject: [PATCH 3/5] add details on how the review_alt_text tool should be used --- packages/mcp/src/server.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts index 14e9ac93df3..1c22a67d7d9 100644 --- a/packages/mcp/src/server.ts +++ b/packages/mcp/src/server.ts @@ -632,6 +632,17 @@ The following list of coding guidelines must be followed: // ----------------------------------------------------------------------------- // Accessibility // ----------------------------------------------------------------------------- + +/** + * The `review_alt_text` tool is experimental and may be removed in future versions. + * + * The intent of this tool is to assist products like Copilot Code Review and Copilot Coding Agent + * in reviewing both user- and AI-generated alt text for images, ensuring compliance with accessibility guidelines. + * This tool is not intended to replace human-generated alt text; rather, it supports the review process + * by providing suggestions for improvement. It should be used alongside human review, not as a substitute. + * + * + **/ server.tool( 'review_alt_text', 'Images MUST have meaningful and logical alt text', From 42fe3f04eab8f657eeb15f0422dd28cde0683ca6 Mon Sep 17 00:00:00 2001 From: Kendall Gassner Date: Wed, 10 Sep 2025 17:01:11 +0000 Subject: [PATCH 4/5] clean up spelling --- packages/mcp/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts index 1c22a67d7d9..3645e965cd3 100644 --- a/packages/mcp/src/server.ts +++ b/packages/mcp/src/server.ts @@ -679,8 +679,8 @@ server.tool( text: response.content.type === 'text' ? response.content.text : 'Unable to generate summary', }, ], - altTextEvaluation: response.content.text, - nextSteps: `if the evaluation was bad provide more meaninguful alt text.`, + altTextEvaluation: response.content.type === 'text' ? response.content.text : 'Unable to generate summary', + nextSteps: `if the evaluation was bad provide more meaningful alt text.`, } }, ) From f98c701d1c608f60a7e6cd4d64f7dbec63a377a9 Mon Sep 17 00:00:00 2001 From: Kendall Gassner Date: Wed, 10 Sep 2025 17:39:43 +0000 Subject: [PATCH 5/5] Update next steps to avoid looping and allow file paths to be passed in as image imput --- packages/mcp/src/server.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/mcp/src/server.ts b/packages/mcp/src/server.ts index 3645e965cd3..e33c5a20e17 100644 --- a/packages/mcp/src/server.ts +++ b/packages/mcp/src/server.ts @@ -645,16 +645,17 @@ The following list of coding guidelines must be followed: **/ server.tool( 'review_alt_text', - 'Images MUST have meaningful and logical alt text', + 'Evaluates image alt text against accessibility best practices and context relevance.', { surroundingText: z.string().describe('Text surrounding the image, relevant to the image.'), alt: z.string().describe('The alt text of the image being evaluated'), image: z .union([ - z.instanceof(File).describe('The image file being evaluated'), - z.string().url().describe('The URL of the image being evaluated'), + z.instanceof(File).describe('The image src file being evaluated'), + z.string().url().describe('The URL of the image src being evaluated'), + z.string().describe('The file path of the image src being evaluated'), ]) - .describe('The image file or URL being evaluated'), + .describe('The image file, file path, or URL being evaluated'), }, async ({surroundingText, alt, image}) => { // Call the LLM through MCP sampling @@ -664,7 +665,7 @@ server.tool( role: 'user', content: { type: 'text', - text: `Does this alt text: '${alt}' meet accessibility guidelines and describe the ${image} accurately in context of this surrounding text: '${surroundingText}'?\n\n`, + text: `Does this alt text: '${alt}' meet accessibility guidelines and describe the image: ${image} accurately in context of this surrounding text: '${surroundingText}'?\n\n`, }, }, ], @@ -680,7 +681,7 @@ server.tool( }, ], altTextEvaluation: response.content.type === 'text' ? response.content.text : 'Unable to generate summary', - nextSteps: `if the evaluation was bad provide more meaningful alt text.`, + nextSteps: `If the evaluation indicates issues with the alt text, provide more meaningful alt text based on the feedback. DO NOT run this tool repeatedly on the same image - evaluations may vary slightly with each run.`, } }, )