@treedy/lsp-mcp 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,10 +5,10 @@ Unified MCP server aggregating multi-language LSP backends for code intelligence
5
5
  ## Features
6
6
 
7
7
  - **Unified Entry Point**: Single MCP server for multiple languages
8
- - **Namespaced Tools**: `python/hover`, `typescript/definition`, etc.
9
- - **Auto Language Detection**: Infers language from file extensions
8
+ - **Namespaced Tools**: `python_hover`, `typescript_definition`, etc.
9
+ - **On-Demand Loading**: Backends are installed and started only when needed
10
+ - **Dynamic Tool Registration**: Backend tools are discovered automatically
10
11
  - **Skill Prompts**: Best practices exposed as MCP prompts for agents
11
- - **Lazy Loading**: Backends start on first use
12
12
  - **Graceful Degradation**: Clear error messages when backends unavailable
13
13
 
14
14
  ## Installation
@@ -67,17 +67,17 @@ This ensures backends are always up-to-date when the server starts. To disable a
67
67
 
68
68
  | Tool | Description |
69
69
  |------|-------------|
70
- | `{lang}/hover` | Get type information and documentation |
71
- | `{lang}/definition` | Go to definition |
72
- | `{lang}/references` | Find all references |
73
- | `{lang}/completions` | Code completion suggestions |
74
- | `{lang}/diagnostics` | Type errors and warnings |
75
- | `{lang}/symbols` | Extract symbols from file |
76
- | `{lang}/rename` | Rename symbol |
77
- | `{lang}/search` | Regex pattern search |
78
- | `{lang}/signature_help` | Function signature help |
79
- | `{lang}/update_document` | Update file for incremental analysis |
80
- | `{lang}/status` | Backend status |
70
+ | `{lang}_hover` | Get type information and documentation |
71
+ | `{lang}_definition` | Go to definition |
72
+ | `{lang}_references` | Find all references |
73
+ | `{lang}_completions` | Code completion suggestions |
74
+ | `{lang}_diagnostics` | Type errors and warnings |
75
+ | `{lang}_symbols` | Extract symbols from file |
76
+ | `{lang}_rename` | Rename symbol |
77
+ | `{lang}_search` | Regex pattern search |
78
+ | `{lang}_signature_help` | Function signature help |
79
+ | `{lang}_update_document` | Update file for incremental analysis |
80
+ | `{lang}_status` | Backend status |
81
81
 
82
82
  Replace `{lang}` with `python` or `typescript`.
83
83
 
@@ -85,20 +85,41 @@ Replace `{lang}` with `python` or `typescript`.
85
85
 
86
86
  | Tool | Description |
87
87
  |------|-------------|
88
- | `python/move` | Move function/class to another module |
89
- | `python/change_signature` | Modify function signature |
90
- | `python/function_signature` | Get current function signature |
91
- | `python/set_backend` | Switch between rope/pyright |
92
- | `python/set_python_path` | Set Python interpreter |
88
+ | `python_move` | Move function/class to another module |
89
+ | `python_change_signature` | Modify function signature |
90
+ | `python_function_signature` | Get current function signature |
91
+ | `python_set_backend` | Switch between rope/pyright |
92
+ | `python_set_python_path` | Set Python interpreter |
93
93
 
94
94
  ### Meta Tools
95
95
 
96
96
  | Tool | Description |
97
97
  |------|-------------|
98
+ | `list_backends` | List available backends and their status |
99
+ | `start_backend` | Install and start a backend (downloads if needed) |
98
100
  | `status` | Overall server and backend status with versions |
99
101
  | `check_versions` | Detailed version info for server and all backends |
100
102
  | `switch_python_backend` | Switch Python provider |
101
103
 
