Skip to main content
Glama
yashpreetbathla

MCP Accessibility Bridge

get_interactive_elements

Identify interactive page elements like buttons and inputs, providing accessibility details and test selectors for automated testing and screen reader compatibility.

Instructions

Find all interactive elements on the page (buttons, inputs, links, etc.) and return their accessibility info plus multi-framework test selectors. Covers 20 interactive ARIA roles. Use roles[] to filter to specific roles.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
rolesNoSpecific ARIA roles to include. Defaults to all 20 interactive roles: button, link, textbox, searchbox, combobox, listbox, option, checkbox, radio, switch, slider, spinbutton, menuitem, tab, treeitem, gridcell, rowheader, columnheader, progressbar, scrollbar
includeDisabledNoInclude disabled elements. Default: false
maxElementsNoMaximum number of elements to return. Default: 100

Implementation Reference

  • Main handler function getInteractiveElementsHandler that retrieves interactive elements from the page. It fetches the full accessibility tree, filters by interactive roles (button, link, textbox, etc.), optionally includes disabled elements, resolves DOM info in parallel, and returns element details with accessibility properties and suggested selectors.
    export async function getInteractiveElementsHandler(args: { roles?: string[]; includeDisabled?: boolean; maxElements?: number; }): Promise<ReturnType<typeof toolSuccess | typeof toolError>> { try { const { cdpSession } = browserManager.requireConnection(); const targetRoles = args.roles ? new Set(args.roles.map((r) => r.toLowerCase())) : INTERACTIVE_ROLES; const includeDisabled = args.includeDisabled ?? false; const maxElements = args.maxElements ?? 100; // Get full AX tree const result = await cdpSession.send( 'Accessibility.getFullAXTree', {} ) as GetFullAXTreeResponse; const allNodes: CdpAXNode[] = result.nodes; // Filter to interactive roles const interactiveNodes = allNodes.filter((node) => { if (node.ignored) return false; const role = (node.role?.value as string ?? '').toLowerCase(); if (!targetRoles.has(role)) return false; // Skip disabled unless requested if (!includeDisabled) { const props = node.properties ?? []; const disabledProp = props.find((p) => p.name === 'disabled'); if (disabledProp?.value?.value === true) return false; } return true; }); const limited = interactiveNodes.slice(0, maxElements); // Resolve DOM info for each node in parallel const elementResults = await Promise.all( limited.map(async (node): Promise<ElementResult> => { const axSummary = cdpAXNodeToSummary(node); const role = (node.role?.value as string) ?? ''; const name = (node.name?.value as string) ?? ''; const base: ElementResult = { role, name, nodeId: node.nodeId, backendDOMNodeId: node.backendDOMNodeId, axProperties: axSummary, }; if (!node.backendDOMNodeId) { return { ...base, suggestedSelectors: buildSelectorFromRawNode(name, role, 'unknown', undefined), }; } try { const describeResult = await cdpSession.send('DOM.describeNode', { backendNodeId: node.backendDOMNodeId, depth: 0, }) as DomDescribeNodeResponse; const domNode = describeResult.node; const tagName = domNode.localName; const rawAttrs = domNode.attributes; const domAttributes = parseAttributes(rawAttrs); return { ...base, tagName, domAttributes, suggestedSelectors: buildSelectorFromRawNode(name, role, tagName, rawAttrs), }; } catch { // DOM.describeNode can fail for some nodes (e.g. detached) return { ...base, suggestedSelectors: buildSelectorFromRawNode(name, role, 'unknown', undefined), }; } }) ); return toolSuccess({ totalFound: interactiveNodes.length, returned: elementResults.length, maxElements, roles: [...targetRoles], elements: elementResults, }); } catch (error) { return toolError(error); } }
  • Zod schema definition getInteractiveElementsSchema validating input parameters: roles (array of ARIA roles), includeDisabled (boolean), and maxElements (positive integer). Defaults to all 20 interactive roles, excludes disabled elements, and max 100 elements.
    export const getInteractiveElementsSchema = { roles: z .array(z.string()) .optional() .describe( 'Specific ARIA roles to include. Defaults to all 20 interactive roles: ' + 'button, link, textbox, searchbox, combobox, listbox, option, checkbox, radio, ' + 'switch, slider, spinbutton, menuitem, tab, treeitem, gridcell, rowheader, ' + 'columnheader, progressbar, scrollbar' ), includeDisabled: z .boolean() .optional() .default(false) .describe('Include disabled elements. Default: false'), maxElements: z .number() .int() .positive() .optional() .default(100) .describe('Maximum number of elements to return. Default: 100'), };
  • src/index.ts:104-116 (registration)
    Tool registration of 'get_interactive_elements' with title, description explaining it finds interactive elements and returns accessibility info plus multi-framework test selectors, and references the schema and handler.
    // ── get_interactive_elements ───────────────────────────────────────────────── server.registerTool( 'get_interactive_elements', { title: 'Get Interactive Elements', description: 'Find all interactive elements on the page (buttons, inputs, links, etc.) ' + 'and return their accessibility info plus multi-framework test selectors. ' + 'Covers 20 interactive ARIA roles. Use roles[] to filter to specific roles.', inputSchema: getInteractiveElementsSchema, }, getInteractiveElementsHandler );
  • INTERACTIVE_ROLES constant containing Set of 20 ARIA role strings (button, link, textbox, searchbox, combobox, listbox, option, checkbox, radio, switch, slider, spinbutton, menuitem, tab, treeitem, gridcell, rowheader, columnheader, progressbar, scrollbar) used for filtering nodes.
    const INTERACTIVE_ROLES = new Set([ 'button', 'link', 'textbox', 'searchbox', 'combobox', 'listbox', 'option', 'checkbox', 'radio', 'switch', 'slider', 'spinbutton', 'menuitem', 'tab', 'treeitem', 'gridcell', 'rowheader', 'columnheader', 'progressbar', 'scrollbar', ]);
  • parseAttributes helper function that converts DOM attributes from alternating string array format (['attr1', 'value1', 'attr2', 'value2']) into a key-value Record object for easier access.
    function parseAttributes(attrs: string[] | undefined): Record<string, string> { const map: Record<string, string> = {}; if (!attrs) return map; for (let i = 0; i + 1 < attrs.length; i += 2) { map[attrs[i]] = attrs[i + 1]; } return map; }

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/yashpreetbathla/mcp-accessibility-bridge'

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