A friendly layer on top of tree-sitter, with an MCP server for AI agents.
Tree-sitter is incredibly powerful for code analysis, but its API is hard to use—both for humans and for AI agents. The node type names are verbose, pattern matching requires manual tree traversal, and transformations involve byte offset math. Tree Hugger wraps tree-sitter with an interface that feels more like writing CSS selectors than navigating an AST.
The library lets you query code with patterns like ‘function[async]’ or ‘class method:has(call[text*="fetch"])’ instead of enumerating every tree-sitter node type. It ships with smart transformations—renaming an identifier skips occurrences inside strings and comments, removing a function call removes the whole statement, and insertions match the surrounding indentation.
The MCP server exposes all of this to AI agents as 12 tools covering analysis, transformation, and navigation. An agent can parse a file, find all async functions with debug logging, rename an identifier safely across the codebase, and remove unused imports—all through MCP tool calls.
import Parser from 'tree-sitter';
import JavaScript from 'tree-sitter-javascript';
const parser = new Parser();
parser.setLanguage(JavaScript);
const tree = parser.parse(code);
const asyncFunctions = [];
function walk(node) {
if (
node.type === 'function_declaration' ||
node.type === 'function_expression' ||
node.type === 'arrow_function' ||
node.type === 'method_definition'
) {
if (node.childForFieldName('async')
|| node.text.startsWith('async')) {
asyncFunctions.push(node);
}
}
for (const child of node.children) walk(child);
}
walk(tree.rootNode);import { parse } from 'tree-hugger-js';
const fns = parse(code).findAll('function[async]');import { parse } from 'tree-hugger-js';
const tree = parse('app.tsx');
// CSS-like selectors instead of raw tree-sitter node types
const asyncFns = tree.findAll('function[async]');
const fetchCalls = tree.findAll('call[text*="fetch"]');
const styledJsx = tree.findAll('jsx:has(jsx-attribute[name="className"])');
// Built-in queries
const hooks = tree.hooks(); // React hooks (useX pattern)
const imports = tree.imports(); // All import statementsconst result = tree.transform()
.rename('getUserData', 'fetchUserProfile')
.remove('console.log')
.removeUnusedImports()
.toString();