npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-lsp-driver

v0.2.0

Published

MCP LSP Driver for IDE plugins to easily expose LSP features via an MCP server.

Readme

MCP LSP Driver SDK

A TypeScript SDK that bridges Language Server Protocol (LSP) capabilities with the Model Context Protocol (MCP). Designed for IDE plugin developers building AI-assisted coding tools for VS Code, JetBrains, and other editors.

Core Philosophy

  • Fuzzy-to-Exact Resolution: LLMs interact via semantic anchors (symbolName, lineHint), and the SDK resolves them to precise coordinates
  • Disk-Based Truth: All read operations reflect the state of files on disk, ignoring unsaved IDE buffers
  • Human-in-the-Loop Edits: Write operations require explicit user approval before applying changes
  • Type Safety: Strict TypeScript with no any types

Installation

npm install mcp-lsp-driver
# or
pnpm add mcp-lsp-driver

Quick Start

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { installMcpLspDriver, type IdeCapabilities } from 'mcp-lsp-driver'
import * as fs from 'fs/promises'

// 1. Create your MCP server
const server = new McpServer({
  name: 'my-ide-mcp-server',
  version: '1.0.0'
})

// 2. Implement File Access (required)
const fileAccess = {
  readFile: async (uri: string) => {
    return await fs.readFile(uri, 'utf-8')
  },

  getFileTree: (uri: string) => yourIDE.workspace.getFileTree(uri),

  readDirectory: (uri: string) => yourIDE.workspace.readDirectory(uri)
}

// 3. Implement User Interaction (required for edits)
const userInteraction = {
  previewAndApplyEdits: async (operation) => {
    // Show diff in your IDE and get user approval
    return await showDiffDialog(operation)
  }
}

// 4. Implement LSP Capability Providers
const definition = {
  provideDefinition: async (uri, position) => {
    // Call your IDE's LSP to get definition
    return await lspClient.getDefinition(uri, position)
  }
}

const diagnostics = {
  provideDiagnostics: async (uri) => {
    // Get diagnostics from your IDE for the file
    return await lspClient.getDiagnostics(uri)
  },
  getWorkspaceDiagnostics: async () => {
    // Optional: Get all diagnostics in the workspace
    return await lspClient.getWorkspaceDiagnostics()
  }
}

const outline = {
  provideDocumentSymbols: async (uri) => {
    // Get document symbols from your IDE
    return await lspClient.getDocumentSymbols(uri)
  }
}

// 5. Register LSP tools and resources on the server
const capabilities: IdeCapabilities = {
  fileAccess,
  userInteraction,
  definition,
  diagnostics,
  outline,
  filesystem,
  onDiagnosticsChanged: (callback) => {
    // Register for diagnostic changes
    yourIDE.onDiagnosticsChanged((uri) => callback(uri))
  },
  // Add more capabilities as needed
}

installMcpLspDriver({ server, capabilities })

// 6. Connect to transport (you control the server lifecycle)
const transport = new StdioServerTransport()
await server.connect(transport)

API Reference

Core Interfaces

FileAccessProvider (Required)

Provides disk access for reading files:

// type UnifiedUri = string
interface FileAccessProvider {
  readFile(uri: UnifiedUri): Promise<string>
  getFileTree(folderPath: UnifiedUri): Promise<string[]>
  readDirectory(folderPath: UnifiedUri): Promise<string[]>
}

UserInteractionProvider (Required for edits)

Handles user approval for edit operations:

interface UserInteractionProvider {
  previewAndApplyEdits(operation: PendingEditOperation): Promise<boolean>
}

Capability Providers

All capability providers receive ExactPosition coordinates (0-based). The SDK handles fuzzy-to-exact conversion before calling these.

DefinitionProvider

interface DefinitionProvider {
  provideDefinition(uri: UnifiedUri, position: ExactPosition): Promise<CodeSnippet[]>
}

ReferencesProvider

interface ReferencesProvider {
  provideReferences(uri: UnifiedUri, position: ExactPosition): Promise<CodeSnippet[]>
}

