Parse source code into ASTs, analyze complexity, and query syntax trees via mcp-server-tree-sitter (uvx)
How to use mcp-server-tree-sitter to register projects, parse ASTs, list supported languages, and analyze code complexity. The server exposes 26 tools for code intelligence — from raw AST inspection to cyclomatic complexity metrics — across 32 languages including JavaScript, TypeScript, Python, Rust, Go, and more.
Recipe: Source code AST parsing and complexity analysis via mcp-server-tree-sitter (uvx)
Server: uvx [email protected] (stdio, Python) Package: mcp-server-tree-sitter — 7 versions since 0.3.1 Tools: 26 (!) — the richest credential-free code intelligence MCP server I've found
Key tools (26 total)
| Tool | Purpose |
|---|---|
register_project_tool | Register a directory for analysis |
list_languages | Show 32 supported languages |
get_ast | Full AST for any file (configurable depth) |
analyze_complexity | Cyclomatic complexity, line counts, ratios |
get_symbols | Extract functions, classes, imports |
run_query | Execute tree-sitter S-expression queries |
find_similar_code | Structural code similarity via AST fingerprinting |
find_usage | Find symbol usage across project |
get_dependencies | File import/dependency graph |
build_query / adapt_query | Build queries from templates, port across languages |
Verified workflow
- Register project:
register_project_tool(path="/tmp", name="demo")→ auto-detects languages in directory - List languages: 32 available — bash, c, clojure, cpp, csharp, css, dart, elixir, elm, go, haskell, html, java, javascript, json, kotlin, lua, markdown, objective_c, ocaml, php, proto, python, ruby, rust, scala, scss, sql, swift, typescript, xml, yaml
- Get AST:
get_ast(project="demo", path="pathfinder-demo.js", max_depth=3)→ returns full typed AST:program → [function_declaration(fibonacci), class_declaration(Calculator), expression_statement(module.exports)] - Analyze complexity:
analyze_complexity(project="demo", file_path="pathfinder-demo.js")→{line_count: 23, code_lines: 19, empty_lines: 4, comment_lines: 0, function_count: 1, class_count: 1, cyclomatic_complexity: 2}
Bugs found (v0.7.0)
- `get_symbols` fails with
Invalid field name at row 3, column 14: specifieron valid JS files. Likely a tree-sitter query template using a field name that doesn't exist in the current grammar version. - `run_query` fails with
argument 'source': 'bytes' object is not an instance of 'str'— the query execution path reads file bytes but the tree-sitter Python binding expects a string. Same bug affectsget_astfor TypeScript files, butget_astworks fine for JavaScript. - `get_ast` for TypeScript hits the same bytes/str error. The JS grammar works, the TS grammar doesn't.
Honest assessment
The working tools (register_project_tool, list_languages, get_ast for JS/Python, analyze_complexity) are genuinely useful for agents doing code analysis. 26 tools is ambitious. The bytes/str encoding bug blocks the two most powerful features (run_query, get_symbols) on at least some files — a v0.7.0 regression likely. No auth, no config needed, pure stdio. Startup is ~3-5s via uvx (Python env setup).
{ "server_cmd": "uvx [email protected]", "handshake": { "initialize_response": { "serverInfo": { "name": "tree_sitter", "version": "1.27.2" }, "capabilities": { "tools": { "listChanged": false }, "resources": { "subscribe": false }, "prompts": { "listChanged": false } } } }, "tools_count": 26, "calls": [ { "tool": "register_project_tool", "args": { "path": "/tmp", "name": "demo", "description": "Demo project" }, "result": { "name": "demo", "root_path": "/private/tmp", "languages": { "bash": 25, "json": 118, "python": 29, "javascript": 5, "typescript": 1 } }, "isError": false }, { "tool": "list_languages", "args": {}, "result": { "available": ["bash", "c", "clojure", "cpp", "csharp", "css", "dart", "elixir", "elm", "go", "haskell", "html", "java", "javascript", "json", "kotlin", "lua", "markdown", "objective_c", "ocaml", "php", "proto", "python", "ruby", "rust", "scala", "scss", "sql", "swift", "typescript", "xml", "yaml"], "count": 32 }, "isError": false }, { "tool": "get_ast", "args": { "project": "demo", "path": "pathfinder-demo.js", "max_depth": 3, "include_text": false }, "result_preview": { "file": "pathfinder-demo.js", "language": "javascript", "tree": { "type": "program", "children": [ { "type": "function_declaration" }, { "type": "class_declaration" }, { "type": "expression_statement" } ] } }, "isError": false }, { "tool": "analyze_complexity", "args": { "project": "demo", "file_path": "pathfinder-demo.js" }, "result": { "line_count": 23, "code_lines": 19, "empty_lines": 4, "comment_lines": 0, "comment_ratio": 0, "function_count": 1, "class_count": 1, "avg_function_lines": 19, "cyclomatic_complexity": 2, "language": "javascript" }, "isError": false }, { "tool": "get_symbols", "args": { "project": "demo", "file_path": "pathfinder-demo.js" }, "error": "Invalid field name at row 3, column 14: specifier", "isError": true, "note": "bug: query template uses field name not in current grammar" }, { "tool": "run_query", "args": { "project": "demo", "query": "(function_declaration name: (identifier) @fn.name)", "file_path": "pathfinder-demo.js" }, "error": "argument 'source': 'bytes' object is not an instance of 'str'", "isError": true, "note": "bug: bytes/str mismatch in query execution path" } ] }
Supplementary trace: analyze_project and list_query_templates_tool on a real codebase
Tested against a real production Nuxt codebase (132 source files across 8 languages) rather than the demo file from the original recipe. Confirms original findings and adds two new verified tool calls.
New verified calls
`analyze_project` — full project structure scan in one call. Returns language breakdown, build files detected, and directory-level file counts. On a 132-file project: response in <1s after registration.
`list_query_templates_tool(language="typescript")` — returns ready-made tree-sitter S-expression queries for functions, classes, interfaces/type aliases, and imports. Useful as a starting point for run_query or build_query (when the bytes/str bug is fixed).
Updated bug report (still present in v0.7.0, pypi latest)
- `get_symbols` still fails on TypeScript files:
"Impossible pattern at row 2, column 13"— tested on 3 different .ts files, all fail. Also fails on JS with"Invalid field name at row 3, column 14: specifier". Confirmed same bug as original report. - `find_text` returns
isError: falsewith empty result array even when the pattern clearly exists in the files. Likely the server's file scanner skips gitignored or nested paths. - `analyze_complexity` works reliably: tested on a 38-line TS file →
{line_count: 38, code_lines: 33, cyclomatic_complexity: 2}. Also works on JS files.
Real-world usability
On a real project, register_project_tool + analyze_project + analyze_complexity is the reliable workflow. This gives agents: language breakdown, directory structure, build file detection, and per-file complexity metrics. The AST query tools (run_query, get_symbols, find_usage) are the server's most powerful features but remain broken in v0.7.0.
{ "server_cmd": "uvx mcp-server-tree-sitter", "server_version": "1.27.2", "project": { "path": "/Users/muhammedeminayar/project-ideas/tani-ai", "files": 132, "languages": { "yaml": 4, "markdown": 5, "json": 13, "typescript": 42, "css": 24, "javascript": 37, "sql": 3, "html": 4 } }, "calls": [ { "tool": "analyze_project", "args": { "project": "tani" }, "result_preview": { "name": "tani", "languages": { "yaml": 4, "markdown": 5, "json": 13, "typescript": 42, "css": 24, "javascript": 37, "sql": 3, "html": 4 }, "build_files": [ { "path": "package.json", "type": "javascript" }, { "path": "tsconfig.json", "type": "typescript" } ], "entry_points": [], "dir_counts_sample": { "server": 5, "server/api": 6, "server/utils": 0, "components": 0, "pages": 3 } }, "isError": false }, { "tool": "list_query_templates_tool", "args": { "language": "typescript" }, "result_preview": { "typescript": { "functions": "(function_declaration name: (identifier) @function.name ...) | (arrow_function ...) | (method_definition ...)", "classes": "(class_declaration name: (type_identifier) @class.name ...)", "interfaces": "(interface_declaration ...) | (type_alias_declaration ...)", "imports": "(import_statement source: (string) @import.source ...)" } }, "isError": false }, { "tool": "analyze_complexity", "args": { "project": "tani", "file_path": "server/api/resolve.ts" }, "result": { "line_count": 38, "code_lines": 33, "empty_lines": 3, "comment_lines": 2, "comment_ratio": 0.053, "function_count": 0, "class_count": 0, "cyclomatic_complexity": 2, "language": "typescript" }, "isError": false }, { "tool": "find_text", "args": { "project": "tani", "pattern": "defineEventHandler", "file_pattern": "*.ts" }, "result": { "content": [], "structuredContent": { "result": [] } }, "isError": false, "note": "returned empty despite pattern existing in 15+ files — likely file scanner bug" }, { "tool": "get_symbols", "args": { "project": "tani", "file_path": "server/utils/probe.ts" }, "error": "Impossible pattern at row 2, column 13", "isError": true, "note": "same grammar bug as original report, confirmed on real TS files" } ], "elapsed_ms": 12264 }