> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/QwenLM/qwen-code/llms.txt
> Use this file to discover all available pages before exploring further.

# Language Server Protocol

> Integrate LSP for precise code intelligence in Qwen Code

# Language Server Protocol Integration

Qwen Code includes first-class support for the Language Server Protocol (LSP), enabling precise code navigation, intelligent symbol lookup, and advanced refactoring capabilities.

## Overview

LSP provides Qwen Code with:

* **Go to Definition**: Navigate to where symbols are defined
* **Find References**: Locate all usages of a symbol
* **Hover Information**: Get documentation and type information
* **Document Symbols**: List all symbols in a file
* **Workspace Symbols**: Search for symbols across the entire codebase
* **Go to Implementation**: Find implementations of interfaces
* **Call Hierarchy**: Analyze function call relationships
* **Diagnostics**: Access compiler/linter errors and warnings
* **Code Actions**: Get available quick fixes and refactorings

## LSP Tool Usage

The unified `lsp` tool supports all LSP operations through a single interface:

```typescript theme={null}
// Tool signature from packages/core/src/tools/lsp.ts:49
export interface LspToolParams {
  operation: LspOperation;
  filePath?: string;
  line?: number;              // 1-based
  character?: number;         // 1-based
  endLine?: number;
  endCharacter?: number;
  includeDeclaration?: boolean;
  query?: string;
  callHierarchyItem?: LspCallHierarchyItem;
  serverName?: string;
  limit?: number;
  diagnostics?: LspDiagnostic[];
  codeActionKinds?: LspCodeActionKind[];
}
```

### Supported Operations

```typescript theme={null}
type LspOperation =
  | 'goToDefinition'
  | 'findReferences'
  | 'hover'
  | 'documentSymbol'
  | 'workspaceSymbol'
  | 'goToImplementation'
  | 'prepareCallHierarchy'
  | 'incomingCalls'
  | 'outgoingCalls'
  | 'diagnostics'
  | 'workspaceDiagnostics'
  | 'codeActions';
```

## Operation Examples

### Go to Definition

Find where a symbol is defined:

```typescript theme={null}
{
  operation: "goToDefinition",
  filePath: "src/index.ts",
  line: 42,
  character: 15,
  limit: 20
}
```

**Response format** (from `lsp.ts:208`):

```
Definitions for src/index.ts:42:15:
1. src/utils/helper.ts:10:9 [typescript]
2. types/index.d.ts:5:14 [typescript]
```

### Find References

Locate all usages of a symbol:

```typescript theme={null}
{
  operation: "findReferences",
  filePath: "src/api.ts",
  line: 10,
  character: 8,
  includeDeclaration: false,  // Exclude the definition itself
  limit: 50
}
```

**Response** (from `lsp.ts:290`):

```
References for src/api.ts:10:8:
1. src/handlers/user.ts:15:3 [typescript]
2. src/routes.ts:42:20 [typescript]
3. tests/api.test.ts:8:12 [typescript]
...
```

### Hover Information

Get documentation and type info:

```typescript theme={null}
{
  operation: "hover",
  filePath: "src/models/user.ts",
  line: 25,
  character: 10
}
```

**Response** (from `lsp.ts:332`):

````
Hover for src/models/user.ts:25:10:

```typescript
function getUserById(id: string): Promise<User | null>
````

Fetches a user by their unique identifier.

@param id - The user's unique ID
@returns A promise resolving to the User object or null if not found

````

### Document Symbols

List all symbols in a file:

```typescript
{
  operation: "documentSymbol",
  filePath: "src/service.ts",
  limit: 50
}
````

**Response** (from `lsp.ts:370`):

```
Document symbols for src/service.ts:
1. UserService (Class) - src/service.ts:5:7 [typescript]
2. constructor (Constructor) in UserService - src/service.ts:8:3 [typescript]
3. getUser (Method) in UserService - src/service.ts:12:9 [typescript]
4. createUser (Method) in UserService - src/service.ts:20:9 [typescript]
...
```

### Workspace Symbol Search

Search for symbols across the workspace:

```typescript theme={null}
{
  operation: "workspaceSymbol",
  query: "handleRequest",
  limit: 20
}
```

**Response** (from `lsp.ts:415`):

```
Found 20 of 45 symbols for query "handleRequest":
1. handleRequest (Function) - src/api.ts:10:9 [typescript]
2. handleRequestError (Function) - src/errors.ts:5:9 [typescript]
3. handleRequestMiddleware (Function) - src/middleware.ts:15:9 [typescript]
...

References for top match (handleRequest):
1. src/routes.ts:25:3 [typescript]
2. src/app.ts:40:8 [typescript]
...
```

### Go to Implementation

Find implementations of an interface or abstract method:

```typescript theme={null}
{
  operation: "goToImplementation",
  filePath: "src/interfaces/storage.ts",
  line: 5,
  character: 18,
  limit: 20
}
```

**Response** (from `lsp.ts:249`):

