LSP bridge: goToDefinition, findReferences, workspaceSymbol always return empty
Bug Description
The built-in LSP bridge (gopls-lsp, typescript-lsp plugins) returns empty results for goToDefinition, findReferences, goToImplementation, and workspaceSymbol, while hover, documentSymbol, and incomingCalls/outgoingCalls work correctly at the same cursor position.
Environment
- Claude Code: latest (CLI)
- macOS Darwin 25.3.0 (Apple Silicon)
- gopls v0.21.1
- typescript-language-server v5.1.3
- Go 1.26.0, Node 22.19.0
Steps to Reproduce
- Install
gopls-lsp@claude-plugins-official - Open a Go project with
go.work(multi-module) - Use the LSP tool:
hoverat any symbol → works (returns type info, docs)documentSymbol→ works (lists all symbols)incomingCalls→ works (finds callers cross-file)goToDefinitionat same position → returns empty ("No definition found")findReferencesat same position → returns empty ("No references found")workspaceSymbol→ returns empty ("No symbols found")
Same behavior with typescript-lsp plugin.
Root Cause Analysis
Tested gopls directly via Python LSP client with identical parameters:
# Direct gopls test — ALL operations work
goToDefinition: ✅ returns correct location (line 20)
findReferences: ✅ 26 locations found
workspaceSymbol: ✅ 100 matches found
The gopls logs show:
- gopls sends
window/showMessage: "Loading packages..."notification - ~400ms later, sends
"Finished loading packages." - Then returns the actual result
The Claude Code LSP bridge appears to not wait for gopls to finish loading packages before reading the response. It likely reads the first response (which is a notification, not the result) and interprets the missing id match as "not found."
Operations that work (hover, documentSymbol, incomingCalls) likely trigger textDocument/didOpen internally, which forces gopls to create a file "view" synchronously. But goToDefinition/findReferences/workspaceSymbol require the full workspace to be indexed first.
Workaround
Built an MCP server (lsp-bridge) that wraps gopls/typescript-language-server/pyright with proper initialization timing — waits for "Finished loading" before sending requests. All operations work correctly through this wrapper.
Expected Behavior
All LSP operations should return correct results, matching what the language server returns when called directly.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