Skip to main content
Glama

ast_grep_search

Search code using structural pattern matching to find specific syntax patterns across multiple programming languages for refactoring, security auditing, and code analysis.

Instructions

šŸ” AST-Grep structural code search tool

Performs powerful structural code search using ast-grep's pattern matching capabilities. Unlike text-based search, this matches syntactical AST node structures.

Key Features:

  • Structural pattern matching (not just text)

  • Multi-language support (JS, TS, Python, Go, Rust, etc.)

  • Wildcard variables ($VAR, $FUNC, $ARGS)

  • Precise code location information

  • Fast Rust-based execution with performance optimizations

  • Comprehensive pattern validation with helpful error messages

  • 120-second timeout for very large projects

  • Automatic respect for .gitignore files (no manual exclusions needed)

Pattern Syntax:

  • Use $ + UPPERCASE for wildcards: $FUNC, $VAR, $ARGS

  • Patterns look like real code: 'function $NAME($ARGS) { $BODY }'

  • Match specific constructs: 'new $CLASS($ARGS)'

  • Valid characters: (), {}, [], "", '', numbers, operators, keywords

  • NOT regex: do NOT use '|', '.*', '.+', '/pattern/', or escapes like '(' or '{'.

Common Mistakes to Avoid: āŒ Don't use: 'function $FUNC' (ambiguous, multiple AST interpretations) āŒ Don't use: 'export $TYPE' (ambiguous, multiple AST interpretations) āŒ Don't use: '$NAME' (too generic, matches everything) āŒ Don't use: /pattern/ (regex syntax not supported)

āœ… Good Patterns:

  • 'function $NAME($ARGS) { $BODY }' (complete function structure)

  • 'export const $NAME = $VALUE' (exported constant)

  • 'import $NAME from "$MODULE"' (import statement)

  • 'new $CLASS($ARGS)' (constructor call)

  • 'def ' (Python function definitions)

  • 'class $NAME:' (Python class)

  • 'await $PROMISE' inside 'for ($COND) { $BODY }' (relational patterns)

Examples:

  • Find all functions: 'function $NAME($ARGS) { $BODY }'

  • Find all exports: 'export const $NAME = $VALUE'

  • Find imports: 'import $NAME from "$MODULE"'

  • Find class instantiation: 'new $CLASS($ARGS)'

  • Find method calls: '$OBJ.$METHOD($ARGS)'

  • Find async functions: 'async function $NAME($ARGS) { $BODY }'

  • Find arrow functions: 'const $NAME = ($ARGS) => $BODY'

  • Find React components: 'export function $NAME($PROPS) { return $JSX }'

  • Find Python function definitions: 'def '

  • Find Python classes: 'class $NAME:'

Advanced Usage:

  • Use $$$ for zero or more arguments: 'console.log($$$ARGS)'

  • Use relational rules: 'await $PROMISE' inside 'for ($COND) { $BODY }'

  • Use multiple searches for OR conditions (alternation not supported)

Direct CLI Usage (for agents with command line access): Agents with command line access can run ast-grep directly:

Basic usage

npx ast-grep --pattern "function $NAME($ARGS) { $BODY }" --lang ts

Python function definitions

npx ast-grep --pattern "def " --lang py

Python classes

npx ast-grep --pattern "class $NAME:" --lang py

With file filtering (recommended for large projects)

npx ast-grep --pattern "def " --lang py src/**/*.py

JSON output

npx ast-grep --pattern "class $NAME:" --lang py --json=stream

Full documentation

npx ast-grep --help

Note: ast-grep respects .gitignore files automatically - no --exclude-dir flags needed

Use Cases:

  • Code refactoring and migration

  • Finding specific patterns across codebase

  • Security auditing for dangerous patterns

  • Architecture analysis and dependency tracking

  • Finding unused imports or exports

  • API usage analysis

Performance Optimizations for Large Projects:

  • 120-second timeout for very large projects

  • Automatically respects .gitignore files for exclusions

  • For additional exclusions, configure .gitignore in your project