```
Implementations for src/interfaces/storage.ts:5:18:
1. src/storage/local.ts:10:7 [typescript]
2. src/storage/s3.ts:8:7 [typescript]
3. src/storage/memory.ts:5:7 [typescript]
```

### Call Hierarchy

**Prepare Call Hierarchy** - Get callable items at a position:

```typescript theme={null}
{
  operation: "prepareCallHierarchy",
  filePath: "src/utils.ts",
  line: 30,
  character: 9,
  limit: 20
}
```

**Response** (from `lsp.ts:505`):

```
Call hierarchy items for src/utils.ts:30:9:
1. processData (Function) - src/utils.ts:30:9 [typescript]

Call hierarchy items (JSON):
[
  {
    "name": "processData",
    "kind": "function",
    "uri": "file:///workspace/src/utils.ts",
    "range": { "start": { "line": 29, "character": 0 }, "end": { "line": 45, "character": 1 } },
    "selectionRange": { "start": { "line": 29, "character": 9 }, "end": { "line": 29, "character": 20 } },
    "serverName": "typescript"
  }
]
```

**Incoming Calls** - Find callers of a function:

```typescript theme={null}
{
  operation: "incomingCalls",
  callHierarchyItem: { /* from prepareCallHierarchy */ },
  limit: 20
}
```

**Response** (from `lsp.ts:548`):

```
Incoming calls for processData at src/utils.ts:30:9:
1. handleData (Function) - src/handlers.ts:15:5 (calls at 18:3) [typescript]
2. main (Function) - src/index.ts:10:9 (calls at 25:5) [typescript]
```

**Outgoing Calls** - Find functions called by a function:

```typescript theme={null}
{
  operation: "outgoingCalls",
  callHierarchyItem: { /* from prepareCallHierarchy */ },
  limit: 20
}
```

**Response** (from `lsp.ts:602`):

```
Outgoing calls for processData at src/utils.ts:30:9:
1. validateInput (Function) - src/validators.ts:8:9 (calls at 32:3) [typescript]
2. transformData (Function) - src/transform.ts:12:9 (calls at 35:10) [typescript]
3. saveToDatabase (Function) - src/db.ts:20:9 (calls at 40:3) [typescript]
```

### Diagnostics

**File Diagnostics** - Get errors/warnings for a file:

```typescript theme={null}
{
  operation: "diagnostics",
  filePath: "src/buggy.ts"
}
```

**Response** (from `lsp.ts:660`):

```
Diagnostics for src/buggy.ts (3 issues):
1. [ERROR] 15:5 (2322) [typescript]: Type 'string' is not assignable to type 'number'.
2. [WARNING] 22:10 (6133) [typescript]: 'unusedVar' is declared but its value is never read.
3. [INFO] 30:1 (80001) [typescript]: File is a CommonJS module; it may be converted to an ES module.
```

**Workspace Diagnostics** - Get all diagnostics:

```typescript theme={null}
{
  operation: "workspaceDiagnostics",
  limit: 50
}
```

**Response** (from `lsp.ts:700`):

```
Workspace diagnostics (15 issues in 5 files):

src/app.ts [typescript]:
  [ERROR] 10:3 (2304): Cannot find name 'proces'. Did you mean 'process'?
  [WARNING] 25:5 (6133): 'tempVar' is declared but its value is never read.

src/utils.ts [typescript]:
  [ERROR] 42:8 (2345): Argument of type 'string[]' is not assignable to parameter of type 'number[]'.
...
```

### Code Actions

Get available quick fixes and refactorings:

```typescript theme={null}
{
  operation: "codeActions",
  filePath: "src/app.ts",
  line: 10,
  character: 3,
  endLine: 10,
  endCharacter: 20,
  diagnostics: [ /* errors at this location */ ],
  codeActionKinds: ["quickfix", "refactor"],
  limit: 20
}
```

**Response** (from `lsp.ts:783`):

```
Code actions at src/app.ts:10:3:
1. Change spelling to 'process' [quickfix] (has edit) [typescript]
2. Add all missing imports [quickfix] (has edit) [typescript]
3. Extract to function [refactor.extract] (has edit) [typescript]
4. Convert to arrow function [refactor.rewrite] (has edit) [typescript]
```

## Configuration

### Enabling LSP

LSP is automatically enabled when language servers are configured. The tool checks:

```typescript theme={null}
// From lsp.ts:148
const client = this.config.getLspClient();
if (!client || !this.config.isLspEnabled()) {
  return { 
    llmContent: 'LSP is unavailable (LSP disabled or not initialized)',
    returnDisplay: 'LSP is unavailable'
  };
}
```

### Server Configuration

Language servers are typically configured through:

1. **IDE Extensions**: When running in IDE mode (VS Code, etc.)
2. **Manual Configuration**: Through Qwen Code settings
3. **Auto-detection**: Based on project files

## Best Practices

### When to Use LSP

The tool description emphasizes (from `lsp.ts:1021`):

> **ALWAYS use LSP as the PRIMARY tool for code intelligence queries when available. Do NOT use grep\_search or glob first.**

Use LSP for:

* Finding symbol definitions
* Analyzing code structure
* Understanding type information
* Refactoring code
* Diagnosing errors

