Language capability matrix
trace-mcp ships 81 language plugins. They are not equally deep, and this
page says how deep each one is. Every language in the list gets symbol
extraction; call graphs and type edges are a much smaller set. For what each
language’s framework integrations understand on top of that, see supported
frameworks; for the include globs referenced
below, see configuration. The edge columns are what makes
the graph queryable: a language with call edges answers get_call_graph and
call-aware find_usages (tools reference), one without
them still answers search and get_outline. How those edges are produced
is the two-pass pipeline in architecture.
- indexed with the default config: 78 (the rest need an
includeentry — see below) - tree-sitter parser: 29 · regex parser: 46 · custom parser: 6
- import edges: 22
- call edges (
get_call_graph, call-awarefind_usages): 3 - type / inheritance edges: 2
- covered by a plugin test: 68
What the columns mean
| Column | Meaning |
|---|---|
| Parser | tree-sitter — real grammar-based AST. regex — pattern extraction, no AST. custom — hand-written parser for a structured format. |
| Default | The shipped default include globs reach files with this extension. Where this is empty the plugin only runs once you add the extension to include in .trace.json. |
| Imports | Import statements are resolved into graph edges. Plugins outside this set still parse imports, but nothing turns them into edges yet. |
| Calls | A call-graph resolver exists, so “who calls this” is answerable for this language. |
| Types | Type-annotation or inheritance edges are resolved. |
| Tests | At least one test exercises this plugin directly. |
Default config vs. plugin count. The default include is one global glob
over every extension the plugins below claim, so 78 of
the 81 plugins run wherever their files live in the repo — no
directory anchoring. The remaining 3
are pure data formats, left out because lockfiles, fixtures and .svg would
swamp the index for little symbol value. Ask for them explicitly if you want
them:
{ "include": ["schemas/**/*.json", "k8s/**/*.xml"] }
Note that include in a project config replaces the built-in list rather
than adding to it, so copy the default glob alongside your addition if you
still want the rest of the repo indexed.
A regex plugin still gives you working search, get_outline and symbol
navigation — that covers most “find it and read it” work. What it does not give
you is a call graph: that needs an AST plus a per-language resolver. Where the
Calls column is empty, get_call_graph returns nothing for that language
unless you enable LSP enrichment (lsp.enabled: true) or ingest a SCIP index.
Imports means edges, not parsing. Most plugins extract import statements;
far fewer have a pipeline pass that resolves the specifier to a target node, and
without one the extracted import never becomes an edge. This column counts the
second thing, so it is much shorter than the language list — see
src/indexer/edge-resolvers/import-capable-languages.ts.
“Yes” is not “every import.” C# is the narrowest case in this column today:
its resolver only trusts using forms that name a specific type (using
static X.Y.Type, an aliased using A = X.Y.Type) and deliberately leaves a
plain using Namespace; — the overwhelming majority of real C# imports —
unresolved, because a namespace can span most of a codebase and a file-level
edge to all of it would be closer to noise than signal. On a large real repo
(Newtonsoft.Json, ~5,000 using directives) this column’s “yes” for C#
produced edges for 12 of them — roughly 0.2%. See
src/indexer/edge-resolvers/csharp-imports.ts for the reasoning and
src/indexer/plugins/language/csharp/helpers.ts for extraction.
Import resolution depth on real repos
C#’s 0.2% above is not an outlier worth a special paragraph — it is one point
on a spread every resolver-bearing language sits somewhere on. Imports: yes
only means a pipeline pass exists; it says nothing about how much of a real
codebase that pass actually connects. Measured on one well-known public repo
per language — clone it, run the real indexing pipeline, read the
{ created, external, ambiguous } counts each resolver already logs
(src/indexer/edge-resolvers/*-imports.ts), filtered by that resolver’s exact
log message so a multi-language repo can’t attribute one language’s counts to
another — the reusable, reproducible measurement is
scripts/measure-import-resolution.ts, and its output is
docs/_data/import-resolution.json:
| Language | Repo | Commit | Edges created | Left external | Left ambiguous | Share resolved |
|---|---|---|---|---|---|---|
| lua | mpeterv/luacheck | 7360cfb4cf2c | 130 | 16 | 0 | 89.0% |
| c | curl/curl | 8f6046485e15 | 3138 | 990 | 0 | 76.0% |
| elixir | elixir-plug/plug | 73404f851852 | 87 | 44 | 0 | 66.4% |
| php | guzzle/guzzle | 93939470950a | 374 | 247 | 0 | 60.2% |
| ruby | sinatra/sinatra | cb22afd7902b | 131 | 88 | 0 | 59.8% |
| rust | BurntSushi/ripgrep | 3fce3b5bb023 | 453 | 447 | 0 | 50.3% |
| typescript | colinhacks/zod | 7a00236683c7 | 660 | 660 | 0 | 50.0% |
| go | spf13/cobra | adbc8813901b | 159 | 178 | 0 | 47.2% |
| java | google/gson | b3f4ca20087f | 1085 | 1586 | 0 | 40.6% |
| kotlin | square/okhttp | dfcfab38248e | 2621 | 4330 | 0 | 37.7% |
| cpp | fmtlib/fmt | 2d4d8a13c2b4 | 155 | 411 | 0 | 27.4% |
| python | pallets/flask | d318b6834711 | 96 | 333 | 0 | 22.4% |
| csharp | JamesNK/Newtonsoft.Json | 09bb545d7296 | 12 | 4979 | 0 | 0.2% |
“Left external” does not mean “missed,” but it does not always mean
“correctly out of scope” either — read the resolver. Most of the time a
specifier a resolver leaves external is genuinely a third-party or standard
library import (import "github.com/spf13/pflag", import os), and
resolving it to a file in this repo would be wrong. But the bucket’s exact
meaning is resolver-specific: csharp’s external count also holds plain
using Namespace; directives that are internal to the repo — left
unresolved by design because a namespace can span most of a codebase (see the
C# paragraph above), not because the target lives outside it. Treat this table
as what “the resolver exists” costs out to on one real codebase per language,
not as a defect list. Every row is n=1 — one repo’s import style, not a
distribution; re-run the script against a second repo per language before
treating any row as a trend rather than a data point.
Matrix
| Language | Extensions | Parser | Default | Imports | Calls | Types | Tests |
|---|---|---|---|---|---|---|---|
| ada | .adb .ads .ada | regex (multi-pass) | yes | — | — | — | yes |
| al | .al | regex | yes | — | — | — | yes |
| apex | .cls .trigger .apex | regex (multi-pass) | yes | — | — | — | yes |
| assembly | .asm .s .S | regex | yes | — | — | — | yes |
| astro | .astro | tree-sitter | yes | yes | — | — | yes |
| autohotkey | .ahk .ah2 | regex | yes | — | — | — | yes |
| bash | .sh .bash .zsh | tree-sitter | yes | — | — | — | yes |
| blade | .blade.php | regex | yes | — | — | — | yes |
| c | .c .h | tree-sitter | yes | yes | — | — | yes |
| clojure | .clj .cljs .cljc .edn | regex | yes | — | — | — | — |
| cmake | .cmake CMakeLists.txt | regex | yes | — | — | — | yes |
| cobol | .cob .cbl .cpy .cobol | regex (multi-pass) | yes | — | — | — | yes |
| common-lisp | .lisp .lsp .cl .asd | regex (multi-pass) | yes | — | — | — | yes |
| cpp | .cpp .cxx .cc .hpp | tree-sitter | yes | yes | — | — | yes |
| csharp | .cs | tree-sitter | yes | yes | — | — | yes |
| css | .css .scss .sass .less | tree-sitter | yes | yes | — | — | yes |
| cuda | .cu .cuh | regex | yes | — | — | — | — |
| d | .d .di | regex (multi-pass) | yes | — | — | — | yes |
| dart | .dart | tree-sitter | yes | — | — | — | yes |
| dockerfile | Dockerfile .dockerfile | regex | yes | — | — | — | yes |
| ejs | .ejs | regex | yes | — | — | — | yes |
| elisp | .el .elc | tree-sitter | yes | — | — | — | — |
| elixir | .ex .exs | tree-sitter | yes | yes | — | — | yes |
| elm | .elm | tree-sitter | yes | — | — | — | — |
| erlang | .erl .hrl | regex | yes | — | — | — | yes |
| form | .frm .prc | regex | yes | — | — | — | — |
| fortran | .f .f90 .f95 .f03 | regex | yes | — | — | — | yes |
| fsharp | .fs .fsi .fsx | regex (multi-pass) | yes | — | — | — | — |
| gdscript | .gd | regex | yes | — | — | — | yes |
| gleam | .gleam | regex | yes | — | — | — | yes |
| glsl | .glsl .vert .frag .geom | regex | yes | — | — | — | — |
| go | .go | tree-sitter | yes | yes | — | — | yes |
| graphql | .graphql .gql | custom | yes | — | — | — | yes |
| groovy | .groovy .gradle .gvy | regex | yes | — | — | — | yes |
| haskell | .hs .lhs | regex | yes | — | — | — | yes |
| hcl | .tf .hcl .tfvars | custom | yes | yes | — | — | yes |
| html | .html .htm | tree-sitter | yes | yes | — | — | yes |
| ini | .ini .cfg .conf .properties | regex | — | — | — | — | — |
| java | .java | tree-sitter | yes | yes | — | — | yes |
| json | .json .jsonc .json5 | tree-sitter | — | — | — | — | yes |
| julia | .jl | regex | yes | — | — | — | yes |
| kotlin | .kt .kts | tree-sitter | yes | yes | — | — | yes |
| lean | .lean | regex | yes | — | — | — | — |
| lua | .lua .luau | tree-sitter | yes | yes | — | — | yes |
| magma | .m .mag .magma | regex | yes | — | — | — | — |
| makefile | Makefile makefile .mk GNUmakefile | regex | yes | — | — | — | yes |
| markdown | .md .mdx .markdown .qmd | custom | yes | yes | — | — | yes |
| matlab | .m .mlx .mat | regex (multi-pass) | yes | — | — | — | yes |
| meson | meson.build meson_options.txt | regex | yes | — | — | — | — |
| nim | .nim .nims .nimble | regex | yes | — | — | — | yes |
| nix | .nix | regex | yes | — | — | — | yes |
| objc | .m .mm | tree-sitter | yes | — | — | — | yes |
| ocaml | .ml .mli | tree-sitter | yes | — | — | — | yes |
| pascal | .pas .dpr .dpk .lpr | regex (multi-pass) | yes | — | — | — | yes |
| perl | .pl .pm .t | regex | yes | — | — | — | yes |
| php | .php | tree-sitter | yes | yes | yes | — | yes |
| plsql | .pls .plb .pck .pkb | regex (multi-pass) | yes | — | — | — | yes |
| powershell | .ps1 .psm1 .psd1 | regex (multi-pass) | yes | — | — | — | yes |
| prisma | .prisma | custom | yes | — | — | — | yes |
| protobuf | .proto | regex | yes | — | — | — | yes |
| python | .py .pyi | tree-sitter | yes | yes | yes | yes | yes |
| r | .r .R .Rmd | regex | yes | — | — | — | yes |
| ruby | .rb .rake | tree-sitter | yes | yes | — | — | yes |
| rust | .rs | tree-sitter | yes | yes | — | — | yes |
| scala | .scala .sc | tree-sitter | yes | — | — | — | yes |
| solidity | .sol | tree-sitter | yes | — | — | — | yes |
| sql | .sql | regex | yes | — | — | — | yes |
| svelte | .svelte | regex | yes | yes | — | — | yes |
| swift | .swift | tree-sitter | yes | — | — | — | yes |
| tcl | .tcl .tk .itcl .itk | regex (multi-pass) | yes | — | — | — | yes |
| toml | .toml | tree-sitter | yes | — | — | — | yes |
| typescript | .ts .tsx .mts .cts | tree-sitter | yes | yes | yes | yes | yes |
| verilog | .v .sv .svh .vh | regex | yes | — | — | — | yes |
| verse | .verse | regex | yes | — | — | — | yes |
| vhdl | .vhd .vhdl .vho .vhs | regex | yes | — | — | — | yes |
| vimscript | .vim .vimrc | regex | yes | — | — | — | — |
| vue | .vue | tree-sitter | yes | yes | — | — | yes |
| wolfram | .wl .wls .m .nb | regex | yes | — | — | — | — |
| xml | .xml .xul .xsl .xslt | custom | — | yes | — | — | yes |
| yaml | .yaml .yml | custom | yes | yes | — | — | yes |
| zig | .zig .zon | tree-sitter | yes | — | — | — | yes |
Last updated: September 15, 2026