Skip to content

LSP (Language Server Protocol) Integration

Version: 1.0 Last updated: 2026-01-26


Introduction

LSP integration allows mcp-scan to communicate with language servers like Pyright (Python), typescript-language-server (TypeScript/JavaScript), and gopls (Go). This provides:

  • Type-aware analysis: Detection based on real types, not just patterns
  • Precise call graphs: Building call graphs using server information
  • Symbol resolution: Precise tracking of definitions and references
  • Dangerous type detection: Identification of Any, object, unknown

Architecture

+---------------------------------------------------------------------+
|                         mcp-scan                                     |
|  +---------------------------------------------------------------+  |
|  |                      LSP Manager                               |  |
|  |  +-------------+ +-------------+ +-------------+               |  |
|  |  |   Python    | | TypeScript  | |     Go      |               |  |
|  |  |   Client    | |   Client    | |   Client    |               |  |
|  |  +------+------+ +------+------+ +------+------+               |  |
|  +---------+---------------+---------------+-------------------------+
+------------+---------------+---------------+--------------------------+
             |               |               |
    JSON-RPC |      JSON-RPC |      JSON-RPC |
    (stdio)  |       (stdio) |       (stdio) |
             |               |               |
    +--------v--------+ +----v-----+ +-------v-------+
    |     Pyright     | | tsserver | |     gopls     |
    |  (subprocess)   | |(subproc) | |  (subprocess) |
    +-----------------+ +----------+ +---------------+

Communication Protocol

LSP uses JSON-RPC 2.0 over stdio:

  1. Requests: Client sends method + params, server responds
  2. Notifications: Client sends without expecting response
  3. Headers: Content-Length: N\r\n\r\n{json}

Installation Requirements

Supported Language Servers

Language Server Command
Python Pyright pyright-langserver --stdio
TypeScript typescript-language-server typescript-language-server --stdio
JavaScript typescript-language-server typescript-language-server --stdio
Go gopls gopls serve

Server Installation

Python (Pyright)

# With npm (recommended)
npm install -g pyright

# Verify installation
pyright-langserver --version

Note: Pyright requires Node.js 14+.

TypeScript/JavaScript

# Install typescript-language-server and typescript
npm install -g typescript typescript-language-server

# Verify installation
typescript-language-server --version

Go (gopls)

# Install gopls
go install golang.org/x/tools/gopls@latest

# Verify it's in PATH
# If ~/go/bin is not in PATH, add it:
export PATH=$PATH:~/go/bin

# Verify installation
gopls version

Search Locations

mcp-scan searches for servers in these locations:

  1. System $PATH
  2. ~/go/bin (Go binaries)
  3. ~/.local/bin
  4. /usr/local/bin
  5. /opt/homebrew/bin (macOS ARM)
  6. ~/.npm-global/bin
  7. ~/node_modules/.bin

CLI Usage

Enable LSP

# Scan with LSP enabled
mcp-scan scan --lsp ./my-mcp-server

# Scan with LSP debug mode
LSP_DEBUG=1 mcp-scan scan --lsp ./my-mcp-server

YAML Configuration

# .mcp-scan.yaml
lsp:
  enabled: true
  languages:
    - python
    - typescript
    - javascript
    - go

Progress Output

[*] Scanning ./my-mcp-server...
[*] LSP: enabled
[*] Discovered 5 files
[*] Running pattern analysis...
[+] Scan completed in 2.3s
[+] Found 3 findings (2 high, 1 medium)

Debug Mode

With LSP_DEBUG=1:

[LSP] Found 5 symbols, 4 functions in server.py
[LSP] Analyzing tool get_company_data at server.py:31:4
[LSP]   type: (function) def get_company_data(data_type: str) -> str
[LSP]   call graph: get_company_data -> 1 callees

LSP Engine Capabilities

Supported Operations

Operation LSP Method Use
Hover textDocument/hover Get types and documentation
Definition textDocument/definition Go to definition
References textDocument/references Find all references
Document Symbols textDocument/documentSymbol List file symbols
Call Hierarchy textDocument/prepareCallHierarchy Prepare call hierarchy
Incoming Calls callHierarchy/incomingCalls Who calls a function
Outgoing Calls callHierarchy/outgoingCalls What a function calls

Detection Flow

1. Identify Tool Handler
         |
         v
2. Open document in LSP server
         |
         v
3. Get document symbols (GetDocumentSymbols)
         |
         v
4. Find handler function by name
         |
         v
5. Get type with hover on SelectionRange
         |
         v
6. Check for dangerous types (Any, object, unknown)
         |
         v
7. Build call graph from handler
         |
         v
8. Search for dangerous sinks in the graph
         |
         v
9. Generate findings with type context
         |
         v
10. Close document

LSP Detection Rules

LSP-TYPE-001: Dangerous Type Pattern

Severity: Medium Confidence: Medium

Detects when a tool handler has a dangerous type like Any, object, or unknown.

# DETECTED: parameter with Any type
from typing import Any