Avoid LSP for:

* Searching file contents by pattern (use grep)
* Finding files by name (use glob)
* Reading file contents (use read)

### Parameter Validation

From `lsp.ts:1153`, the tool validates:

```typescript theme={null}
// Location-based operations require filePath + line
if (LOCATION_REQUIRED_OPERATIONS.has(operation)) {
  if (!params.filePath || params.filePath.trim() === '') {
    return `filePath is required for ${operation}.`;
  }
  if (typeof params.line !== 'number') {
    return `line is required for ${operation}.`;
  }
}

// File-based operations require only filePath
if (FILE_REQUIRED_OPERATIONS.has(operation)) {
  if (!params.filePath || params.filePath.trim() === '') {
    return `filePath is required for ${operation}.`;
  }
}
```

### Line/Character Coordinates

**Important**: LSP uses 1-based line and character numbers in the tool interface, but converts to 0-based internally:

```typescript theme={null}
// From lsp.ts:829
const position = {
  line: Math.max(0, Math.floor(this.params.line - 1)),        // Convert to 0-based
  character: Math.max(0, Math.floor((this.params.character ?? 1) - 1))
};
```

### Result Limits

All operations support a `limit` parameter with sensible defaults:

```typescript theme={null}
// From lsp.ts:191, 232, 273, 398
const limit = this.params.limit ?? {
  goToDefinition: 20,
  findReferences: 50,
  documentSymbol: 50,
  workspaceSymbol: 20,
  // ...
};
```

## Troubleshooting

### LSP Not Available

**Problem**: Tool returns "LSP is unavailable"

**Solution**: Ensure language servers are configured:

```bash theme={null}
# Check if LSP is enabled
qwen config get lsp.enabled

# Enable LSP
qwen config set lsp.enabled true
```

### No Results Returned

**Problem**: Operations return empty results

**Possible causes**:

1. Incorrect file path (use workspace-relative or absolute paths)
2. Wrong line/character position
3. Language server not initialized for file type
4. Symbol not indexed yet

**Solution**:

```typescript theme={null}
// Use workspaceSymbol to search first
{ operation: "workspaceSymbol", query: "MyClass" }

// Then use returned location for precise lookup
{ 
  operation: "goToDefinition",
  filePath: "src/myclass.ts",  // From search result
  line: 10,
  character: 7
}
```

### Server-Specific Operations

**Problem**: Need to target specific language server

**Solution**: Use the `serverName` parameter:

```typescript theme={null}
{
  operation: "goToDefinition",
  filePath: "src/index.ts",
  line: 10,
  character: 5,
  serverName: "typescript"  // Target TypeScript LSP specifically
}
```

### Path Resolution

From `lsp.ts:847`, paths are resolved as:

```typescript theme={null}
private resolveUri(filePath: string, workspaceRoot: string): string | null {
  if (!filePath) return null;
  
  // Already a URI
  if (filePath.startsWith('file://') || filePath.includes('://')) {
    return filePath;
  }
  
  // Convert to absolute path
  const absolutePath = path.isAbsolute(filePath)
    ? filePath
    : path.resolve(workspaceRoot, filePath);
    
  // Convert to file:// URI
  return pathToFileURL(absolutePath).toString();
}
```

## Integration Examples

### Symbol Navigation Workflow

```typescript theme={null}
// 1. Search for symbol in workspace
{ operation: "workspaceSymbol", query: "UserService" }
// Returns: src/services/user.ts:10:7

// 2. Get documentation
{ 
  operation: "hover",
  filePath: "src/services/user.ts",
  line: 10,
  character: 7
}

// 3. Find all usages
{
  operation: "findReferences",
  filePath: "src/services/user.ts",
  line: 10,
  character: 7,
  includeDeclaration: false
}
```

### Error Analysis Workflow

```typescript theme={null}
// 1. Get all workspace errors
{ operation: "workspaceDiagnostics", limit: 100 }

// 2. Get errors for specific file
{ operation: "diagnostics", filePath: "src/buggy.ts" }

// 3. Get available fixes
{
  operation: "codeActions",
  filePath: "src/buggy.ts",
  line: 15,
  character: 5,
  endLine: 15,
  endCharacter: 20,
  codeActionKinds: ["quickfix"]
}
```

### Call Graph Analysis

```typescript theme={null}
// 1. Prepare call hierarchy for function
{
  operation: "prepareCallHierarchy",
  filePath: "src/api.ts",
  line: 50,
  character: 9
}
// Returns: callHierarchyItem

// 2. Find who calls this function
{
  operation: "incomingCalls",
  callHierarchyItem: { /* from step 1 */ },
  limit: 50
}

// 3. Find what this function calls
{
  operation: "outgoingCalls",
  callHierarchyItem: { /* from step 1 */ },
  limit: 50
}
```

## Source Code References

* LSP tool implementation: `packages/core/src/tools/lsp.ts`
* LSP types: `packages/core/src/lsp/types.ts`
* Configuration: `packages/core/src/config/config.ts:64`