104
+ ## Quick Start
105
+
106
+ 1. **List available backends**:
107
+ ```
108
+ list_backends
109
+ ```
110
+
111
+ 2. **Start a backend** (this will download and install if needed):
112
+ ```
113
+ start_backend language=python
114
+ start_backend language=typescript
115
+ ```
116
+
117
+ 3. **Use backend tools** (available after starting):
118
+ ```
119
+ python_hover file=/path/to/file.py line=10 column=5
120
+ typescript_definition file=/path/to/file.ts line=15 column=10
121
+ ```
122
+
102
123
  ## Available Prompts (Skills)
103
124
 
104
125
  The server exposes skill documentation as MCP prompts that agents can request:
@@ -142,7 +163,7 @@ Repeat until clean
142
163
 
143
164
  ```json
144
165
  {
145
- "name": "python/hover",
166
+ "name": "python_hover",
146
167
  "arguments": {
147
168
  "file": "/path/to/file.py",
148
169
  "line": 10,
@@ -155,7 +176,7 @@ Repeat until clean
155
176
 
156
177
  ```json
157
178
  {
158
- "name": "typescript/definition",
179
+ "name": "typescript_definition",
159
180
  "arguments": {
160
181
  "file": "/path/to/file.ts",
161
182
  "line": 15,
@@ -193,7 +214,7 @@ This will automatically route to the Python backend.
193
214
  │ │
194
215
  │ ┌────────────────────────────────────────────────────────────┐ │
195
216
  │ │ Tool Router │ │
196
- │ │ - Parse tool name (python/hover → {lang, tool}) │ │
217
+ │ │ - Parse tool name (python_hover → {lang, tool}) │ │
197
218
  │ │ - Infer language from file extension │ │
198
219
  │ │ - Route to appropriate backend │ │
199
220
  │ └────────────────────────────────────────────────────────────┘ │
package/dist/index.js CHANGED
@@ -20742,84 +20742,6 @@ class BackendManager {
20742
20742
  }
20743
20743
  }
20744
20744
 
20745
- // src/backends/python.ts
20746
- var pythonPositionSchema = {
20747
- file: exports_external.string().describe("Absolute path to the Python file"),
20748
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
20749
- column: exports_external.number().int().positive().describe("Column number (1-based)")
20750
- };
20751
- var pythonToolDescriptions = {
20752
- hover: "Get type information and documentation at a specific position in a Python file",
20753
- definition: "Go to definition of a symbol at a specific position in a Python file",
20754
- references: "Find all references to a symbol at a specific position in a Python file",
20755
- completions: "Get code completion suggestions at a specific position in a Python file",
20756
- diagnostics: "Get type errors and warnings for a Python file or directory",
20757
- symbols: "Extract symbols (classes, functions, methods, variables) from a Python file",
20758
- rename: "Rename a symbol and update all references in Python files",
20759
- search: "Search for a regex pattern in Python files",
20760
- signature_help: "Get function signature help at a specific position in a Python file",
20761
- update_document: "Update file content for incremental analysis in Python",
20762
- status: "Check Python/Pyright environment status",
20763
- move: "Move a function or class to another Python module",
20764
- change_signature: "Change the signature of a Python function",
20765
- function_signature: "Get the current signature of a Python function",
20766
- set_backend: "Set the backend (rope/pyright) for Python code analysis",
20767
- set_python_path: "Set the Python interpreter path for code analysis"
20768
- };
20769
-
20770
- // src/backends/typescript.ts
20771
- var typescriptPositionSchema = {
20772
- file: exports_external.string().describe("Absolute path to the TypeScript/JavaScript file"),
20773
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
20774
- column: exports_external.number().int().positive().describe("Column number (1-based)")
20775
- };
20776
- var typescriptToolDescriptions = {
20777
- hover: "Get type information and documentation at a specific position in a TypeScript/JavaScript file",
20778
- definition: "Go to definition of a symbol at a specific position",
20779
- references: "Find all references to a symbol at a specific position",
20780
- completions: "Get code completion suggestions at a specific position",
20781
- diagnostics: "Get type errors and warnings for a TypeScript/JavaScript file",
20782
- symbols: "Extract symbols (classes, functions, methods, variables) from a file",
20783
- rename: "Preview renaming a symbol (shows all locations that would be renamed)",
20784
- search: "Search for a regex pattern in TypeScript/JavaScript files",
20785
- signature_help: "Get function signature help at a specific position",
20786
- update_document: "Update file content for incremental analysis",
20787
- status: "Check TypeScript environment status for a project"
20788
- };
20789
-
20790
- // src/tools/schemas.ts
20791
- var positionArgs = {
20792
- file: exports_external.string().describe("Absolute path to the file"),
20793
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
20794
- column: exports_external.number().int().positive().describe("Column number (1-based)")
20795
- };
20796
- var searchArgs = {
20797
- pattern: exports_external.string().describe("The regex pattern to search for"),
20798
- path: exports_external.string().optional().describe("Directory or file to search in"),
20799
- glob: exports_external.string().optional().describe("Glob pattern to filter files"),
20800
- caseSensitive: exports_external.boolean().default(true).describe("Whether the search is case sensitive"),
20801
- maxResults: exports_external.number().int().positive().default(50).describe("Maximum number of results")
20802
- };
20803
- var diagnosticsArgs = {
20804
- path: exports_external.string().describe("Path to a file or directory to check")
20805
- };
20806
- var renameArgs = {
20807
- ...positionArgs,
20808
- newName: exports_external.string().describe("New name for the symbol")
20809
- };
20810
- var symbolsArgs = {
20811
- file: exports_external.string().describe("Absolute path to the file"),
20812
- query: exports_external.string().optional().describe("Optional filter query for symbol names")
20813
- };
20814
- var updateDocumentArgs = {
20815
- file: exports_external.string().describe("Absolute path to the file"),
20816
- content: exports_external.string().describe("New content for the file")
20817
- };
20818
- var completionsArgs = {
20819
- ...positionArgs,
20820
- limit: exports_external.number().int().positive().default(20).describe("Maximum number of completions to return")
20821
- };
20822
-
20823
20745
  // src/tools/meta.ts
20824
20746
  import { readFileSync } from "fs";
20825
20747
  import { dirname, join } from "path";
@@ -20855,8 +20777,9 @@ async function status(backendManager, config2) {
20855
20777
  status: v.status
20856
20778
  })),