@mcp.tool()
async def process_data(data: Any):  # LSP-TYPE-001
    # data can be anything
    eval(str(data))

Dangerous types:

Type Language Risk
Any Python No type checking
object Python/TS Generic, no restrictions
unknown TypeScript Unsafe type
any TypeScript No type checking

LSP-TYPE-002: Parameter with Loose Type

Severity: Low Confidence: Medium

Detects parameters in the tool schema with loose types.

@mcp.tool(
    schema={
        "properties": {
            "data": {"type": "object"}  # LSP-TYPE-002
        }
    }
)
async def process(data):
    pass

LSP-SINK-001: Tool Input Reaches Dangerous Sink

Severity: High Confidence: Medium

Detects when a tool handler can reach a dangerous sink through the call graph.

@mcp.tool()
async def execute_command(cmd: str):
    # LSP builds call graph and finds path to os.system
    helper(cmd)

def helper(command):
    run_shell(command)

def run_shell(cmd):
    os.system(cmd)  # LSP-SINK-001: Dangerous sink reached

Tracked dangerous sinks:

Sink Type Language
os.system Command execution Python
subprocess.run Command execution Python
subprocess.Popen Command execution Python
eval Code evaluation Python/JS
exec Code execution Python
open File access Python
sqlite3.execute SQL execution Python
cursor.execute SQL execution Python
requests.get HTTP request Python
urllib.request HTTP request Python
child_process.exec Command execution Node.js
child_process.spawn Command execution Node.js

Call Graph Construction

Algorithm

1. PrepareCallHierarchy at handler position
         |
         v
2. Create root node with symbol information
         |
         v
3. For each depth up to maxDepth:
   |
   +-- GetOutgoingCalls from current node
   |         |
   |         v
   +-- For each call:
   |   |
   |   +-- Create node for the callee
   |   |
   |   +-- Add edge with call sites
   |   |
   |   +-- Recurse if not visited
   |
   +-- Mark node as visited

Analysis Depth

Depth Use Case
1-2 Quick checks, direct calls only
3-5 Standard analysis, covers most vulnerabilities
5-10 Deep analysis, complex call chains
10+ Exhaustive analysis, performance impact

Default: mcp-scan uses depth 5.


Performance

Startup Times

Server Cold start With cache
Pyright 2-5s <100ms
tsserver 1-3s <100ms
gopls 1-2s <100ms

Memory Usage

Server Base memory Per 1000 files
Pyright ~150MB +50MB
tsserver ~200MB +80MB
gopls ~100MB +30MB

Optimizations

  1. Client cache: The manager keeps active clients between analyses
  2. Document opened once: Opened at start and closed at end
  3. Visitation tracking: Call graph doesn't revisit already visited nodes

Integration with Other Engines

With Pattern Engine

LSP complements pattern rules by providing type context:

Pattern Engine          LSP Detector
      |                      |
      | Detects call         | Verifies type
      | to subprocess.run    | of argument
      |                      |
      +----------+-----------+
                 |
                 v
         Combined finding:
         - Pattern: MCP-A001
         - LSP: str type verified
         - Confidence: HIGH

With Taint Engine

LSP improves taint analysis precision:

Taint Engine                    LSP
      |                          |
      | Detects flow             | Gets types
      | source -> sink           | at each step
      |                          |
      | May lose type            | Confirms that
      | in propagation           | type is maintained
      |                          |
      +-------------+------------+
                    |
                    v
          Trace with types:
          [str] -> [str] -> [str] -> sink

Limitations

Current Limitations

Limitation Impact Mitigation
Requires installed server Won't work without server Clear error message
Slow startup First execution slow Client cache
Large projects High memory usage Limit analyzed files
Dynamic code Can't follow getattr Fallback to pattern matching
Cross-file limited Depends on server gopls has better support

Unsupported Cases

# LSP cannot follow this:
func = getattr(module, "dangerous_" + user_input)
func()

# LSP cannot analyze eval:
code = f"subprocess.run('{cmd}')"
eval(code)

# Metaprogramming:
class Meta(type):
    def __new__(cls, name, bases, dct):
        dct['run'] = lambda self, x: os.system(x)
        return super().__new__(cls, name, bases, dct)

Troubleshooting

Common Problems

Problem: Server won't start

Error: language server not found: pyright-langserver
Solution: Install the server globally:
npm install -g pyright

Problem: gopls not found

Error: command not found: gopls
Solution: Ensure ~/go/bin is in PATH:
export PATH=$PATH:~/go/bin

Problem: No type information obtained

[LSP] type: (nil)
Solution: Verify the project has valid configuration (pyproject.toml, tsconfig.json, go.mod).

Problem: Slow analysis Solution: 1. Reduce call graph depth 2. Limit analyzed files 3. Use --mode fast

Verify Installation

# Python
pyright-langserver --version

# TypeScript
typescript-language-server --version

# Go
gopls version

# Run with debug to see which servers are found
LSP_DEBUG=1 mcp-scan scan --lsp ./project

References


This documentation is for security analysts. For general usage, see user-guide/.