Skip to main content
Glama
get_text.ts6 kB
import { BrowserToolBase } from '../base.js'; import { ToolContext, ToolResponse, ToolMetadata, SessionConfig, createSuccessResponse, createErrorResponse, } from '../../common/types.js'; import { makeConfirmPreview } from '../../common/confirm_output.js'; /** * Tool for getting visible text from the page */ export class GetTextTool extends BrowserToolBase { static getMetadata(sessionConfig?: SessionConfig): ToolMetadata { return { name: "get_text", description: "⚠️ RARELY NEEDED: Get ALL visible text content from the entire page (no structure, just raw text). Most tasks need structured inspection instead. ONLY use get_text for: (1) extracting text for content analysis (word count, language detection), (2) searching for text when location is completely unknown, (3) text-only snapshots for comparison. For structured tasks, use: inspect_dom() to understand page structure, find_by_text() to locate specific text with context, query_selector() to find elements. Auto-returns text if <2000 chars (small elements); if larger, returns a preview and a one-time token to fetch the full output via confirm_output. Supports testid shortcuts.", inputSchema: { type: "object", properties: { selector: { type: "string", description: "CSS selector, text selector, or testid shorthand to limit text extraction to a specific container. Omit to get text from entire page. Example: 'testid:article-body' or '#main-content'" }, maxLength: { type: "number", description: "Maximum number of characters to return (default: 20000)" } }, required: [], }, }; } async execute(args: any, context: ToolContext): Promise<ToolResponse> { const requestedMaxLength = typeof args.maxLength === 'number' && Number.isFinite(args.maxLength) && args.maxLength > 0 ? Math.floor(args.maxLength) : 20000; const PREVIEW_THRESHOLD = 2000; if (!context.page) { return createErrorResponse('Page is not available'); } if (context.browser && !context.browser.isConnected()) { return createErrorResponse('Browser is not connected'); } if (context.page.isClosed()) { return createErrorResponse('Page is not available or has been closed'); } return this.safeExecute(context, async (page) => { try { const hasSelector = typeof args.selector === 'string' && args.selector.length > 0; const scopeLabel = hasSelector ? ` (from "${args.selector}")` : ' (entire page)'; const lines: string[] = [`Visible text content${scopeLabel}`]; let selectionWarning = ''; let textContent = ''; if (hasSelector) { const normalizedSelector = this.normalizeSelector(args.selector); const locator = page.locator(normalizedSelector); const { element, elementIndex, totalCount } = await this.selectPreferredLocator(locator, { originalSelector: args.selector, }); selectionWarning = this.formatElementSelectionInfo( args.selector, elementIndex, totalCount, true ); textContent = await element.evaluate((target: HTMLElement | null) => { if (!target) { return ''; } if (typeof target.innerText === 'string') { return target.innerText; } return target.textContent ?? ''; }); } else { textContent = await page.evaluate(() => document.body?.innerText ?? ''); } textContent = textContent ?? ''; if (selectionWarning) { lines.push(selectionWarning.trimEnd()); } const safeMaxLength = requestedMaxLength > 0 ? requestedMaxLength : 20000; const totalLength = textContent.length; // Large-output guard: return preview + confirm_output token when text is big if (totalLength >= PREVIEW_THRESHOLD) { const preview = makeConfirmPreview(() => textContent, { counts: { totalLength, shownLength: Math.min(500, totalLength), truncated: true, }, previewLines: [ 'Preview (first 500 chars):', textContent.slice(0, 500), ...(totalLength > 500 ? ['...'] : []), '', '⚠️ Full text not returned to save tokens', '', '💡 RECOMMENDED: Use token-efficient alternatives:', ' • inspect_dom() - structured view with positions and layout', ' • find_by_text() - locate specific text with context', ' • query_selector() - inspect specific elements', ], }); lines.push(`Text size: ${totalLength.toLocaleString()} characters (exceeds ${PREVIEW_THRESHOLD} char threshold)`); lines.push(''); lines.push(...preview.lines); return createSuccessResponse(lines.join('\n')); } lines.push(''); let displayText = textContent; const truncated = displayText.length > safeMaxLength; if (truncated) { displayText = `${displayText.slice(0, safeMaxLength)}\n[Output truncated due to size limits]`; } lines.push(displayText); if (truncated) { lines.push(''); lines.push( `Output truncated due to size limits (returned ${safeMaxLength} of ${textContent.length} characters)` ); } lines.push(''); lines.push('💡 TIP: If you need structured inspection, try inspect_dom(), find_by_text(), or query_selector().'); return createSuccessResponse(lines.join('\n')); } catch (error) { return createErrorResponse(`Failed to get visible text content: ${(error as Error).message}`); } }); } }

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/antonzherdev/mcp-web-inspector'

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