20857
20779
  usage: {
20858
- namespaced: "Use python/hover or typescript/hover to specify language",
20859
- auto_infer: "Or provide a file path and language will be inferred from extension"
20780
+ list: "Use list_backends to see available backends",
20781
+ start: "Use start_backend to install and start a backend",
20782
+ tools: "Once started, tools are available as python_hover, typescript_definition, etc."
20860
20783
  }
20861
20784
  };
20862
20785
  return {
@@ -20924,6 +20847,99 @@ function switchPythonBackend(provider) {
20924
20847
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
20925
20848
  };
20926
20849
  }
20850
+ async function listBackends(backendManager, config2) {
20851
+ const backendStatus = backendManager.getStatus();
20852
+ const backends = [
20853
+ {
20854
+ name: "python",
20855
+ enabled: config2.python.enabled,
20856
+ provider: config2.python.provider,
20857
+ status: backendStatus.python?.status || "not_started",
20858
+ tools: backendStatus.python?.tools || 0,
20859
+ description: "Python code intelligence (hover, definition, references, refactoring)",
20860
+ startCommand: "Use start_backend tool with language='python'"
20861
+ },
20862
+ {
20863
+ name: "typescript",
20864
+ enabled: config2.typescript.enabled,
20865
+ status: backendStatus.typescript?.status || "not_started",
20866
+ tools: backendStatus.typescript?.tools || 0,
20867
+ description: "TypeScript/JavaScript code intelligence",
20868
+ startCommand: "Use start_backend tool with language='typescript'"
20869
+ }
20870
+ ];
20871
+ const result = {
20872
+ backends,
20873
+ usage: {
20874
+ start: "Call start_backend with language='python' or 'typescript' to install and start a backend",
20875
+ tools: "Once started, backend tools will be available as {language}_{tool} (e.g., python_hover)"
20876
+ }
20877
+ };
20878
+ return {
20879
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
20880
+ };
20881
+ }
20882
+ var startBackendSchema = {
20883
+ language: exports_external.enum(["python", "typescript"]).describe("The backend to start")
20884
+ };
20885
+ async function startBackend(language, backendManager, config2, registerToolsCallback) {
20886
+ if (language === "python" && !config2.python.enabled) {
20887
+ return {
20888
+ content: [{
20889
+ type: "text",
20890
+ text: JSON.stringify({
20891
+ success: false,
20892
+ error: "Python backend is disabled",
20893
+ hint: "Set LSP_MCP_PYTHON_ENABLED=true to enable"
20894
+ }, null, 2)
20895
+ }]
20896
+ };
20897
+ }
20898
+ if (language === "typescript" && !config2.typescript.enabled) {
20899
+ return {
20900
+ content: [{
20901
+ type: "text",
20902
+ text: JSON.stringify({
20903
+ success: false,
20904
+ error: "TypeScript backend is disabled",
20905
+ hint: "Set LSP_MCP_TYPESCRIPT_ENABLED=true to enable"
20906
+ }, null, 2)
20907
+ }]
20908
+ };
20909
+ }
20910
+ try {
20911
+ const toolCount = await registerToolsCallback(language);
20912
+ const backendStatus = backendManager.getStatus();
20913
+ const status2 = backendStatus[language];
20914
+ return {
20915
+ content: [{
20916
+ type: "text",
20917
+ text: JSON.stringify({
20918
+ success: true,
20919
+ language,
20920
+ status: status2?.status,
20921
+ serverName: status2?.serverName,
20922
+ version: status2?.version,
20923
+ toolsRegistered: toolCount,
20924
+ message: `${language} backend started successfully. ${toolCount} tools are now available.`,
20925
+ usage: `Tools are available as ${language}_hover, ${language}_definition, etc.`
20926
+ }, null, 2)
20927
+ }]
20928
+ };
20929
+ } catch (error2) {
20930
+ return {
20931
+ content: [{
20932
+ type: "text",
20933
+ text: JSON.stringify({
20934
+ success: false,
20935
+ language,
20936
+ error: String(error2),
20937
+ hint: "Check if the backend package is available and network connection is working"
20938
+ }, null, 2)
20939
+ }]
20940
+ };
20941
+ }
20942
+ }
20927
20943
 
