@theupsider/lsp-mcp 0.1.3 → 0.1.5
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 +23 -2
- package/dist/__tests__/index.test.js +3 -6
- package/dist/index.js +1 -16
- package/mcp.json +12 -0
- package/package.json +9 -3
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ A Model Context Protocol (MCP) server that gives language models access to **Lan
|
|
|
41
41
|
|
|
42
42
|
## Installation
|
|
43
43
|
|
|
44
|
+
> **Important:** Install `lsp-mcp` on the **same machine where your code lives**. The language servers it manages need direct filesystem access to your codebase — they cannot work over a remote connection or on a different machine than your source files.
|
|
45
|
+
|
|
44
46
|
```bash
|
|
45
47
|
# npm
|
|
46
48
|
npm install -g @theupsider/lsp-mcp
|
|
@@ -51,6 +53,26 @@ bun install -g @theupsider/lsp-mcp
|
|
|
51
53
|
|
|
52
54
|
## Quickstart
|
|
53
55
|
|
|
56
|
+
### VS Code / Cursor
|
|
57
|
+
|
|
58
|
+
Add to your **workspace** `.vscode/mcp.json` (recommended — ensures the server runs on the same machine as your code, including SSH remotes, WSL, and Dev Containers):
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"servers": {
|
|
63
|
+
"lsp-mcp": {
|
|
64
|
+
"type": "stdio",
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "@theupsider/lsp-mcp"]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
> **Why workspace config?** VS Code runs servers defined in `.vscode/mcp.json` wherever the workspace lives. Servers defined in your user profile always run locally — which breaks LSP when your code is on a remote machine.
|
|
73
|
+
|
|
74
|
+
### CLI
|
|
75
|
+
|
|
54
76
|
```bash
|
|
55
77
|
# Run the server (reads from stdin, writes to stdout)
|
|
56
78
|
lsp-mcp
|
|
@@ -107,7 +129,6 @@ lsp_init({ root: "/path/to/project", languages: ["python", "typescript"] })
|
|
|
107
129
|
|
|
108
130
|
| Environment Variable | Description | Default |
|
|
109
131
|
| -------------------- | ----------------------------------- | ------------ |
|
|
110
|
-
| `LSP_MCP_ROOT` | Project root (auto-calls `lsp_init` on startup) | _(optional)_ |
|
|
111
132
|
| `LSP_MCP_LOG_LEVEL` | Log level: `error`, `info`, `debug` | `info` |
|
|
112
133
|
|
|
113
134
|
## Setup Scripts
|
|
@@ -152,7 +173,7 @@ gem install solargraph
|
|
|
152
173
|
|
|
153
174
|
### Server not detecting language
|
|
154
175
|
|
|
155
|
-
Ensure your project root contains a language marker file (e.g., `package.json` for TypeScript, `Cargo.toml` for Rust). The server scans the `
|
|
176
|
+
Ensure your project root contains a language marker file (e.g., `package.json` for TypeScript, `Cargo.toml` for Rust). The server scans the directory passed to `lsp_init` for these markers.
|
|
156
177
|
|
|
157
178
|
### High memory usage
|
|
158
179
|
|
|
@@ -12,7 +12,7 @@ describe('index entrypoint', () => {
|
|
|
12
12
|
beforeEach(() => {
|
|
13
13
|
jest.clearAllMocks();
|
|
14
14
|
});
|
|
15
|
-
it('starts and waits for lsp_init
|
|
15
|
+
it('starts and waits for lsp_init', async () => {
|
|
16
16
|
const stderr = jest.fn();
|
|
17
17
|
const exit = jest.fn();
|
|
18
18
|
const McpServer = jest.requireMock('../mcp/server').McpServer;
|
|
@@ -31,15 +31,12 @@ describe('index entrypoint', () => {
|
|
|
31
31
|
expect(stdout).toHaveBeenCalledWith(`${version}\n`);
|
|
32
32
|
expect(exit).toHaveBeenCalledWith(0);
|
|
33
33
|
});
|
|
34
|
-
it('
|
|
34
|
+
it('uses LSP_MCP_LOG_LEVEL and registers signals', async () => {
|
|
35
35
|
const stderr = jest.fn();
|
|
36
36
|
const onSignal = jest.fn();
|
|
37
37
|
const McpServer = jest.requireMock('../mcp/server').McpServer;
|
|
38
|
-
await (0, index_1.main)([], {
|
|
39
|
-
const serverInstance = McpServer.mock.results[0]?.value;
|
|
38
|
+
await (0, index_1.main)([], { LSP_MCP_LOG_LEVEL: 'debug' }, { stderr, onSignal });
|
|
40
39
|
expect(McpServer).toHaveBeenCalledWith('debug');
|
|
41
|
-
expect(serverInstance.initializeManager).toHaveBeenCalledWith('/workspace');
|
|
42
|
-
expect(stderr).toHaveBeenCalledWith(`${JSON.stringify({ languages: ['typescript'], started: ['typescript'], errors: [] })}\n`);
|
|
43
40
|
expect(McpServer).toHaveBeenCalledTimes(1);
|
|
44
41
|
expect(onSignal).toHaveBeenCalledTimes(2);
|
|
45
42
|
});
|
package/dist/index.js
CHANGED
|
@@ -22,17 +22,9 @@ async function main(argv = process.argv.slice(2), env = process.env, overrides =
|
|
|
22
22
|
exit(0);
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
-
const projectRoot = env.LSP_MCP_ROOT;
|
|
26
25
|
const logLevel = env.LSP_MCP_LOG_LEVEL ?? 'info';
|
|
27
26
|
const mcpServer = new server_1.McpServer(logLevel);
|
|
28
|
-
|
|
29
|
-
const initialized = await mcpServer.initializeManager(projectRoot);
|
|
30
|
-
const startupReport = summarizeHealth(initialized.health);
|
|
31
|
-
stderr(`${JSON.stringify(startupReport)}\n`);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
stderr(`${JSON.stringify({ event: 'startup', status: 'waiting-for-init' })}\n`);
|
|
35
|
-
}
|
|
27
|
+
stderr(`${JSON.stringify({ event: 'startup', status: 'waiting-for-init' })}\n`);
|
|
36
28
|
await mcpServer.start();
|
|
37
29
|
const shutdown = async () => {
|
|
38
30
|
await mcpServer.shutdown();
|
|
@@ -41,13 +33,6 @@ async function main(argv = process.argv.slice(2), env = process.env, overrides =
|
|
|
41
33
|
onSignal('SIGINT', shutdown);
|
|
42
34
|
onSignal('SIGTERM', shutdown);
|
|
43
35
|
}
|
|
44
|
-
function summarizeHealth(health) {
|
|
45
|
-
return {
|
|
46
|
-
languages: health.map((entry) => entry.language),
|
|
47
|
-
started: health.filter((entry) => entry.status === 'ready').map((entry) => entry.language),
|
|
48
|
-
errors: health.filter((entry) => entry.status === 'error' && entry.error).map((entry) => entry.error)
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
36
|
function readVersion() {
|
|
52
37
|
const packageJsonPath = node_path_1.default.resolve(__dirname, '..', 'package.json');
|
|
53
38
|
return JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf8')).version;
|
package/mcp.json
ADDED
package/package.json
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theupsider/lsp-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Universal LSP MCP server",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "commonjs",
|
|
7
|
+
"mcpName": "io.github.theupsider/lsp-mcp",
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "David Fischer",
|
|
10
|
+
"url": "https://davidfischer.dev"
|
|
11
|
+
},
|
|
7
12
|
"main": "dist/index.js",
|
|
8
13
|
"bin": {
|
|
9
14
|
"lsp-mcp": "dist/index.js"
|
|
10
15
|
},
|
|
11
16
|
"files": [
|
|
12
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"mcp.json"
|
|
13
19
|
],
|
|
14
20
|
"scripts": {
|
|
15
21
|
"build": "tsc",
|
|
@@ -29,4 +35,4 @@
|
|
|
29
35
|
"ts-jest": "latest",
|
|
30
36
|
"typescript": "latest"
|
|
31
37
|
}
|
|
32
|
-
}
|
|
38
|
+
}
|