Skip to content

Extend clangd capabilities#122

Open
mykhailopylyp wants to merge 12 commits intoisaacphi:mainfrom
mykhailopylyp:extend-clangd-capabilities
Open

Extend clangd capabilities#122
mykhailopylyp wants to merge 12 commits intoisaacphi:mainfrom
mykhailopylyp:extend-clangd-capabilities

Conversation

@mykhailopylyp
Copy link

Great project!

I tried using it with clangd, but it did not work out of the box for me. This PR was largely vibe-coded while I was working on a private project. I updated the tests for clangd and tested each utility on my project.
I hope it will be useful for the next person.

Here are the issues I encountered:

  • The LLM does not have utilities to open files (textDocument/didOpen), and tools such as references do not work because they do not accept a position argument. So I've added an optional position argument to such tools.
  • The clangd index is shared between the IDE and the MCP language server, so there is a high risk of corruption. Here is a comment describing the issue: What's the best way to let LLMs get access to clangd information? clangd/clangd#2605 (comment)
    . I fixed it by creating a symlink for compile_commands.json in the llm_lsp folder.

Finally, I added a few more tools that I think are very useful. For example, the inactive region tool is helpful for multi-target embedded projects. The get hierarchy tool is useful for understanding all possible code paths. I use it a lot when navigating a codebase, so it makes sense to give an LLM access to the same capability.

- Add optional filePath, line, character (1-based) to the references tool.
- When position is provided, call textDocument/references at that location
  instead of workspace/symbol, so references work when the file/project
  isn’t indexed yet (common with clangd).
- Introduce RefPosition and formatReferenceLocations in internal/tools/references.
- Prefer position for clangd in tool and filePath descriptions.
- Keep existing behavior when position is omitted; tests pass nil.
…for clangd

- references: add optional filePath, line, character (1-based). When set,
  call textDocument/references at that position so references work when
  workspace/symbol returns [] (e.g. clangd before indexing). Prefer
  position for clangd in tool description.
- definition: add optional filePath, line, character. When set, call
  textDocument/definition at that position so definitions work when
  workspace/symbol returns []. Prefer position for clangd in tool
  description. Add DefPosition and definitionLocationFromResult.
- lsp: in OpenFile, resolve path with filepath.Abs and filepath.ToSlash
  so the didOpen URI matches the URI used in definition/references
  requests (fixes clangd "trying to get AST for non-added document").
- Update references and definition integration tests to pass nil for
  the new position parameter. Add "References and C++/clangd" note to
  integrationtests/README.md.
…iagnostic)

- Resolve file path with filepath.Abs and use protocol.URIFromPath so the
  cache lookup URI matches the URI from textDocument/didOpen and
  publishDiagnostics (fixes empty diagnostics for paths like src/main.cpp).
- Stop calling textDocument/diagnostic; many servers (e.g. clangd) don't
  support it. Rely on the cache populated by textDocument/publishDiagnostics
  after opening the file.
Resolve filePath with filepath.Abs and use protocol.URIFromPath for the
hover request URI so it matches the document opened via textDocument/didOpen.
Fixes "trying to get AST for non-added document" when using paths like
src/main.cpp with clangd.
… clangd)

Resolve filePath with filepath.Abs and use protocol.URIFromPath for the
rename request URI so it matches the document opened via textDocument/didOpen.
Fixes "onRename called for non-added file" when using paths like src/main.cpp
with clangd.
…conflicts

When the LSP is clangd, resolve the base directory from --compile-commands-dir
(if present) or the workspace, then:
- Create llm_lsp in that base directory
- Add a symlink llm_lsp/compile_commands.json -> base/compile_commands.json
- Run clangd with --compile-commands-dir set to the llm_lsp path
- Use that base directory as the process cwd

This keeps the MCP clangd index/cache separate from the editor’s clangd so
two LSP instances do not corrupt each other’s cache.
- Add internal/tools/workspace_symbol.go: calls LSP workspace/symbol,
  returns human-readable list (name, kind, location)
- Register workspace_symbol MCP tool in tools.go with required query arg
- Add integrationtests/tests/clangd/workspace_symbol with snapshot tests
- Snapshots: foo_bar, helper

Made-with: Cursor
- Add internal/tools/document_symbol.go: open file via LSP, call
  DocumentSymbol, format DocumentSymbol[] (hierarchical) or
  SymbolInformation[] (flat) as human-readable outline (name, kind, range).
- Register document_symbol tool in tools.go with required filePath argument.
- Add clangd integration test and snapshot for src/consumer.cpp.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant