v0.4.2
Added
- Markdown support (
.md,.markdown). Headings are the symbols, nested by
level, and a symbol spans its whole section rather than the heading line, so
read_symbolwithQuick start.Connect your clientreturns that section —
839 bytes instead of this project's 20 KB README. Both#and underline
(setext) headings are indexed, a#inside a fenced code block is not, and
repeated headings receive@line:columnselectors.read_symbol,
list_symbols,search_symbols, andget_document_outlineare supported;
the semantic operations do not apply to prose and report as unsupported.
Fixed
- A registered language could be rejected by the filesystem boundary. The
set of supported extensions was written out twice — once by the provider
registry and once as a literal list inload_source— so a newly registered
language was accepted through the MCP entry point and refused through the
public API. The boundary now derives its list from the registry, and a test
asserts the two agree. - The
[.ts/.tsx/...]marker on each tool description — the only place an agent
learns which files a tool accepts — is hand-written and was a third copy of
the same set. It now has a test that derives the expectation from the
registry, which immediately caught.markdownbeing supported but never
advertised. - Python definitions guarded by control flow were missing entirely. A
function or class insideif,try,with, or a loop was absent from
get_document_outlineand unreachable byread_symbol, so the standard
try: from _fast import loads / except ImportError: def loads(...)fallback
had no addressable symbol. Python has no block scope, so these are indexed in
their enclosing module or class. - Duplicate names were unreachable outside TypeScript too. Java overloads,
repeated Goinitfunctions, and#[cfg]-gated Rust twins were listed by the
outline whileread_symbolanswered with candidates likeE.a at line 2—
a label, not a name that could be sent back. They now receive the same
@line:columnoccurrence selectors TypeScript uses, and every reported
candidate reads back. - Composing a path from an outline now resolves for Rust impl blocks:
impl Client.sendreaches the declaration whose canonical name is
Client.send. - The occurrence selector was not always unique, so some names the outline
reported still could not be read back. Running the indexer over the Go and
Python standard libraries surfaced three cases the earlier disambiguation
missed: declarations sharing one source position (var _, _ = …, both blanks
anchored to the spec), a property getter/setter pair stranded when their
enclosing class was itself disambiguated, and a top-level name whose leaf
display collided with another declaration (a Go method shown asfoobeside a
top-levelconst foo). A final uniqueness pass now closes the invariant
unconditionally — everynamedistinct, every siblingdisplay_namedistinct,
with a#ordinalwhen declarations genuinely share a position — and the Go and
Python standard libraries are exercised as real-world corpora in the test
suite.
Changed
- Tree-sitter languages (Rust, Python, Java, Go) no longer map byte offsets to
line/column by scanning from the start of the file for every declaration,
which was quadratic in file size. A 16k-declaration file went from 5.2s to
0.2s, and outline time is now linear in file size. - The embedded Tree-sitter runtime moved from 0.25 to 0.26. The bundled grammars
are unaffected — they bind throughtree-sitter-languagerather than the core
crate — and no provider behaviour changed. - Outline snapshots now cover every Tree-sitter language. They previously
covered only TypeScript, so a change in the shared Tree-sitter backend could
drop a declaration for the other providers without failing a test.
Install
curl -fsSL https://raw.githubusercontent.com/pioner92/symbolpeek-mcp/main/scripts/install.sh | shirm https://raw.githubusercontent.com/pioner92/symbolpeek-mcp/main/scripts/install.ps1 | iexThen connect the server to your client — the installer prints the exact command.
See the README for requirements and troubleshooting.
Full Changelog: v0.4.1...v0.4.2