Skip to content

Commit c01b260

Browse files
committed
fix: resolve MCP server module resolution and Windows file locking issues
1 parent fdac3d7 commit c01b260

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

scripts/mcp-server.js

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,47 @@
11
#!/usr/bin/env node
22

3+
// 🚀 MCP Diagnostics Bootstrap – ensure additional node_module paths
4+
// This must be executed BEFORE any `require()` that depends on extension-provided
5+
// dependencies (e.g. @modelcontextprotocol/sdk). We read a path from the
6+
// MCP_NODE_MODULES_PATH environment variable that the extension sets when it
7+
// generates the MCP configuration and, if present, push it onto Node's global
8+
// module resolution list so that `require()` can locate the dependency even
9+
// though the standalone server is running from the user's home directory.
10+
const Module = require('module');
11+
if (process.env.MCP_NODE_MODULES_PATH) {
12+
const extra = process.env.MCP_NODE_MODULES_PATH;
13+
if (!Module.globalPaths.includes(extra)) {
14+
Module.globalPaths.push(extra);
15+
}
16+
}
17+
318
/**
419
* Standalone Real VS Code Diagnostics MCP Server - Cross-Platform Enhanced
520
* This script provides REAL diagnostic data from workspace analysis
621
* with full cross-platform compatibility (Windows, macOS, Linux)
722
*/
823

9-
const { Server } = require('../node_modules/@modelcontextprotocol/sdk/dist/cjs/server/index.js');
10-
const { StdioServerTransport } = require('../node_modules/@modelcontextprotocol/sdk/dist/cjs/server/stdio.js');
24+
const path = require('path');
25+
26+
// Resolve SDK paths from injected NODE_MODULES dir (set by VS Code extension)
27+
const NODE_MODULES_DIR =
28+
process.env.MCP_NODE_MODULES_PATH || path.join(__dirname, '..', 'node_modules');
29+
30+
function r(relPath) {
31+
try {
32+
return require(path.join(NODE_MODULES_DIR, relPath));
33+
} catch {
34+
// Fallback to Node's resolver (will succeed when script runs inside extension dir)
35+
return require(relPath.startsWith('@') ? relPath : path.join('..', 'node_modules', relPath));
36+
}
37+
}
38+
39+
const { Server } = r('@modelcontextprotocol/sdk/dist/cjs/server/index.js');
40+
const { StdioServerTransport } = r('@modelcontextprotocol/sdk/dist/cjs/server/stdio.js');
1141
const {
1242
CallToolRequestSchema,
1343
ListToolsRequestSchema
14-
} = require('../node_modules/@modelcontextprotocol/sdk/dist/cjs/types.js');
15-
const path = require('path');
44+
} = r('@modelcontextprotocol/sdk/dist/cjs/types.js');
1645
const fs = require('fs');
1746
const { spawn } = require('child_process');
1847

src/infrastructure/mcp/McpServerRegistration.ts

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ interface McpServerConfig {
1010
type: string;
1111
command: string;
1212
args: string[];
13-
env: {
14-
NODE_ENV: string;
15-
MCP_DEBUG: string;
16-
};
13+
env: Record<string, string>;
1714
}
1815

1916
interface McpConfiguration {
@@ -120,11 +117,17 @@ export class McpServerRegistration {
120117
* Returns the destination path and whether the file was (re)deployed.
121118
*/
122119
public async deployBundledServer(): Promise<{ installedPath: string; upgraded: boolean }> {
120+
// Priority order: always prefer the fully-featured development script; the
121+
// `dist/assets` copy may be a tiny stub used by the bundler for tree-shaken
122+
// production builds. Choosing it first led to a 29-byte file that only
123+
// prints "Activation test" – the root cause of the empty server you saw
124+
// in C:\Users\<user>\.mcp-diagnostics .
125+
123126
const bundledPathVariants = [
124-
// When running from VS Code extension build output (webpack/rollup)
125-
path.join(this.context.extensionPath, 'dist', 'assets', 'mcp-server.js'),
126-
// Fallback – raw script in repo (development)
127+
// 1️⃣ Raw script in repo (development & CI) – **always** the full file
127128
path.join(this.context.extensionPath, 'scripts', 'mcp-server.js'),
129+
// 2️⃣ Compiled asset produced by rollup/webpack for marketplace builds
130+
path.join(this.context.extensionPath, 'dist', 'assets', 'mcp-server.js'),
128131
];
129132

130133
const bundledPath = bundledPathVariants.find((p) => fs.existsSync(p));
@@ -148,9 +151,28 @@ export class McpServerRegistration {
148151
})();
149152

150153
if (needCopy) {
151-
fs.copyFileSync(bundledPath, destPath);
152-
upgraded = true;
153-
console.log('[MCP Registration] Deployed bundled server to:', destPath);
154+
try {
155+
fs.copyFileSync(bundledPath, destPath);
156+
upgraded = true;
157+
console.log('[MCP Registration] Deployed bundled server to:', destPath);
158+
} catch (copyError) {
159+
const code =
160+
copyError && typeof copyError === 'object' && 'code' in copyError
161+
? (copyError as NodeJS.ErrnoException).code
162+
: undefined;
163+
164+
// Windows locks the file if the previous process has not released the
165+
// handle yet. Rather than failing the whole activation we tolerate
166+
// the common lock codes and keep using the previously deployed copy.
167+
if (code === 'EBUSY' || code === 'EPERM' || code === 'EACCES') {
168+
console.warn(
169+
'[MCP Registration] Destination file locked – using existing server binary'
170+
);
171+
upgraded = false;
172+
} else {
173+
throw copyError;
174+
}
175+
}
154176
} else {
155177
console.log('[MCP Registration] Existing server up-to-date at:', destPath);
156178
}
@@ -343,6 +365,7 @@ export class McpServerRegistration {
343365
env: {
344366
NODE_ENV: 'production',
345367
MCP_DEBUG: 'false',
368+
MCP_NODE_MODULES_PATH: path.join(this.context.extensionPath, 'node_modules'),
346369
},
347370
};
348371

@@ -719,6 +742,7 @@ export class McpServerRegistration {
719742
env: {
720743
NODE_ENV: 'production',
721744
MCP_DEBUG: 'false',
745+
MCP_NODE_MODULES_PATH: path.join(this.context.extensionPath, 'node_modules'),
722746
},
723747
version: '1.0.0',
724748
});
@@ -782,6 +806,7 @@ export class McpServerRegistration {
782806
env: {
783807
NODE_ENV: 'production',
784808
MCP_DEBUG: 'false',
809+
MCP_NODE_MODULES_PATH: path.join(this.context.extensionPath, 'node_modules'),
785810
},
786811
};
787812
}
@@ -1006,7 +1031,8 @@ export class McpServerRegistration {
10061031
],
10071032
"env": {
10081033
"NODE_ENV": "production",
1009-
"MCP_DEBUG": "false"
1034+
"MCP_DEBUG": "false",
1035+
"MCP_NODE_MODULES_PATH": "${path.join(this.context.extensionPath, 'node_modules')}"
10101036
}
10111037
}
10121038
}
@@ -1032,7 +1058,8 @@ export class McpServerRegistration {
10321058
],
10331059
"env": {
10341060
"NODE_ENV": "production",
1035-
"MCP_DEBUG": "false"
1061+
"MCP_DEBUG": "false",
1062+
"MCP_NODE_MODULES_PATH": "${path.join(this.context.extensionPath, 'node_modules')}"
10361063
}
10371064
}
10381065
}

0 commit comments

Comments
 (0)