Adding a New MCP Tool
Relevant source files
The following files were used as context for generating this wiki page:
The lsp-mcp-server project uses a structured approach to expose Language Server Protocol (LSP) functionalities as Model Context Protocol (MCP) tools. Adding a new tool involves a five-step process: defining a validation schema, implementing the handler logic, exporting the handler, defining the tool metadata, and registering the handler in the main server loop.
Sources: CLAUDE.md:104-109
Core Architecture and Data Flow
The project acts as a bridge where MCP requests are validated, processed through specialized tool handlers, and translated into LSP requests sent to various language servers. Tool handlers interact with global services like the ConnectionManager and DocumentManager via a shared ToolContext.
Tool Execution Flow
The following diagram illustrates the lifecycle of an MCP tool call from request arrival to response delivery.
The prepareFile(filePath) utility is a critical component that validates paths, retrieves the appropriate LSP client for the file type, and ensures the document is open before the tool logic proceeds.
Sources: CLAUDE.md:88-100, src/tools/utils.ts
Implementation Steps
1. Define Input Validation Schema
New tools must have a Zod schema defined in src/schemas/tool-schemas.ts. This ensures strict type checking and absolute path validation. Common schemas like FilePathSchema, LineSchema, and ColumnSchema should be reused to maintain consistency.
export const NewToolSchema = z.object({
file_path: FilePathSchema,
line: LineSchema,
column: ColumnSchema,
custom_param: z.string().describe('Description of parameter'),
}).strict();
Sources: src/schemas/tool-schemas.ts:31-50
2. Implement the Handler Function
Create a handler function in a relevant file within src/tools/. Handlers typically use prepareFile to obtain the client and uri needed for LSP communication.
| Component | Responsibility |
|---|---|
prepareFile | Validates path, gets LSP client, and ensures file is open. |
client | The LSPClient instance used to send protocol-specific requests. |
toPosition | Converts 1-indexed human positions to LSP 0-indexed positions. |
fromLspRange | Converts LSP 0-indexed ranges back to 1-indexed tool outputs. |
Sources: CLAUDE.md:92-96, src/types.ts:167-200
3. Register the Tool and Handler
The tool must be registered in src/index.ts in two locations: the TOOLS array (for discovery) and the toolHandlers map (for execution).
| Requirement | Location | Description |
|---|---|---|
| Tool Metadata | TOOLS array | Includes name, description, and inputSchema in JSON Schema format. |
| Logic Mapping | toolHandlers | Maps the tool name to its Zod schema and implementation function. |
Sources: src/index.ts:117-122, src/index.ts:517-530
Position and Character Encoding
A critical requirement for all tool handlers is the handling of 1-indexed positions. While the MCP tools expose 1-indexed lines and columns for human readability, the internal LSP communication must be 0-indexed. Furthermore, characters must be handled as UTF-16 code units to align with the LSP specification.
Sources: CLAUDE.md:73-82
Error Handling
Tool handlers should catch and convert errors into the structured LSPError format.
| Error Code | Meaning |
|---|---|
INVALID_POSITION | The provided line/column is outside the file bounds. |
CAPABILITY_NOT_SUPPORTED | The connected LSP server does not support the requested feature. |
UNSUPPORTED_LANGUAGE | No language server is configured for the file extension. |
Sources: src/types.ts:315-333, src/index.ts:717-750
Conclusion
Adding a tool to the lsp-mcp-server requires adhering to the established pattern of Zod-based validation, standard position conversion, and registration within the central server file. This structured approach ensures that new semantic capabilities remain consistent with the existing 24+ tools already provided by the server.
Sources: src/index.ts:104-114, CLAUDE.md:104-110