Tips for Large Projects (like D:\Dev\SWE-agent):

  • Use filePattern to search specific directories: "src/**/*.py"

  • Add large directories to .gitignore: node_modules/, tests/, docs/, etc.

  • Consider CLI usage for better performance: npx ast-grep --pattern "import json" --lang py src/**/*.py

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
patternNoAST pattern, not regex. Use $UPPERCASE wildcards. Examples: "$FUNC($ARGS)", "new $CLASS($ARGS)", "import $NAME from "express""
rulePathNoPath to an ast-grep rule file (YAML/JSON). When provided, rule mode is used instead of pattern.
ruleYamlNoInline ast-grep rule content in YAML (JSON is also valid YAML). Will be written to a temp file and used with --rule.
ruleJsonNoInline ast-grep rule object (JSON). Optionally validated against local schemas and written to a temp file for --rule.
projectPathYesProject directory path to search in. Can be absolute or relative to workspace.
languageNoProgramming language (auto-detected if not provided). Supported: js, ts, py, go, rs, java, c, cpp
filePatternNoSpecific directory or file path to search within the project (e.g., "src", "lib", "*.py", "src/**/*.ts"). **RECOMMENDED for large projects** - if not provided, searches entire project respecting .gitignore. Use wildcards like "src/**/*.py" to search recursively in specific directories. This can dramatically improve performance on large codebases.
maxMatchesNoMaximum number of matches to return (default: 100)
includeContextNoInclude surrounding context lines for each match (default: true)
contextLinesNoNumber of context lines to include around matches (default: 3)
respectGitignoreNoRespect .gitignore files and other ignore patterns (default: true)
excludePatternsNoAdditional patterns to exclude from search (e.g., ["test/**", "docs/**"])