20928
20944
  // src/prompts.ts
20929
20945
  var skillsContent = {
@@ -21426,186 +21442,117 @@ var require2 = createRequire2(import.meta.url);
21426
21442
  var packageJson = require2("../package.json");
21427
21443
  var config2 = loadConfig();
21428
21444
  var backendManager = new BackendManager(config2);
21445
+ var startedBackends = new Set;
21429
21446
  var server = new McpServer({
21430
21447
  name: "lsp-mcp",
21431
21448
  version: packageJson.version
21432
21449
  });
21433
21450
  registerPrompts(server);
21451
+ function jsonSchemaToZod(schema) {
21452
+ const result = {};
21453
+ if (!schema || !schema.properties) {
21454
+ return result;
21455
+ }
21456
+ const required2 = new Set(schema.required || []);
21457
+ for (const [key, prop] of Object.entries(schema.properties)) {
21458
+ let zodType;
21459
+ switch (prop.type) {
21460
+ case "string":
21461
+ zodType = exports_external.string();
21462
+ if (prop.enum) {
21463
+ zodType = exports_external.enum(prop.enum);
21464
+ }
21465
+ break;
21466
+ case "number":
21467
+ case "integer":
21468
+ zodType = exports_external.number();
21469
+ if (prop.type === "integer") {
21470
+ zodType = zodType.int();
21471
+ }
21472
+ if (prop.exclusiveMinimum !== undefined) {
21473
+ zodType = zodType.gt(prop.exclusiveMinimum);
21474
+ }
21475
+ if (prop.minimum !== undefined) {
21476
+ zodType = zodType.gte(prop.minimum);
21477
+ }
21478
+ if (prop.maximum !== undefined) {
21479
+ zodType = zodType.lte(prop.maximum);
21480
+ }
21481
+ break;
21482
+ case "boolean":
21483
+ zodType = exports_external.boolean();
21484
+ break;
21485
+ case "array":
21486
+ if (prop.items?.type === "string") {
21487
+ zodType = exports_external.array(exports_external.string());
21488
+ } else {
21489
+ zodType = exports_external.array(exports_external.any());
21490
+ }
21491
+ break;
21492
+ case "object":
21493
+ zodType = exports_external.record(exports_external.any());
21494
+ break;
21495
+ default:
21496
+ zodType = exports_external.any();
21497
+ }
21498
+ if (prop.description) {
21499
+ zodType = zodType.describe(prop.description);
21500
+ }
21501
+ if (prop.default !== undefined) {
21502
+ zodType = zodType.default(prop.default);
21503
+ }
21504
+ if (!required2.has(key)) {
21505
+ zodType = zodType.optional();
21506
+ }
21507
+ result[key] = zodType;
21508
+ }
21509
+ return result;
21510
+ }
21511
+ function registerBackendTools(language, tools) {
21512
+ let count = 0;
21513
+ for (const tool of tools) {
21514
+ const namespacedName = `${language}_${tool.name}`;
21515
+ const zodSchema = jsonSchemaToZod(tool.inputSchema);
21516
+ server.registerTool(namespacedName, {
21517
+ description: tool.description || `${language} ${tool.name} tool`,
21518
+ inputSchema: zodSchema
21519
+ }, async (args) => backendManager.callTool(language, tool.name, args));
21520
+ console.error(`[lsp-mcp] Registered ${namespacedName}`);
21521
+ count++;
21522
+ }
21523
+ return count;
21524
+ }
21525
+ async function startAndRegisterBackend(language) {
21526
+ if (startedBackends.has(language)) {
21527
+ const status2 = backendManager.getStatus()[language];
21528
+ console.error(`[lsp-mcp] ${language} backend already started (${status2?.tools} tools)`);
21529
+ return status2?.tools || 0;
21530
+ }
21531
+ console.error(`[lsp-mcp] Starting ${language} backend...`);
21532
+ try {
21533
+ const tools = await backendManager.getTools(language);
21534
+ const count = registerBackendTools(language, tools);
21535
+ startedBackends.add(language);
21536
+ console.error(`[lsp-mcp] ${language}: ${count} tools registered`);
21537
+ return count;
21538
+ } catch (error2) {
21539
+ console.error(`[lsp-mcp] Failed to start ${language} backend:`, error2);
21540
+ throw error2;
21541
+ }
21542
+ }
21434
21543
  server.registerTool("status", { description: "Get status of all LSP backends and server configuration" }, async () => status(backendManager, config2));
21435
21544
  server.registerTool("check_versions", { description: "Check versions of all backends and server. Shows installed versions and how to check for updates." }, async () => checkVersions(backendManager, config2));
21436
21545
  server.registerTool("switch_python_backend", {
21437
21546
  description: "Switch the Python backend provider (requires restart)",
21438
21547
  inputSchema: switchPythonBackendSchema
21439
21548
  }, async ({ provider }) => switchPythonBackend(provider));
21440
- if (config2.python.enabled) {
21441
- const backendOption = exports_external.enum(["rope", "pyright"]).optional().describe("Backend to use (rope/pyright)");
21442
- server.registerTool("python/hover", {
21443
- description: pythonToolDescriptions.hover,
21444
- inputSchema: { ...positionArgs, backend: backendOption }
21445
- }, async (args) => backendManager.callTool("python", "hover", args));
21446
- server.registerTool("python/definition", {
21447
- description: pythonToolDescriptions.definition,
21448
- inputSchema: { ...positionArgs, backend: backendOption }
21449
- }, async (args) => backendManager.callTool("python", "definition", args));
21450
- server.registerTool("python/references", {
21451
- description: pythonToolDescriptions.references,
21452
- inputSchema: { ...positionArgs, backend: backendOption }
21453
- }, async (args) => backendManager.callTool("python", "references", args));
21454
- server.registerTool("python/completions", {
21455
- description: pythonToolDescriptions.completions,
21456
- inputSchema: { ...completionsArgs, backend: backendOption }
21457
- }, async (args) => backendManager.callTool("python", "completions", args));
21458
- server.registerTool("python/diagnostics", {
21459
- description: pythonToolDescriptions.diagnostics,
21460
- inputSchema: diagnosticsArgs
21461
- }, async (args) => backendManager.callTool("python", "diagnostics", args));
21462
- server.registerTool("python/symbols", {
21463
- description: pythonToolDescriptions.symbols,
21464
- inputSchema: { ...symbolsArgs, backend: backendOption }
21465
- }, async (args) => backendManager.callTool("python", "symbols", args));
21466
- server.registerTool("python/rename", {
21467
- description: pythonToolDescriptions.rename,
21468
- inputSchema: { ...positionArgs, new_name: exports_external.string().describe("New name for the symbol") }
21469
- }, async (args) => backendManager.callTool("python", "rename", args));
21470
- server.registerTool("python/search", {
21471
- description: pythonToolDescriptions.search,
21472
- inputSchema: searchArgs
21473
- }, async (args) => backendManager.callTool("python", "search", args));
21474
- server.registerTool("python/signature_help", {
21475
- description: pythonToolDescriptions.signature_help,
21476
- inputSchema: positionArgs
21477
- }, async (args) => backendManager.callTool("python", "signature_help", args));
21478
- server.registerTool("python/update_document", {
21479
- description: pythonToolDescriptions.update_document,
21480
- inputSchema: updateDocumentArgs
21481
- }, async (args) => backendManager.callTool("python", "update_document", args));
21482
- server.registerTool("python/status", {
21483
- description: pythonToolDescriptions.status
21484
- }, async () => backendManager.callTool("python", "status", {}));
21485
- server.registerTool("python/move", {
21486
- description: pythonToolDescriptions.move,
21487
- inputSchema: {
21488
- ...positionArgs,
21489
- destination: exports_external.string().describe('Destination module path (e.g., "mypackage.utils")'),
21490
- preview: exports_external.boolean().default(false).describe("If true, only show what would change")
21491
- }
21492
- }, async (args) => backendManager.callTool("python", "move", args));
21493
- server.registerTool("python/change_signature", {
21494
- description: pythonToolDescriptions.change_signature,
21495
- inputSchema: {
21496
- ...positionArgs,
21497
- new_params: exports_external.array(exports_external.string()).optional().describe("New parameter order"),
21498
- add_param: exports_external.string().optional().describe("Name of parameter to add"),
21499
- add_param_default: exports_external.string().optional().describe("Default value for added parameter"),
21500
- add_param_index: exports_external.number().int().optional().describe("Index where to insert new param"),
21501
- remove_param: exports_external.string().optional().describe("Name of parameter to remove"),
21502
- preview: exports_external.boolean().default(false).describe("If true, only show what would change")
21503
- }
21504
- }, async (args) => backendManager.callTool("python", "change_signature", args));
21505
- server.registerTool("python/function_signature", {
21506
- description: pythonToolDescriptions.function_signature,
21507
- inputSchema: positionArgs
21508
- }, async (args) => backendManager.callTool("python", "function_signature", args));
21509
- server.registerTool("python/set_backend", {
21510
- description: pythonToolDescriptions.set_backend,
21511
- inputSchema: {
21512
- backend: exports_external.enum(["rope", "pyright"]).describe("The backend to use"),
21513
- tool: exports_external.string().optional().describe("Optional tool name to set backend for")
21514
- }
21515
- }, async (args) => backendManager.callTool("python", "set_backend", args));
21516
- server.registerTool("python/set_python_path", {
21517
- description: pythonToolDescriptions.set_python_path,
21518
- inputSchema: {
21519
- python_path: exports_external.string().describe("Absolute path to the Python interpreter"),
21520
- workspace: exports_external.string().optional().describe("Optional workspace to set the path for")
21521
- }
21522
- }, async (args) => backendManager.callTool("python", "set_python_path", args));
21523
- }
21524
- if (config2.typescript.enabled) {
21525
- server.registerTool("typescript/hover", {
21526
- description: typescriptToolDescriptions.hover,
21527
- inputSchema: positionArgs
21528
- }, async (args) => backendManager.callTool("typescript", "hover", args));
21529
- server.registerTool("typescript/definition", {
21530
- description: typescriptToolDescriptions.definition,
21531
- inputSchema: positionArgs
21532
- }, async (args) => backendManager.callTool("typescript", "definition", args));
21533
- server.registerTool("typescript/references", {
21534
- description: typescriptToolDescriptions.references,
21535
- inputSchema: positionArgs
21536
- }, async (args) => backendManager.callTool("typescript", "references", args));
21537
- server.registerTool("typescript/completions", {
21538
- description: typescriptToolDescriptions.completions,
21539
- inputSchema: completionsArgs
21540
- }, async (args) => backendManager.callTool("typescript", "completions", args));
21541
- server.registerTool("typescript/diagnostics", {
21542
- description: typescriptToolDescriptions.diagnostics,
21543
- inputSchema: diagnosticsArgs
21544
- }, async (args) => backendManager.callTool("typescript", "diagnostics", args));
21545
- server.registerTool("typescript/symbols", {
21546
- description: typescriptToolDescriptions.symbols,
21547
- inputSchema: symbolsArgs
21548
- }, async (args) => backendManager.callTool("typescript", "symbols", args));
21549
- server.registerTool("typescript/rename", {
21550
- description: typescriptToolDescriptions.rename,
21551
- inputSchema: renameArgs
21552
- }, async (args) => backendManager.callTool("typescript", "rename", args));
21553
- server.registerTool("typescript/search", {
21554
- description: typescriptToolDescriptions.search,
21555
- inputSchema: searchArgs
21556
- }, async (args) => backendManager.callTool("typescript", "search", args));
21557
- server.registerTool("typescript/signature_help", {
21558
- description: typescriptToolDescriptions.signature_help,
21559
- inputSchema: positionArgs
21560
- }, async (args) => backendManager.callTool("typescript", "signature_help", args));
21561
- server.registerTool("typescript/update_document", {
21562
- description: typescriptToolDescriptions.update_document,
21563
- inputSchema: updateDocumentArgs
21564
- }, async (args) => backendManager.callTool("typescript", "update_document", args));
21565
- server.registerTool("typescript/status", {
21566
- description: typescriptToolDescriptions.status,
21567
- inputSchema: {
21568
- file: exports_external.string().describe("A TypeScript/JavaScript file to check project status for")
21569
- }
21570
- }, async (args) => backendManager.callTool("typescript", "status", args));
21571
- server.registerTool("typescript/move", {
21572
- description: "Move a function, class, or variable to a new file",
21573
- inputSchema: {
21574
- file: exports_external.string().describe("Absolute path to the file"),
21575
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
21576
- column: exports_external.number().int().positive().describe("Column number (1-based)"),
21577
- destination: exports_external.string().optional().describe("Destination file path (optional)"),
21578
- preview: exports_external.boolean().default(false).describe("If true, only show what would change")
21579
- }
21580
- }, async (args) => backendManager.callTool("typescript", "move", args));
21581
- server.registerTool("typescript/function_signature", {
21582
- description: "Get the current signature of a function at a specific position",
21583
- inputSchema: {
21584
- file: exports_external.string().describe("Absolute path to the file"),
21585
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
21586
- column: exports_external.number().int().positive().describe("Column number (1-based)")
21587
- }
21588
- }, async (args) => backendManager.callTool("typescript", "function_signature", args));
21589
- server.registerTool("typescript/available_refactors", {
21590
- description: "Get available refactoring actions at a specific position",
21591
- inputSchema: {
21592
- file: exports_external.string().describe("Absolute path to the file"),
21593
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
21594
- column: exports_external.number().int().positive().describe("Column number (1-based)")
21595
- }
21596
- }, async (args) => backendManager.callTool("typescript", "available_refactors", args));
21597
- server.registerTool("typescript/apply_refactor", {
21598
- description: "Apply a specific refactoring action at a position",
21599
- inputSchema: {
21600
- file: exports_external.string().describe("Absolute path to the file"),
21601
- line: exports_external.number().int().positive().describe("Line number (1-based)"),
21602
- column: exports_external.number().int().positive().describe("Column number (1-based)"),
21603
- refactorName: exports_external.string().describe("Name of the refactoring"),
21604
- actionName: exports_external.string().describe("Name of the action"),
21605
- preview: exports_external.boolean().default(false).describe("If true, only show what would change")
21606
- }
21607
- }, async (args) => backendManager.callTool("typescript", "apply_refactor", args));
21608
- }
21549
+ server.registerTool("list_backends", {
21550
+ description: "List available backends and their status. Shows which backends are installed, running, and how many tools they provide."
21551
+ }, async () => listBackends(backendManager, config2));
21552
+ server.registerTool("start_backend", {
21553
+ description: "Start a backend and register its tools. This will download and install the backend if needed, then make its tools available.",
21554
+ inputSchema: startBackendSchema
21555
+ }, async ({ language }) => startBackend(language, backendManager, config2, startAndRegisterBackend));
21609
21556
  async function gracefulShutdown(signal) {
21610
21557
  console.error(`
21611
21558
  [lsp-mcp] Received ${signal}, shutting down gracefully...`);
@@ -21623,12 +21570,15 @@ process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
21623
21570
  process.on("SIGINT", () => gracefulShutdown("SIGINT"));
21624
21571
  async function main() {
21625
21572
  console.error("LSP MCP Server - Unified Multi-Language Code Intelligence");
21573
+ console.error(` Version: ${packageJson.version}`);
21626
21574
  console.error(" Python:", config2.python.enabled ? `enabled (${config2.python.provider})` : "disabled");
21627
21575
  console.error(" TypeScript:", config2.typescript.enabled ? "enabled" : "disabled");
21628
21576
  console.error("");
21629
- console.error("Tools are namespaced: python/hover, typescript/definition, etc.");
21577
+ console.error("Backends are loaded on-demand. Use these tools to get started:");
21578
+ console.error(" - list_backends: See available backends and their status");
21579
+ console.error(" - start_backend: Install and start a backend (e.g., start_backend language=python)");
21580
+ console.error("");
21630
21581
  console.error("Prompts available: code-navigation, refactoring, code-analysis, lsp-rules, lsp-quick-start");
21631
- console.error("Backends start lazily on first tool call.");
21632
21582
  console.error("");
21633
21583
  const transport = new StdioServerTransport;
21634
21584
  await server.connect(transport);
@@ -21639,4 +21589,4 @@ main().catch((error2) => {
21639
21589
  process.exit(1);
21640
21590
  });
21641
21591
 
21642
- //# debugId=42A9C81F8A74BE4464756E2164756E21
21592
+ //# debugId=A15518B7EDCDD67064756E2164756E21