HierarchyProvider

interface HierarchyProvider {
  provideCallHierarchy(
    uri: UnifiedUri,
    position: ExactPosition,
    direction: 'incoming' | 'outgoing'
  ): Promise<CodeSnippet[]>
}

DiagnosticsProvider

interface DiagnosticsProvider {
  provideDiagnostics(uri: UnifiedUri): Promise<Diagnostic[]>
  getWorkspaceDiagnostics?(): Promise<Diagnostic[]>  // Optional workspace diagnostics
}

OutlineProvider

interface OutlineProvider {
  provideDocumentSymbols(uri: UnifiedUri): Promise<DocumentSymbol[]>
}

GlobalFindProvider

interface GlobalFindProvider {
  globalFind(query: string, options: GlobalFindOptions): Promise<GlobalFindMatch[]>
  globalReplace(query: string, replaceWith: string, options: GlobalFindOptions): Promise<number>
}

Provides global find and replace functionality across the workspace. GlobalFindOptions includes:

  • caseSensitive: Whether the search is case-sensitive (default: false)
  • exactMatch: Whether to match exact words only (default: false)
  • regexMode: Whether the query is a regular expression (default: false)

GlobalFindMatch includes:

  • uri: File URI containing the match
  • line: 1-based line number
  • column: 1-based column number
  • matchText: The matching text
  • context: Context around the match (e.g., the full line)

IdeCapabilities

Combine all providers into a single configuration:

interface IdeCapabilities {
  fileAccess: FileAccessProvider           // Required
  userInteraction?: UserInteractionProvider // Required for apply_edit tool
  definition?: DefinitionProvider           // Enables goto_definition tool
  references?: ReferencesProvider           // Enables find_references tool
  hierarchy?: HierarchyProvider             // Enables call_hierarchy tool
  diagnostics?: DiagnosticsProvider         // Enables diagnostics resources
  outline?: OutlineProvider                 // Enables outline resource
  globalFind?: GlobalFindProvider           // Enables global_find and global_replace tools
  onDiagnosticsChanged?: (callback: OnDiagnosticsChangedCallback) => void
}

MCP Tools

The SDK automatically registers tools based on which capabilities you provide:

goto_definition

Navigate to the definition of a symbol.

Inputs:

  • uri: File path or URI
  • symbol_name: Text of the symbol to find
  • line_hint: Approximate line number (1-based)
  • order_hint: Which occurrence if symbol appears multiple times (0-based, default: 0)

find_references

Find all references to a symbol.

Inputs: Same as goto_definition

call_hierarchy

Get call hierarchy for a function or method.

Inputs:

  • Same as goto_definition, plus:
  • direction: 'incoming' (callers) or 'outgoing' (callees)

apply_edit

Apply a text edit to a file (requires user approval).

Inputs:

  • uri: File path or URI
  • search_text: Exact text to replace (must be unique in file)
  • replace_text: New text to insert
  • description: Rationale for the edit

global_find

Search for text across the entire workspace.

Inputs:

  • query: The search query (required)
  • case_sensitive: Whether the search is case-sensitive (optional, default: false)
  • exact_match: Whether to match exact words only (optional, default: false)
  • regex_mode: Whether the query is a regular expression (optional, default: false)

Returns:

  • Array of matches with file URI, line, column, matching text, and context
  • Total number of matches found

global_replace

Replace all occurrences of text across the entire workspace.

Inputs:

  • query: The search query (required)
  • replace_with: The replacement text (required)
  • case_sensitive: Whether the search is case-sensitive (optional, default: false)
  • exact_match: Whether to match exact words only (optional, default: false)
  • regex_mode: Whether the query is a regular expression (optional, default: false)

Returns:

  • Number of replacements made
  • Success status and message

MCP Resources

The SDK automatically registers resources based on which capabilities you provide:

lsp://diagnostics/{path}

Get diagnostics (errors, warnings) for a specific file.

Resource URI Pattern: lsp://diagnostics/{+path}

Example: lsp://diagnostics/src/main.ts