Implementation Reference

  • Main handler function for 'ast_grep_search' tool. Validates input, prepares rules if provided, executes ast-grep via child_process.spawn (with multiple fallback methods), parses JSON stream output, handles timeouts, gitignore, exclusions, and returns structured AstGrepResult.
    export async function handleAstGrep(args: any): Promise<AstGrepResult> { const startTime = Date.now(); try { // Support rule-based execution path in addition to pattern const hasRuleInput = !!(args.rulePath || args.ruleYaml || args.ruleJson); let pattern: string | undefined; let ruleFilePath: string | undefined; let tempRule: string | null = null; const languageToUse = args.language || inferLanguageFromArgs(args); if (hasRuleInput) { const prepared = await prepareRuleFile(args); ruleFilePath = prepared.ruleFilePath; tempRule = prepared.isTemporary ? prepared.ruleFilePath : null; if (prepared.validationErrors && prepared.validationErrors.length > 0) { const message = 'Rule schema validation failed:\n' + prepared.validationErrors.map((m: string) => '• ' + m).join('\n'); throw new Error(message); } } else { // Early validation: comprehensive pattern validation if (typeof args.pattern !== 'string' || !args.pattern.trim()) { throw new Error( 'Pattern must be a non-empty string containing an AST pattern (not regex).' ); } pattern = String(args.pattern); const validation = validateAstGrepPattern(pattern); if (!validation.isValid) { const errorMessage = validation.error || 'Invalid AST pattern'; const suggestions = validation.suggestions || []; const fullMessage = errorMessage + (suggestions.length > 0 ? '\n\nSuggestions:\n' + suggestions.map(s => '• ' + s).join('\n') : ''); throw new Error(fullMessage); } // Log warnings for potentially problematic patterns if (validation.warning) { logger.warn('āš ļø Potentially problematic AST pattern', { pattern, warning: validation.warning, suggestions: validation.suggestions, }); } // Log suggestions for improvement if (validation.suggestions && validation.suggestions.length > 0) { logger.info('šŸ’” Pattern suggestions available', { pattern, suggestions: validation.suggestions, }); } } logger.info('šŸ” Executing ast-grep search', { mode: hasRuleInput ? 'rule' : 'pattern', pattern, ruleFilePath, projectPath: args.projectPath, language: languageToUse, filePattern: args.filePattern, }); // Validate and resolve the project path const projectPath = await validateAndResolvePath(args.projectPath); // Execute ast-grep command const result = await executeAstGrep({ pattern, ruleFilePath, projectPath, language: languageToUse, filePattern: args.filePattern, maxMatches: args.maxMatches || 100, includeContext: args.includeContext !== false, contextLines: args.contextLines || 3, respectGitignore: args.respectGitignore !== false, excludePatterns: args.excludePatterns, }); const executionTime = Date.now() - startTime; logger.info('āœ… ast-grep search completed', { matches: result.matches.length, executionTime, }); // Clean up temp rule if created if (tempRule) { try { await fs.unlink(tempRule); } catch (error) { logger.debug('Failed to delete temporary ast-grep rule file', { ruleFile: tempRule, error: error instanceof Error ? error.message : String(error), }); } } return { ...result, executionTime, pattern: pattern ?? '(rule)', language: languageToUse, }; } catch (error) { const executionTime = Date.now() - startTime; const errorMessage = error instanceof Error ? error.message : String(error); logger.error('āŒ ast-grep search failed', { error: errorMessage, pattern: args.pattern, executionTime, }); return { matches: [], totalMatches: 0, executionTime, pattern: args?.pattern, language: args.language, error: errorMessage, }; } }
  • Tool definition including name, detailed description, and comprehensive inputSchema with validation for pattern, rule inputs, projectPath (required), language enum, filePattern for performance, maxMatches, context options, gitignore respect, and exclusions.
    export const astGrepTool: Tool = { name: 'ast_grep_search', description: `šŸ” AST-Grep structural code search tool Performs powerful structural code search using ast-grep's pattern matching capabilities. Unlike text-based search, this matches syntactical AST node structures. **Key Features:** - Structural pattern matching (not just text) - Multi-language support (JS, TS, Python, Go, Rust, etc.) - Wildcard variables ($VAR, $FUNC, $ARGS) - Precise code location information - Fast Rust-based execution with performance optimizations - Comprehensive pattern validation with helpful error messages - 120-second timeout for very large projects - Automatic respect for .gitignore files (no manual exclusions needed) **Pattern Syntax:** - Use $ + UPPERCASE for wildcards: $FUNC, $VAR, $ARGS - Patterns look like real code: 'function $NAME($ARGS) { $BODY }' - Match specific constructs: 'new $CLASS($ARGS)' - Valid characters: (), {}, [], "", '', numbers, operators, keywords - NOT regex: do NOT use '|', '.*', '.+', '/pattern/', or escapes like '\\(' or '\\{'. **Common Mistakes to Avoid:** āŒ Don't use: 'function $FUNC' (ambiguous, multiple AST interpretations) āŒ Don't use: 'export $TYPE' (ambiguous, multiple AST interpretations) āŒ Don't use: '$NAME' (too generic, matches everything) āŒ Don't use: /pattern/ (regex syntax not supported) **āœ… Good Patterns:** - 'function $NAME($ARGS) { $BODY }' (complete function structure) - 'export const $NAME = $VALUE' (exported constant) - 'import $NAME from "$MODULE"' (import statement) - 'new $CLASS($ARGS)' (constructor call) - 'def ' (Python function definitions) - 'class $NAME:' (Python class) - 'await $PROMISE' inside 'for ($COND) { $BODY }' (relational patterns) **Examples:** - Find all functions: 'function $NAME($ARGS) { $BODY }' - Find all exports: 'export const $NAME = $VALUE' - Find imports: 'import $NAME from "$MODULE"' - Find class instantiation: 'new $CLASS($ARGS)' - Find method calls: '$OBJ.$METHOD($ARGS)' - Find async functions: 'async function $NAME($ARGS) { $BODY }' - Find arrow functions: 'const $NAME = ($ARGS) => $BODY' - Find React components: 'export function $NAME($PROPS) { return $JSX }' - Find Python function definitions: 'def ' - Find Python classes: 'class $NAME:' **Advanced Usage:** - Use $$$ for zero or more arguments: 'console.log($$$ARGS)' - Use relational rules: 'await $PROMISE' inside 'for ($COND) { $BODY }' - Use multiple searches for OR conditions (alternation not supported) **Direct CLI Usage (for agents with command line access):** Agents with command line access can run ast-grep directly: # Basic usage npx ast-grep --pattern "function $NAME($ARGS) { $BODY }" --lang ts # Python function definitions npx ast-grep --pattern "def " --lang py # Python classes npx ast-grep --pattern "class $NAME:" --lang py # With file filtering (recommended for large projects) npx ast-grep --pattern "def " --lang py src/**/*.py # JSON output npx ast-grep --pattern "class $NAME:" --lang py --json=stream # Full documentation npx ast-grep --help # Note: ast-grep respects .gitignore files automatically - no --exclude-dir flags needed **Use Cases:** - Code refactoring and migration - Finding specific patterns across codebase - Security auditing for dangerous patterns - Architecture analysis and dependency tracking - Finding unused imports or exports - API usage analysis **Performance Optimizations for Large Projects:** - 120-second timeout for very large projects - Automatically respects .gitignore files for exclusions - For additional exclusions, configure .gitignore in your project **Tips for Large Projects (like D:\\Dev\\SWE-agent):** - Use filePattern to search specific directories: "src/**/*.py" - Add large directories to .gitignore: node_modules/, tests/, docs/, etc. - Consider CLI usage for better performance: npx ast-grep --pattern "import json" --lang py src/**/*.py `, inputSchema: { type: 'object', properties: { pattern: { type: 'string', description: 'AST pattern, not regex. Use $UPPERCASE wildcards. Examples: "$FUNC($ARGS)", "new $CLASS($ARGS)", "import $NAME from "express""', }, rulePath: { type: 'string', description: 'Path to an ast-grep rule file (YAML/JSON). When provided, rule mode is used instead of pattern.', }, ruleYaml: { type: 'string', description: 'Inline ast-grep rule content in YAML (JSON is also valid YAML). Will be written to a temp file and used with --rule.', }, ruleJson: { type: 'object', description: 'Inline ast-grep rule object (JSON). Optionally validated against local schemas and written to a temp file for --rule.', }, projectPath: { type: 'string', description: 'Project directory path to search in. Can be absolute or relative to workspace.', }, language: { type: 'string', description: 'Programming language (auto-detected if not provided). Supported: js, ts, py, go, rs, java, c, cpp', enum: [ 'js', 'ts', 'tsx', 'jsx', 'py', 'go', 'rs', 'java', 'c', 'cpp', 'php', 'rb', 'kt', 'swift', ], }, filePattern: { type: 'string', description: 'Specific directory or file path to search within the project (e.g., "src", "lib", "*.py", "src/**/*.ts"). **RECOMMENDED for large projects** - if not provided, searches entire project respecting .gitignore. Use wildcards like "src/**/*.py" to search recursively in specific directories. This can dramatically improve performance on large codebases.', }, maxMatches: { type: 'number', description: 'Maximum number of matches to return (default: 100)', default: 100, minimum: 1, maximum: 1000, }, includeContext: { type: 'boolean', description: 'Include surrounding context lines for each match (default: true)', default: true, }, contextLines: { type: 'number', description: 'Number of context lines to include around matches (default: 3)', default: 3, minimum: 0, maximum: 10, }, respectGitignore: { type: 'boolean', description: 'Respect .gitignore files and other ignore patterns (default: true)', default: true, }, excludePatterns: { type: 'array', description: 'Additional patterns to exclude from search (e.g., ["test/**", "docs/**"])', items: { type: 'string' }, }, }, required: ['projectPath'], }, };
  • Registration of the handler in localHandlers object exported from localTools module, mapping 'ast_grep_search' to handleAstGrep. Also includes astGrepTool in localTools array.
    export const localHandlers = { ...(allowLocalContext ? { local_context: handleSemanticCompact } : {}), local_project_hints: handleProjectHints, local_file_summary: handleFileSummary, frontend_insights: handleFrontendInsights, local_debug_context: handleLocalDebugContext, manage_embeddings: handleManageEmbeddings, ast_grep_search: handleAstGrep, };
  • src/index.ts:135-142 (registration)
    Registration in main MCP server handlers dictionary in src/index.ts, mapping 'ast_grep_search' to handleAstGrep, and astGrepTool added to tools list.
    this.handlers = { ...(allowLocalContext ? { local_context: handleSemanticCompact } : {}), local_project_hints: handleProjectHints, local_file_summary: handleFileSummary, frontend_insights: handleFrontendInsights, local_debug_context: handleLocalDebugContext, ast_grep_search: handleAstGrep, };
  • Core helper function that executes the ast-grep CLI command, handles spawning with platform-specific fallbacks, streams and parses JSON output into AstGrepMatch structures, applies filters, and manages timeouts/errors.
    export async function executeAstGrep(options: { pattern?: string; ruleFilePath?: string; projectPath: string; language?: string; filePattern?: string; maxMatches: number; includeContext: boolean; contextLines: number; respectGitignore?: boolean; excludePatterns?: string[]; }): Promise<AstGrepResult> { return new Promise((resolve, reject) => { const startTime = Date.now(); const cliArgs: string[] = []; try { // Use rule file if provided; otherwise fall back to pattern if (options.ruleFilePath) { logger.debug('Using ast-grep rule file', { ruleFilePath: options.ruleFilePath }); cliArgs.push('--rule', options.ruleFilePath); } else { logger.debug('Adding pattern to args', { pattern: options.pattern, patternType: typeof options.pattern, patternLength: (options.pattern || '').length, }); // Double-check the pattern before adding to args if (!options.pattern || options.pattern.trim() === '') { throw new Error('Pattern is empty or undefined'); } logger.debug('Adding pattern to ast-grep arguments', { pattern: options.pattern, patternLength: options.pattern.length, }); cliArgs.push('--pattern', options.pattern); } if (options.language) { cliArgs.push('--lang', options.language); } cliArgs.push('--json=stream'); if (options.includeContext && options.contextLines > 0) { cliArgs.push('--context', options.contextLines.toString()); } if (options.respectGitignore === false) { cliArgs.push('--no-ignore', 'vcs'); } if (options.filePattern) { cliArgs.push(options.filePattern); } else { // Note: ast-grep respects .gitignore files by default, which provides most exclusions // For additional exclusions, users should configure .gitignore in their project cliArgs.push('.'); logger.debug( 'Using default .gitignore-based exclusions (ast-grep does not support --exclude-dir flags)' ); } logger.info('Executing ast-grep search', { pattern: options.pattern, ruleFilePath: options.ruleFilePath, language: options.language, projectPath: options.projectPath, maxMatches: options.maxMatches, filePattern: options.filePattern || 'all files (with exclusions)', cwd: options.projectPath, }); // Debug: Check if project path exists and is accessible try { const fs = require('fs'); const path = require('path'); const stats = fs.statSync(options.projectPath); logger.debug('Project path exists', { path: options.projectPath, isDirectory: stats.isDirectory(), readable: true, size: stats.size, }); } catch (error) { logger.error('Project path does not exist or is not accessible', { path: options.projectPath, error: error instanceof Error ? error.message : String(error), }); throw new Error('Project path does not exist or is not accessible: ' + options.projectPath); } logger.debug('ast-grep command details', { command: 'npx ast-grep', args: cliArgs, cwd: options.projectPath, fullCommand: 'npx ast-grep ' + cliArgs.join(' '), }); // Log the command being executed const fullCommand = 'npx ast-grep ' + cliArgs.join(' '); logger.debug('Executing ast-grep command:', { command: fullCommand }); let astGrep: ReturnType<typeof spawn> | null = null; let executionMethod = 'unknown'; const localBinary = findLocalAstGrepBinary(); if (localBinary) { try { const useShell = process.platform === 'win32' && localBinary.endsWith('.cmd'); astGrep = spawn(localBinary, cliArgs, { cwd: options.projectPath, stdio: ['ignore', 'pipe', 'pipe'], shell: useShell, }); executionMethod = 'local-binary'; logger.debug('Using local ast-grep binary', { binary: localBinary, useShell }); } catch (localBinaryError) { logger.debug('Failed to spawn local binary, falling back to npx', { error: localBinaryError instanceof Error ? localBinaryError.message : String(localBinaryError), }); } } if (!astGrep) { const approaches = [ { name: 'cmd-npx', command: 'cmd', args: ['/c', 'npx', 'ast-grep', ...cliArgs], options: { shell: false }, }, { name: 'powershell-npx', command: 'powershell', args: ['-Command', 'npx ast-grep ' + cliArgs.join(' ')], options: { shell: false }, }, { name: 'direct-npx', command: 'npx', args: ['ast-grep', ...cliArgs], options: { shell: false }, }, ] as const; let lastError: Error | null = null; for (const approach of approaches) { try { logger.debug('Attempting spawn approach', { approach: approach.name, command: approach.command, args: approach.args, cwd: options.projectPath, pattern: options.pattern, language: options.language, }); astGrep = spawn(approach.command, approach.args, { cwd: options.projectPath, stdio: ['pipe', 'pipe', 'pipe'], // Change to pipe all streams for debugging ...approach.options, env: process.env, }); executionMethod = approach.name; logger.debug('Spawn succeeded', { approach: approach.name }); break; } catch (approachError) { lastError = approachError instanceof Error ? approachError : new Error(String(approachError)); logger.debug('Spawn approach failed', { approach: approach.name, error: lastError.message, code: (lastError as any).code, shell: approach.options.shell, }); } } if (!astGrep) { logger.error('All spawn approaches failed', { approaches: approaches.map(a => a.name), lastError: lastError?.message, cwd: options.projectPath, nodeVersion: process.version, }); throw new Error( 'All spawn approaches failed: ' + (lastError?.message || 'Unknown error') ); } } if (!astGrep) { throw new Error('Failed to spawn ast-grep: no process handle available.'); } let stdout = ''; let stderr = ''; astGrep.stdout?.on('data', data => { stdout += data.toString(); }); astGrep.stderr?.on('data', data => { const chunk = data.toString(); stderr += chunk; // Only log stderr chunks that contain actual error information if (chunk.includes('SyntaxError') || chunk.includes('Error') || chunk.includes('error')) { logger.debug('ast-grep stderr:', chunk.substring(0, 200)); } }); astGrep.on('close', code => { clearInterval(activityInterval); logger.debug('ast-grep process closed', { code, executionMethod, success: code === 0, executionTime: Date.now() - startTime, }); if (code !== 0 && code !== null) { reject( new Error( 'ast-grep exited with code ' + code + ': ' + (stderr || 'No error message provided') ) ); return; } try { let matches = parseAstGrepOutput(stdout, options.maxMatches); if (options.excludePatterns && options.excludePatterns.length > 0) { matches = filterMatchesByExcludePatterns( matches, options.excludePatterns, options.projectPath ); } resolve({ ...matches, executionTime: Date.now() - startTime, pattern: options.pattern || (options.ruleFilePath ? '(rule)' : ''), language: options.language, }); } catch (parseError) { reject( new Error( 'Failed to parse ast-grep output: ' + (parseError instanceof Error ? parseError.message : String(parseError)) ) ); } }); // Add debugging for process activity let lastActivity = Date.now(); const activityInterval = setInterval(() => { const now = Date.now(); const timeSinceLastActivity = now - lastActivity; if (timeSinceLastActivity > 5000) { // Log every 5 seconds of inactivity logger.debug('ast-grep process still running', { executionTime: now - startTime, timeSinceLastActivity, executionMethod, cwd: options.projectPath, }); } }, 5000); astGrep.stdout?.on('data', (data: Buffer) => { lastActivity = Date.now(); const chunk = data.toString(); stdout += chunk; if (chunk.includes('\n')) { logger.debug('ast-grep stdout chunk', { chunkLength: chunk.length, totalStdoutLength: stdout.length, executionTime: Date.now() - startTime, }); } }); astGrep.stderr?.on('data', (data: Buffer) => { lastActivity = Date.now(); const chunk = data.toString(); stderr += chunk; if (chunk.includes('\n')) { logger.debug('ast-grep stderr chunk', { chunkLength: chunk.length, totalStderrLength: stderr.length, executionTime: Date.now() - startTime, }); } }); astGrep.on('error', processError => { clearInterval(activityInterval); logger.error('ast-grep process error', { error: processError.message, code: (processError as any).code, stack: processError.stack?.substring(0, 300), executionMethod, cwd: options.projectPath, platform: process.platform, nodeVersion: process.version, path: process.env.PATH?.substring(0, 200), }); reject( new Error( 'Failed to spawn ast-grep (' + executionMethod + '): ' + processError.message + ' (code: ' + (processError as any).code + '). Make sure @ast-grep/cli is installed and accessible.' ) ); }); setTimeout(() => { clearInterval(activityInterval); if (astGrep) { astGrep.kill(); } reject( new Error( 'ast-grep search timed out after 30 seconds. For large projects, consider using filePattern to search specific directories (e.g., "src/**/*.py") or excludePatterns to exclude large directories.' ) ); }, 30000); } catch (error) { logger.error('Failed to execute ast-grep', { error: error instanceof Error ? error.message : String(error), cwd: options.projectPath, platform: process.platform, }); reject( new Error( 'Failed to execute ast-grep: ' + (error instanceof Error ? error.message : String(error)) ) ); } }); }

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/sbarron/AmbianceMCP'

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