Skip to main content
Glama

Token Saver MCP

by jerry426
find-symbols.ts5.5 kB
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js' import type { ToolMetadata } from '../types' import * as fs from 'node:fs' import { z } from 'zod' import { vscode } from '../../vscode-adapter' /** * Tool metadata for documentation generation */ export const metadata: ToolMetadata = { name: 'find_symbols', title: 'Find Symbols in Workspace', category: 'lsp' as const, description: 'Find symbols (functions, classes, methods, variables) across the workspace using semantic search', docs: { brief: 'Semantic symbol search across entire workspace', parameters: { query: 'The symbol name or pattern to search for', }, examples: [ { title: 'Find function by name', code: `find_symbols({ query: "validateEmail" }) // Finds all functions, methods, or variables named validateEmail`, }, { title: 'Find class definitions', code: `find_symbols({ query: "UserService" }) // Finds UserService class and related symbols`, }, { title: 'Partial name search', code: `find_symbols({ query: "handle" }) // Finds handleRequest, handleError, eventHandler, etc.`, }, ], workflow: { usedWith: ['get_definition', 'get_references', 'get_hover'], followedBy: ['get_references', 'rename_symbol'], description: 'Primary tool for navigating to code symbols semantically', }, tips: [ 'Uses Language Server Protocol for semantic understanding', 'Finds symbols regardless of file location', 'Returns exact locations for direct navigation', 'More accurate than text search for code elements', 'Works best when language servers are active', ], performance: { speed: '< 500ms for most workspaces', tokenSavings: '80-95% vs text search for finding symbols', accuracy: '100% (semantic matching)', buffering: 'Not needed - results are already concise', }, }, } // Tool handler - single source of truth for execution export async function handler({ query }: any): Promise<any> { // Use VSCode's workspace symbol provider const results = await vscode.commands.executeCommand( 'vscode.executeWorkspaceSymbolProvider', query, ) // Handle empty results if (!results || (results as any[]).length === 0) { return { content: [{ type: 'text', text: `No symbols found matching "${query}"`, }], } } // Format results for better readability const formattedResults = (results as any[]) .filter(symbol => symbol && symbol.location) .map((symbol: any) => { // Handle VSCode's URI format const uriObj = symbol.location?.uri const uri = uriObj?.path || uriObj?.toString() || '' const fileName = uri.split('/').pop() || 'unknown' // Handle range - it might be an array [start, end] or an object {start, end} const range = symbol.location?.range let startLine = null let startChar = null if (Array.isArray(range) && range.length >= 1) { // Array format [start, end] startLine = range[0].line + 1 startChar = range[0].character } else if (range?.start) { // Object format {start, end} startLine = range.start.line + 1 startChar = range.start.character } // Try to find the exact position of the symbol name in the line if (startLine !== null && startChar !== null && symbol.name && uri) { try { // Convert URI to file path const filePath = uri.replace('file://', '') // Read the file and get the specific line const fileContent = fs.readFileSync(filePath, 'utf-8') const lines = fileContent.split('\n') const lineContent = lines[startLine - 1] // Convert to 0-indexed if (lineContent) { // Extract just the symbol name without parentheses or type parameters const cleanSymbolName = symbol.name .replace(/\(\)$/, '') // Remove function parentheses .replace(/<.*>/, '') // Remove generic type parameters // Find the position of the symbol name in the line const symbolIndex = lineContent.indexOf(cleanSymbolName, startChar) // If we found the symbol name after the current position, use that if (symbolIndex >= startChar) { startChar = symbolIndex } } } catch (err) { // If we can't read the file or find the position, keep the original // This is non-fatal - we'll just use VSCode's original position } } return { name: symbol.name, kind: symbol.kind, // Function, Class, Variable, etc. file: fileName, uri: uriObj?.scheme ? `${uriObj.scheme}://${uri}` : uri, line: startLine, character: startChar, containerName: symbol.containerName || '', } }) return { content: [{ type: 'text', text: JSON.stringify(formattedResults, null, 2), }], } } // Tool registration function export function register(server: McpServer) { server.registerTool( metadata.name, { title: metadata.title, description: metadata.description, inputSchema: { query: z.string().describe(metadata.docs.parameters?.query || 'The symbol name or pattern to search for'), }, }, handler, // Use the exported handler ) }

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/jerry426/token-saver-mcp'

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