Returns diagnostics formatted as markdown with location, severity, and message information.

Subscription Support: If your IDE implements onDiagnosticsChanged capability, these resources become subscribable. When diagnostics change, the driver sends resource update notifications.

lsp://diagnostics/workspace

Get diagnostics across the entire workspace.

Resource URI: lsp://diagnostics/workspace

Only available if your DiagnosticsProvider implements the optional getWorkspaceDiagnostics() method.

Returns workspace diagnostics grouped by file, formatted as markdown.

Subscription Support: If your IDE implements onDiagnosticsChanged capability, this resource becomes subscribable.

lsp://outline/{path}

Get the document outline (symbol tree) for a file.

Resource URI Pattern: lsp://outline/{+path}

Example: lsp://outline/src/components/Button.tsx

Returns document symbols formatted as a hierarchical markdown outline, including:

  • Symbol names and kinds (class, function, method, etc.)
  • Source locations
  • Nested children (e.g., methods within classes)

No subscription support for this resource (read-only).

lsp://filetree/{path}

Get the complete file tree for a directory, excluding git-ignored files.

Resource URI Pattern: lsp://filetree/{+path}

Example: lsp://filetree/src, lsp://filetree/.

Returns a JSON array of all file paths in the directory tree (recursive). Use "." for the root directory.

No subscription support for this resource (read-only).

lsp://files/{path}

For directories: returns directory children (git-ignored files excluded, similar to ls). For files: gets file content with optional line range.

Resource URI Pattern: lsp://files/{+path}

Example: lsp://files/src, lsp://files/src/index.ts, lsp://files/src/index.ts#L1-L2

No subscription support for this resource (read-only).

Subscription and Change Notifications

When your IDE supports the onDiagnosticsChanged capability, diagnostic resources become subscribable:

const capabilities: IdeCapabilities = {
  fileAccess,
  diagnostics: {
    provideDiagnostics: async (uri) => { /* ... */ },
    getWorkspaceDiagnostics: async () => { /* ... */ }
  },
  onDiagnosticsChanged: (callback) => {
    // Register your IDE's diagnostic change listener
    yourIDE.onDiagnosticsChanged((uri) => {
      // Call the callback when diagnostics change
      callback(uri)
    })
  }
}

When diagnostics change, call the registered callback with the affected file URI. The driver will send MCP resource update notifications to subscribers.

Symbol Resolution

The SDK uses a robust algorithm to handle imprecise LLM positioning:

  1. Target the lineHint (converting 1-based to 0-based)
  2. Search for symbolName in that line
  3. Robustness Fallback: If not found, scan +/- 2 lines (configurable)
  4. Use orderHint to select the Nth occurrence if needed

Configure the search radius:

installMcpLspDriver({ server, capabilities, config: {
  resolverConfig: {
    lineSearchRadius: 5  // Default: 2
  }
}})

Type Definitions

Position Types

// 0-based exact coordinates (internal)
interface ExactPosition {
  line: number
  character: number
}

// Fuzzy position from LLM
interface FuzzyPosition {
  symbolName: string
  lineHint: number      // 1-based
  orderHint?: number    // 0-based, default: 0
}

// Range on disk
interface DiskRange {
  start: ExactPosition
  end: ExactPosition
}

Result Types

interface CodeSnippet {
  uri: UnifiedUri
  range: DiskRange
  content: string
}

interface Diagnostic {
  uri: UnifiedUri
  range: DiskRange
  severity: 'error' | 'warning' | 'information' | 'hint'
  message: string
  source?: string
  code?: string | number
}

type EditResult =
  | { success: true; message: string }
  | { success: false; message: string; reason: 'UserRejected' | 'IOError' | 'ValidationFailed' }

Development

# Install dependencies
pnpm install

# Build
pnpm build

# Run tests
pnpm test

# Run tests in watch mode
pnpm test:watch

# Lint
pnpm lint

# Format
pnpm format

Requirements

  • Node.js >= 18.0.0
  • TypeScript >= 5.7.0

License

MIT