Push-to-Pull Diagnostics Engine
Relevant source files
The following files were used as context for generating this wiki page:
The Push-to-Pull Diagnostics Engine is a core architectural component of the lsp-mcp-server designed to reconcile the asynchronous, push-based nature of Language Server Protocol (LSP) diagnostics with the synchronous, request-based nature of Model Context Protocol (MCP) tool calls. In the LSP specification, diagnostics are not requested by the client; instead, they are "pushed" by the server via textDocument/publishDiagnostics notifications whenever a file is opened or changed.
To make these diagnostics available to an LLM or MCP client, this engine implements a caching layer that captures these notifications as they arrive. When a user calls a tool like lsp_diagnostics, the engine "pulls" the information from this local cache. This approach ensures that the MCP server can provide immediate responses to diagnostic queries without needing to wait for a full re-scan of the codebase by the underlying language server.
Sources: CLAUDE.md:38-40, src/tools/diagnostics.ts:98-100
Architecture and Data Flow
The engine operates across three main layers: the LSP Client, the Diagnostics Cache service, and the Tool Handlers.
- LSP Client Layer: The
LSPClientImpllistens forPublishDiagnosticsNotificationfrom the spawned language server. - Caching Layer: Received diagnostics are stored in the
DiagnosticsCache, which maintains a mapping of URIs to diagnostic arrays and provides aggregated summaries. - MCP Tool Layer: Tool handlers query the cache to return structured results to the user.
Diagnostic Flow Sequence
This diagram illustrates how an asynchronous notification from a Language Server becomes a synchronous response to an MCP client.
Core Components
DiagnosticsCache Service
The DiagnosticsCache is the central repository for all diagnostic data pushed by active language servers. It tracks errors, warnings, information, and hints across the entire workspace.
update(uri, diagnostics): Updates the cache for a specific file, replacing old entries with the new set provided by the server.get(uri): Retrieves current diagnostics for a specific file.getSummary(): Calculates a workspace-wide count of all issues by severity.
Sources: src/types.ts:318-340, src/services/diagnostics-cache.ts
Severity Classification
Diagnostics are categorized into four standard severity levels, which the engine uses for filtering and sorting:
| Severity | Numeric Value (LSP) | Order Rank | Description |
|---|---|---|---|
| Error | 1 | 1 | Critical issues preventing compilation. |
| Warning | 2 | 2 | Potential issues or code smells. |
| Info | 3 | 3 | Informational messages. |
| Hint | 4 | 4 | Suggestions for code improvement. |
Sources: src/tools/diagnostics.ts:34, src/tools/utils.ts:162-164
Implementation Details
Retrieving Diagnostics
When handleDiagnostics is invoked for a specific file, the engine first ensures the file is open to trigger a diagnostic push if necessary. It then performs the following logic:
- Retrieves diagnostics from the client's internal cache via
client.getCachedDiagnostics(uri). - Iterates through diagnostics and applies a
severity_filter. - Converts LSP 0-indexed ranges to human-readable 1-indexed positions.
- Extracts the
contextline from the file content to provide immediate visual feedback.
Sources: src/tools/diagnostics.ts:42-88, CLAUDE.md:44-46
Workspace-Wide Analysis
The handleWorkspaceDiagnostics function enables a broader view of the project's health. It aggregates data from the DiagnosticsCache for all URIs that have been "warmed up" or opened during the session.
Sources: src/tools/diagnostics.ts:106-175
Key Data Structures
DiagnosticResult
The engine transforms raw LSP diagnostics into a refined DiagnosticResult structure for MCP tool output.
export interface DiagnosticResult {
range: {
start: { line: number; column: number };
end: { line: number; column: number };
};
severity: 'error' | 'warning' | 'info' | 'hint';
code?: string | number;
source?: string;
message: string;
context: string;
}
Sources: src/types.ts:474-484
Performance and Limitations
- Warm-up Requirement: Because diagnostics are push-based,
lsp_workspace_diagnosticswill only show results for files that have been opened or indexed vialsp_index_files. Unopened files remain invisible to the engine. - Stale Data: If a file was recently modified externally, the cache might hold stale data until the document is re-opened or refreshed via an LSP tool call.
- Limit Enforcement: Workspace queries are capped (defaulting to 50 results) to prevent large diagnostic sets from overwhelming the MCP transport.
Sources: src/tools/diagnostics.ts:182-184, src/schemas/tool-schemas.ts:133-134, SKILL.md:124-128
Summary
The Push-to-Pull Diagnostics Engine provides a robust bridge between real-time language server feedback and the request-response model of LLM interfaces. By leveraging a centralized DiagnosticsCache and transforming asynchronous notifications into structured tool responses, it enables developers and agents to maintain high code quality through continuous, project-wide error monitoring.