Document Synchronization
Relevant source files
The following files were used as context for generating this wiki page:
Document Synchronization is a core service in the lsp-mcp-server architecture that manages the state and lifecycle of source code files between the MCP server and various Language Servers (LSPs). It ensures that files are correctly opened, updated with unsaved changes, and closed across multiple language server instances, maintaining a consistent view of the codebase for semantic analysis.
The system relies on the DocumentManager to track document versions and content per URI. It acts as a bridge, converting file-system events and tool requests into LSP-compliant notifications such as textDocument/didOpen, textDocument/didChange, and textDocument/didClose.
Sources: CLAUDE.md:31-36, src/services/document-manager.ts:84-86
Architecture and Components
The synchronization logic is primarily contained within the DocumentManagerImpl class, which implements the DocumentManager interface. It interacts closely with the LSPClient to propagate state changes to the underlying language servers.
Key Data Structures
The system maintains internal maps to track the state of documents and handle concurrency.
| Structure | Type | Description |
|---|---|---|
documents | Map<string, DocumentState> | Stores the URI, content, version, and set of active client IDs for each open document. |
versionCounters | Map<string, number> | Maintains a monotonically increasing version number for each URI to ensure LSP synchronization order. |
openLocks | Map<string, Promise<void>> | Handles concurrent open requests for the same document to prevent redundant file reads or notifications. |
Sources: src/services/document-manager.ts:87-89, src/types.ts:184-190
Document Manager Class Diagram
The following diagram illustrates the relationships between the DocumentManager, its state, and the LSPClient.
Lifecycle Operations
Opening and Ensuring Documents
The system uses an idempotent ensureOpen method. When a tool (e.g., lsp_hover) is called, the server first calls prepareFile, which triggers ensureOpen. This method reads the file from disk, detects the languageId based on the extension, and sends a didOpen notification to the LSP client if the file isn't already tracked for that specific server.
Sources: src/services/document-manager.ts:114-121, src/tools/utils.ts:43-52
Content Updates
When unsaved changes are required, updateContent increments the document version and sends a textDocument/didChange notification. This notification includes the full text or incremental changes (the current implementation sends the full text in a [{ text: content }] array).
Sources: src/services/document-manager.ts:153-172, src/types.ts:111-111
Document Closure
Documents are closed via reference counting. DocumentState tracks which clients have a document open. When closeDocument is called, the client is removed from the openWithClients set. Only when no more clients are tracking the document is the didClose notification sent to the server and the local state cleared.
Sources: src/services/document-manager.ts:133-146
Language Identification
The DocumentManager mapping translates file extensions to LSP-standard language identifiers. This is critical for the didOpen notification so the language server handles the file correctly.
| Extension | Language ID |
|---|---|
.ts, .tsx | typescript, typescriptreact |
.py, .pyi | python |
.rs | rust |
.go | go |
.js, .jsx, .mjs | javascript, javascriptreact |
| Others | plaintext (default) |
Sources: src/services/document-manager.ts:41-80
Integration with LSP Client
The LSPClientImpl handles the actual transmission of JSON-RPC notifications over the stdio transport. It ensures that the document synchronization notifications are sent only when the server is properly initialized.
- didOpen: Sends
TextDocumentItem(uri, languageId, version, text). - didChange: Sends
VersionedTextDocumentIdentifierand content changes. - didClose: Sends
TextDocumentIdentifier.
Sources: src/services/lsp-client.ts:435-460, src/types.ts:109-112
Summary
Document Synchronization in lsp-mcp-server provides a thread-safe, idempotent mechanism for managing code state. By centralizing file reading and version tracking in the DocumentManager, the server ensures that multiple MCP tools can interact with the same file across different language servers without state corruption or redundant I/O. This push-based synchronization is the prerequisite for all semantic features, including diagnostics collection and symbol resolution.
Sources: CLAUDE.md:31-40, src/index.ts:717-720