[BUG] LSP workspaceSymbol Implementation Violates LSP Specification
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Claude Code's LSP tool incorrectly implements the Microsoft Language Server Protocol specification for multiple operations. The tool forces a uniform interface (filePath, line, character) for ALL 9 LSP operations, but the LSP specification defines different parameter types for different operations.
Violations Found (4 out of 9 operations):
CRITICAL - Operation 5: workspaceSymbol
- Requires:
filePath,line,character(all wrong) - Missing:
queryparameter (the only one that should exist) - LSP Spec: Should accept ONLY
query: stringto search symbols by name - Impact: Cannot search for symbols across workspace by name - primary LSP use case is completely broken
HIGH - Operations 8-9: incomingCalls / outgoingCalls
- Requires:
filePath,line,character(wrong type) - Should require:
item: CallHierarchyItem(object from prepareCallHierarchy) - LSP Spec: Should accept the CallHierarchyItem returned by prepareCallHierarchy
- Impact: Cannot properly chain call hierarchy operations per spec
MEDIUM - Operation 4: documentSymbol
- Requires:
filePath,line,character - Should require:
textDocument(URI) only, no position - LSP Spec: Position parameters not required for document-level symbol listing
- Impact: Operation works but forces unnecessary parameters
MEDIUM - Operation 2: findReferences
- Missing:
context.includeDeclarationparameter - LSP Spec: Should include optional context for including/excluding declarations
- Impact: Cannot control whether to include symbol declarations in results
Working Correctly (5 out of 9 operations):
Operations 1, 3, 6, 7 (goToDefinition, hover, goToImplementation, prepareCallHierarchy) correctly map to LSP's TextDocumentPositionParams pattern.
What Should Happen?
Each LSP operation should follow the Microsoft Language Server Protocol specification exactly:
Operation 1: goToDefinition (textDocument/definition)
interface TextDocumentPositionParams {
textDocument: TextDocumentIdentifier; // { uri: string }
position: Position; // { line: number, character: number }
}
Current: ✅ Works correctly (filePath maps to uri, line/character map to position)
Operation 2: findReferences (textDocument/references)
interface ReferenceParams extends TextDocumentPositionParams {
context: ReferenceContext; // { includeDeclaration: boolean }
}
Should accept: filePath, line, character, includeDeclaration (optional boolean)
Operation 3: hover (textDocument/hover)
interface HoverParams extends TextDocumentPositionParams {
// Same as TextDocumentPositionParams
}
Current: ✅ Works correctly
Operation 4: documentSymbol (textDocument/documentSymbol)
interface DocumentSymbolParams {
textDocument: TextDocumentIdentifier; // { uri: string }
// NO position required!
}
Should accept: filePath only (line/character should be optional)
Operation 5: workspaceSymbol (workspace/symbol)
interface WorkspaceSymbolParams {
query: string; // Search term for symbols
// NO textDocument or position!
}
Should accept: query only (no filePath, line, or character)
Operation 6: goToImplementation (textDocument/implementation)
interface ImplementationParams extends TextDocumentPositionParams {
// Same as TextDocumentPositionParams
}
Current: ✅ Works correctly
Operation 7: prepareCallHierarchy (textDocument/prepareCallHierarchy)
interface CallHierarchyPrepareParams extends TextDocumentPositionParams {
// Same as TextDocumentPositionParams
}
Current: ✅ Works correctly
Operation 8: incomingCalls (callHierarchy/incomingCalls)
interface CallHierarchyIncomingCallsParams {
item: CallHierarchyItem; // NOT a document position!
}
Should accept: item (CallHierarchyItem object from prepareCallHierarchy)
Operation 9: outgoingCalls (callHierarchy/outgoingCalls)
interface CallHierarchyOutgoingCallsParams {
item: CallHierarchyItem; // NOT a document position!
}
Should accept: item (CallHierarchyItem object from prepareCallHierarchy)
Error Messages/Logs
### workspaceSymbol Tests (Operation 5)
# Test 1: Omit filePath (should work per spec with just query)
LSP.workspaceSymbol(operation: "workspaceSymbol", line: 1, character: 1)
# Error:
InputValidationError: LSP failed due to the following issue:
The required parameter `filePath` is missing
# Test 2: Use directory path (workspace-level search)
LSP.workspaceSymbol(filePath: "/path/to/project", line: 1, character: 1)
# Error:
Path is not a file: /path/to/project
# Test 3: Use wildcard pattern
LSP.workspaceSymbol(filePath: "/path/to/project/*.ts", line: 1, character: 1)
# Error:
File does not exist: /path/to/project/*.ts
# Test 4: Use recursive glob
LSP.workspaceSymbol(filePath: "/path/to/project/**/*.ts", line: 1, character: 1)
# Error:
File does not exist: /path/to/project/**/*.ts
# Test 5: Use search term as filePath
LSP.workspaceSymbol(filePath: "myFunction", line: 1, character: 1)
# Error:
File does not exist: myFunction
# Test 6: Use valid file (only way that works)
LSP.workspaceSymbol(filePath: "/path/to/file.ts", line: 1, character: 1)
# Result:
Found 2 symbols in workspace:
functionA (Function) - Line 5
variableB (Constant) - Line 10
# Problem: Returns ALL symbols unfiltered, no way to search for specific symbol
### documentSymbol Tests (Operation 4)
# Test 1: With position (currently required)
LSP.documentSymbol(filePath: "/path/to/file.ts", line: 1, character: 1)
# Result:
Document symbols:
greet (Function) - Line 2
result (Constant) - Line 7
# Works but position shouldn't be required
# Test 2: Without position (should work per spec)
LSP.documentSymbol(filePath: "/path/to/file.ts")
# Error:
InputValidationError: LSP failed due to the following issue:
The required parameter `line` is missing
### All Operations: Wildcard/Directory Pattern Tests
# Tested patterns on ALL 9 operations:
# Pattern: *
Error: File does not exist: *
# Pattern: ./
Error: Path is not a file: ./
# Pattern: .
Error: Path is not a file: .
# Pattern: /path/to/workspace
Error: Path is not a file: /path/to/workspace
# Pattern: /path/to/workspace/*
Error: File does not exist: /path/to/workspace/*
# Pattern: /path/to/workspace/**/*
Error: File does not exist: /path/to/workspace/**/*
# Pattern: ~/workspace/**/*.ts
Error: File does not exist: ~/workspace/**/*.ts
# Conclusion: ALL operations reject directories and wildcards
# Only accept specific, existing file paths
Steps to Reproduce
Setup
- Install Claude Code v2.1.23 or later
- Install LSP plugins from official marketplace:
```bash
# Check available plugins
claude plugin search lsp
# Install TypeScript LSP
claude plugin install typescript-lsp@claude-plugins-official
```
- Install the actual language server binary:
``bash``
npm install -g typescript-language-server typescript
- Verify LSP tool is available (restart Claude Code if needed)
Test 1: workspaceSymbol - Missing filePath
// Per LSP spec, should accept only query parameter
LSP.workspaceSymbol(
operation: "workspaceSymbol",
line: 1,
character: 1
)
// Expected: Should accept query parameter to search by symbol name
// Actual: Error - "InputValidationError: The required parameter `filePath` is missing"
Test 2: workspaceSymbol - Directory Path
// Try workspace-level search with directory
LSP.workspaceSymbol(
operation: "workspaceSymbol",
filePath: "/Users/username/workspace",
line: 1,
character: 1
)
// Expected: Should search across workspace directory
// Actual: Error - "Path is not a file: /Users/username/workspace"
Test 3: workspaceSymbol - Wildcard Pattern
// Try with glob pattern
LSP.workspaceSymbol(
operation: "workspaceSymbol",
filePath: "/Users/username/workspace/**/*.ts",
line: 1,
character: 1
)
// Expected: Should search across matching files
// Actual: Error - "File does not exist: /Users/username/workspace/**/*.ts"
Test 4: workspaceSymbol - Search Term as Path
// Try using what should be a query as filePath
LSP.workspaceSymbol(
operation: "workspaceSymbol",
filePath: "authenticate",
line: 1,
character: 1
)
// Expected: "authenticate" should be treated as search query
// Actual: Error - "File does not exist: authenticate"
Test 5: workspaceSymbol - Valid File (Only Way That Works)
// Must provide specific file path
LSP.workspaceSymbol(
operation: "workspaceSymbol",
filePath: "/Users/username/workspace/src/file.ts",
line: 1,
character: 1
)
// Result: Returns ALL symbols unfiltered
// Problem: No way to specify which symbol to search for
Test 6: documentSymbol - Without Position
// Per LSP spec, position not required for documentSymbol
LSP.documentSymbol(
operation: "documentSymbol",
filePath: "/Users/username/workspace/src/file.ts"
)
// Expected: Should work with just file path
// Actual: Error - "InputValidationError: The required parameter `line` is missing"
Test 7: Verify All 9 Operations Require File Path
// Try each operation without filePath:
const operations = [
"goToDefinition",
"findReferences",
"hover",
"documentSymbol",
"workspaceSymbol",
"goToImplementation",
"prepareCallHierarchy",
"incomingCalls",
"outgoingCalls"
];
operations.forEach(op => {
LSP[op](operation: op, line: 1, character: 1);
// All return: "InputValidationError: The required parameter `filePath` is missing"
});
Claude Model
Sonnet (default)
Is this a regression?
No, this never worked
Last Working Version
_No response_
Claude Code Version
2.1.23
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
Background: No Official LSP Tool Documentation
IMPORTANT: There is currently no official documentation for the LSP tool's parameters or usage. The official Claude Code team has acknowledged:
"Support for LSP in Claude Code is pretty raw still. There are bugs in the different LSP operations, no documentation, and no UI indication that your LSP servers are started/running/have errors or even exist."
What We Know from Actual Testing:
Through extensive testing, we've determined that Claude Code's LSP tool currently requires for ALL 9 operations:
filePath(string) - Must be an existing file pathline(number) - Position line numbercharacter(number) - Position character offset
Validation behavior observed:
- Rejects directories:
Path is not a file: /path/to/dir - Rejects wildcards:
File does not exist: *.ts - Requires exact file paths for ALL operations, including
workspaceSymbol
The Core Issue:
The current implementation forces a uniform interface (file path + position) for ALL operations, which contradicts the Microsoft LSP specification. Different LSP operations are designed to accept different parameter types.
Related Official Information:
- LSP Feature Added: v2.0.74 (Dec 2024)
- Official Docs: https://code.claude.com/docs/en/plugins-reference (covers LSP server configuration only)
- GitHub Issues: Multiple reports of LSP tool bugs (#14803, #16291, #17312)
---
Detailed Comparison: LSP Spec vs Claude Code (All 9 Operations)
1. goToDefinition (textDocument/definition)
LSP Specification:
interface TextDocumentPositionParams {
textDocument: TextDocumentIdentifier; // { uri: string }
position: Position; // { line: number, character: number }
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "goToDefinition",
filePath: string, // ✅ Correct (maps to textDocument.uri)
line: number, // ✅ Correct (maps to position.line)
character: number // ✅ Correct (maps to position.character)
}
Status: ✅ Correct (tested and working)
---
2. findReferences (textDocument/references)
LSP Specification:
interface ReferenceParams extends TextDocumentPositionParams {
context: ReferenceContext; // { includeDeclaration: boolean }
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "findReferences",
filePath: string, // ✅ Correct (maps to textDocument.uri)
line: number, // ✅ Correct (maps to position.line)
character: number // ✅ Correct (maps to position.character)
// ❌ MISSING: context parameter
}
Status: ⚠️ Incomplete (missing context.includeDeclaration option)
---
3. hover (textDocument/hover)
LSP Specification:
interface HoverParams extends TextDocumentPositionParams {
// Same as TextDocumentPositionParams
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "hover",
filePath: string, // ✅ Correct (maps to textDocument.uri)
line: number, // ✅ Correct (maps to position.line)
character: number // ✅ Correct (maps to position.character)
}
Status: ✅ Correct
---
4. documentSymbol (textDocument/documentSymbol)
LSP Specification:
interface DocumentSymbolParams {
textDocument: TextDocumentIdentifier; // { uri: string }
// NO position required!
}
Claude Code Implementation:
📋 Actual Test Results:
// Test 1: With position (currently required)
LSP.documentSymbol(filePath: "/path/to/file.ts", line: 1, character: 1)
// Result: Works, returns symbols: "greet (Function) - Line 2, result (Constant) - Line 7"
// Test 2: Without position (should work per spec)
LSP.documentSymbol(filePath: "/path/to/file.ts")
// Error: "InputValidationError: The required parameter `line` is missing"
Required parameters:
{
operation: "documentSymbol",
filePath: string, // ✅ Correct (maps to textDocument.uri)
line: number, // ❌ NOT REQUIRED BY SPEC
character: number // ❌ NOT REQUIRED BY SPEC
}
Status: ❌ WRONG - Requires unnecessary line and character parameters
Impact: Minor (operation works but forces unnecessary parameters)
---
5. workspaceSymbol (workspace/symbol)
LSP Specification:
interface WorkspaceSymbolParams {
query: string; // Search term for symbols
// NO textDocument or position!
}
Claude Code Implementation:
📋 Actual Test Results:
// Test 1: Omit filePath
LSP.workspaceSymbol(operation: "workspaceSymbol", line: 1, character: 1)
// Error: "InputValidationError: The required parameter `filePath` is missing"
// Test 2: Use directory path
LSP.workspaceSymbol(filePath: "/path/to/project", line: 1, character: 1)
// Error: "Path is not a file: /path/to/project"
// Test 3: Use wildcard
LSP.workspaceSymbol(filePath: "/path/to/project/*.ts", line: 1, character: 1)
// Error: "File does not exist: /path/to/project/*.ts"
// Test 4: Use search term as filePath
LSP.workspaceSymbol(filePath: "myFunction", line: 1, character: 1)
// Error: "File does not exist: myFunction"
// Test 5: Use valid file (only way that works)
LSP.workspaceSymbol(filePath: "/path/to/file.ts", line: 1, character: 1)
// Result: Returns ALL symbols unfiltered, no way to search for specific symbol
Required parameters:
{
operation: "workspaceSymbol",
filePath: string, // ❌ NOT IN SPEC
line: number, // ❌ NOT IN SPEC
character: number // ❌ NOT IN SPEC
// ❌ MISSING: query parameter (the only one that should exist!)
}
Status: ❌ COMPLETELY WRONG - Requires wrong parameters, missing required parameter
Impact: CRITICAL - Operation is completely unusable for its intended purpose
---
6. goToImplementation (textDocument/implementation)
LSP Specification:
interface ImplementationParams extends TextDocumentPositionParams {
// Same as TextDocumentPositionParams
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "goToImplementation",
filePath: string, // ✅ Correct (maps to textDocument.uri)
line: number, // ✅ Correct (maps to position.line)
character: number // ✅ Correct (maps to position.character)
}
Status: ✅ Correct
---
7. prepareCallHierarchy (textDocument/prepareCallHierarchy)
LSP Specification:
interface CallHierarchyPrepareParams extends TextDocumentPositionParams {
// Same as TextDocumentPositionParams
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "prepareCallHierarchy",
filePath: string, // ✅ Correct (maps to textDocument.uri)
line: number, // ✅ Correct (maps to position.line)
character: number // ✅ Correct (maps to position.character)
}
Status: ✅ Correct
---
8. incomingCalls (callHierarchy/incomingCalls)
LSP Specification:
interface CallHierarchyIncomingCallsParams {
item: CallHierarchyItem; // NOT a document position!
}
interface CallHierarchyItem {
name: string;
kind: SymbolKind;
uri: DocumentUri;
range: Range;
selectionRange: Range;
// ... other fields
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "incomingCalls",
filePath: string, // ❌ WRONG TYPE (should be CallHierarchyItem)
line: number, // ❌ WRONG TYPE (should be CallHierarchyItem)
character: number // ❌ WRONG TYPE (should be CallHierarchyItem)
}
Status: ❌ WRONG - Should accept CallHierarchyItem, not file position
Impact: HIGH - Operation may work by accident but doesn't follow spec
---
9. outgoingCalls (callHierarchy/outgoingCalls)
LSP Specification:
interface CallHierarchyOutgoingCallsParams {
item: CallHierarchyItem; // NOT a document position!
}
Claude Code Implementation:
📋 Tested: Works correctly with file path and position
{
operation: "outgoingCalls",
filePath: string, // ❌ WRONG TYPE (should be CallHierarchyItem)
line: number, // ❌ WRONG TYPE (should be CallHierarchyItem)
character: number // ❌ WRONG TYPE (should be CallHierarchyItem)
}
Status: ❌ WRONG - Should accept CallHierarchyItem, not file position
Impact: HIGH - Operation may work by accident but doesn't follow spec
---
Summary Table
| Operation | LSP Spec Parameters | Claude Code Parameters | Status |
|-----------|---------------------|------------------------|--------|
| 1. goToDefinition | textDocument, position | filePath, line, character | ✅ Correct |
| 2. findReferences | textDocument, position, context | filePath, line, character | ⚠️ Missing context |
| 3. hover | textDocument, position | filePath, line, character | ✅ Correct |
| 4. documentSymbol | textDocument only | filePath, line, character | ❌ Extra params |
| 5. workspaceSymbol | query only | filePath, line, character | ❌ WRONG |
| 6. goToImplementation | textDocument, position | filePath, line, character | ✅ Correct |
| 7. prepareCallHierarchy | textDocument, position | filePath, line, character | ✅ Correct |
| 8. incomingCalls | item (CallHierarchyItem) | filePath, line, character | ❌ WRONG |
| 9. outgoingCalls | item (CallHierarchyItem) | filePath, line, character | ❌ WRONG |
Issues Found: 4 operations with violations
---
Proof: VS Code's Implementation (Microsoft Reference Implementation)
Microsoft's VS Code correctly implements the LSP specification. Here's proof from their actual source code:
Repository: https://github.com/microsoft/vscode-languageserver-node (Official Microsoft LSP implementation for VS Code)
---
Operations 1-3, 6-7: TextDocumentPositionParams
VS Code Implementation:
📖 Source: https://github.com/microsoft/vscode-languageserver-node/blob/main/protocol/src/common/protocol.ts
interface TextDocumentPositionParams {
textDocument: TextDocumentIdentifier; // { uri: string }
position: Position; // { line: number, character: number }
}
✅ Uses: textDocument (URI) + position (line, character)
✅ Matches LSP Spec: Exactly
✅ Claude Code: Matches (uses filePath/line/character)
---
Operation 4: documentSymbol - ONLY textDocument, NO position
VS Code Implementation:
const params: DocumentSymbolParams = {
textDocument: { uri: 'file:///abc.txt' }
// NO position parameter!
};
✅ Uses: ONLY textDocument (URI)
✅ Matches LSP Spec: Exactly
❌ Claude Code: Forces unnecessary line and character parameters
---
Operation 5: workspaceSymbol - ONLY query, NO file/position
VS Code Implementation:
const params: WorkspaceSymbolParams = {
query: query // ONLY query string!
};
const symbols: LocalizeSymbolInformation[] =
await this.client.languageClient.sendRequest(GetSymbolInfoRequest, params, token);
✅ Uses: ONLY query (search string)
✅ Matches LSP Spec: Exactly
❌ Claude Code: Requires filePath, line, character - missing query entirely
---
Operations 8-9: incomingCalls/outgoingCalls - item (CallHierarchyItem), NOT file/position
VS Code Implementation:
export interface CallHierarchyIncomingCallsParams
extends WorkDoneProgressParams, PartialResultParams {
item: CallHierarchyItem; // NOT a file position!
}
export interface CallHierarchyOutgoingCallsParams
extends WorkDoneProgressParams, PartialResultParams {
item: CallHierarchyItem; // NOT a file position!
}
✅ Uses: item (CallHierarchyItem object from prepareCallHierarchy)
✅ Matches LSP Spec: Exactly
❌ Claude Code: Requires filePath, line, character instead of CallHierarchyItem
---
Proof: Neovim's Implementation
Neovim also correctly implements the LSP specification:
Repository: https://github.com/neovim/neovim
Operation 5: workspaceSymbol
Neovim Implementation:
📖 Source: https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/buf.lua
function M.workspace_symbol(query, opts)
local params = { query = query } -- ONLY query string!
request_with_opts('workspace/symbol', params, opts)
end
Handler:
📖 Source: https://github.com/neovim/neovim/blob/master/runtime/lua/vim/lsp/handlers.lua
RCS['workspace/symbol'] = response_to_list(util.symbols_to_items, 'symbols', function(ctx)
return string.format("Symbols matching '%s'", ctx.params.query) -- Uses query from params
end)
✅ Uses: ONLY query (search string)
✅ Matches LSP Spec: Exactly
❌ Claude Code: Requires filePath, line, character - missing query entirely
---
Summary: VS Code & Neovim vs Claude Code
| Operation | VS Code/Neovim Parameters | Claude Code Parameters | Match? |
|-----------|---------------------------|------------------------|--------|
| 1-3, 6-7 | textDocument, position | filePath, line, character | ✅ Equivalent |
| 4 (documentSymbol) | textDocument only | filePath, line, character | ❌ Extra params |
| 5 (workspaceSymbol) | query only | filePath, line, character | ❌ WRONG |
| 8-9 (incoming/outgoingCalls) | item (CallHierarchyItem) | filePath, line, character | ❌ WRONG |
Conclusion: Both Microsoft's VS Code and Neovim (the two major LSP reference implementations) prove Claude Code's violations of the LSP specification.
---
Impact Analysis
High Severity Issues
1. workspaceSymbol (CRITICAL)
- ❌ Cannot search for symbols by name across workspace
- ❌ Primary use case is completely broken
- ❌ Forces fallback to text-based grep instead of semantic search
- ❌ Defeats the core value proposition of LSP integration
2. incomingCalls / outgoingCalls (HIGH)
- ❌ Wrong parameter type (should be CallHierarchyItem)
- ⚠️ May work by accident in simple cases
- ❌ Cannot be used in complex scenarios requiring CallHierarchyItem data
Medium Severity Issues
3. documentSymbol (MEDIUM)
- ⚠️ Requires unnecessary position parameters
- ✅ Still functions correctly despite extra parameters
4. findReferences (MEDIUM)
- ⚠️ Missing
context.includeDeclarationoption - ✅ Works for basic use cases
---
Use Case Examples
Example 1: Finding a function across workspace
User request: "Find the authenticate function in my project"
What should work (per LSP spec):
LSP.workspaceSymbol(query: "authenticate")
// Returns: Symbol locations across entire workspace
What actually happens:
Error: The required parameter `filePath` is missing
Workaround: Must use grep/text search instead
---
Example 2: Getting call hierarchy
User request: "Show me what calls this function"
What should work (per LSP spec):
// Step 1: Prepare call hierarchy at a position
const item = LSP.prepareCallHierarchy(
filePath: "file.ts",
line: 10,
character: 5
)
// Returns: CallHierarchyItem
// Step 2: Get incoming calls using that item
LSP.incomingCalls(item: item)
// Should accept the CallHierarchyItem from step 1
What Claude Code forces:
// Step 1: Works correctly
const item = LSP.prepareCallHierarchy(
filePath: "file.ts",
line: 10,
character: 5
)
// Returns: "Call hierarchy item: greet (Function) - file.ts:1"
// Step 2: Cannot use the item
LSP.incomingCalls(filePath: "file.ts", line: 10, character: 5)
// Must provide position again, cannot pass CallHierarchyItem
// Works by accident but doesn't follow spec
---
Expected Behavior Per LSP Specification
Example 1: Workspace Symbol Search
Per LSP Spec: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_symbol
// What should work:
LSP.workspaceSymbol(query: "authenticate")
// Should return symbols matching "authenticate" from across the workspace
// Response: Array of SymbolInformation with locations
Current Claude Code Behavior (tested):
// What's currently required:
LSP.workspaceSymbol(filePath: "/path/to/file.ts", line: 1, character: 1)
// Returns: ALL symbols unfiltered, no way to search by name
// Cannot specify what symbol to search for
---
Example 2: Call Hierarchy
Per LSP Spec: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#callHierarchy_incomingCalls
// Step 1: Prepare call hierarchy at a position
const item = LSP.prepareCallHierarchy(
filePath: "file.ts",
line: 10,
character: 5
)
// Returns: CallHierarchyItem
// Step 2: Get incoming calls using that item
LSP.incomingCalls(item: item)
// Should accept the CallHierarchyItem from step 1
Current Claude Code Behavior (tested):
// Step 1: Works correctly
const item = LSP.prepareCallHierarchy(
filePath: "file.ts",
line: 10,
character: 5
)
// Returns: "Call hierarchy item: greet (Function) - test-lsp.ts:1"
// Step 2: Cannot use the item
LSP.incomingCalls(filePath: "file.ts", line: 10, character: 5)
// Must provide position again, cannot pass CallHierarchyItem
// Works by accident but doesn't follow spec
---
Suggested Fixes
1. workspaceSymbol (CRITICAL)
Remove:
filePathrequirementlinerequirementcharacterrequirement
Add:
queryparameter (required string)
Example:
{
operation: "workspaceSymbol",
query: "authenticate" // NEW: The symbol name to search for
}
---
2. incomingCalls / outgoingCalls (HIGH)
Change parameters to accept CallHierarchyItem:
Option A: Accept CallHierarchyItem directly
{
operation: "incomingCalls",
item: CallHierarchyItem // From prepareCallHierarchy result
}
Option B: Keep current interface but auto-resolve
{
operation: "incomingCalls",
filePath: string,
line: number,
character: number
}
// Internally: call prepareCallHierarchy first, then incomingCalls
---
3. documentSymbol (MEDIUM)
Make position parameters optional:
{
operation: "documentSymbol",
filePath: string,
line?: number, // OPTIONAL
character?: number // OPTIONAL
}
---
4. findReferences (MEDIUM)
Add context parameter:
{
operation: "findReferences",
filePath: string,
line: number,
character: number,
includeDeclaration?: boolean // NEW: Default to true
}
---
References
Claude Code Official Resources
- Plugins Reference (LSP configuration): https://code.claude.com/docs/en/plugins-reference
- GitHub Repository: https://github.com/anthropics/claude-code
- Changelog (LSP added in v2.0.74): https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md
- Official LSP Plugins: https://github.com/anthropics/claude-plugins-official
Microsoft LSP Specification Documentation
- LSP 3.17 Main Spec: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
- LSP 3.14 Spec: https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/
- LSP 3.15 Spec: https://microsoft.github.io/language-server-protocol/specifications/specification-3-15/
- LSP GitHub: https://github.com/microsoft/language-server-protocol
Specific Operations
- textDocument/definition: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_definition
- textDocument/references: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references
- textDocument/hover: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover
- textDocument/documentSymbol: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol
- workspace/symbol: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_symbol
- textDocument/implementation: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_implementation
- Call Hierarchy (3.16+): https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/
Related Issues
- #14803 - LSP race condition (fixed in v2.1.0+)
- #17312 - LSP empty results on Windows
---
Priority
CRITICAL: workspaceSymbol - Makes workspace-level symbol discovery impossible
HIGH: incomingCalls/outgoingCalls - Wrong parameter types violate spec
MEDIUM: documentSymbol, findReferences - Minor spec violations, operations still functional
---
Root Cause Analysis
The Problem: Claude Code's LSP Tool implementation forces a uniform interface (filePath, line, character) for ALL 9 LSP operations. This "one size fits all" approach violates the Microsoft LSP specification, which defines different parameter structures for different operations.
Why This Matters:
The LSP specification was designed with different parameter types for good reasons:
- Document-level operations (documentSymbol) don't need a position - they scan the entire document
- Workspace-level operations (workspaceSymbol) don't need a file - they search across all files
- Hierarchy operations (incomingCalls/outgoingCalls) need the result object from a previous operation - not a file position
By forcing all operations to use file + position, Claude Code:
- Makes workspace-level search impossible (no way to specify search query)
- Breaks operation chaining (can't pass CallHierarchyItem between operations)
- Forces unnecessary parameters (documentSymbol doesn't need position)
The Fix: Align each LSP operation with its specification-defined parameter structure.
---
Note: This issue affects the core value proposition of LSP integration. Users expect LSP to provide semantic code intelligence (understanding symbols, types, and relationships), but the current implementation forces users to fall back to text-based search tools (grep) for workspace-level operations.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