fix: Update VS Code profile with MCP config transformation (#971)
* remove dash in server name * add OLLAMA_API_KEY to VS Code MCP instructions * transform vscode mcp to correct format * add changeset * switch back to task-master-ai * use task-master-ai
This commit is contained in:
@@ -1,6 +1,162 @@
|
||||
// VS Code conversion profile for rule-transformer
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { log } from '../../scripts/modules/utils.js';
|
||||
import { createProfile, COMMON_TOOL_MAPPINGS } from './base-profile.js';
|
||||
|
||||
/**
|
||||
* Transform standard MCP config format to VS Code format
|
||||
* @param {Object} mcpConfig - Standard MCP configuration object
|
||||
* @returns {Object} - Transformed VS Code configuration object
|
||||
*/
|
||||
function transformToVSCodeFormat(mcpConfig) {
|
||||
const vscodeConfig = {};
|
||||
|
||||
// Transform mcpServers to servers
|
||||
if (mcpConfig.mcpServers) {
|
||||
vscodeConfig.servers = {};
|
||||
|
||||
for (const [serverName, serverConfig] of Object.entries(
|
||||
mcpConfig.mcpServers
|
||||
)) {
|
||||
// Transform server configuration
|
||||
const transformedServer = {
|
||||
...serverConfig
|
||||
};
|
||||
|
||||
// Add type: "stdio" after the env block
|
||||
if (transformedServer.env) {
|
||||
// Reorder properties: keep command, args, env, then add type
|
||||
const reorderedServer = {};
|
||||
if (transformedServer.command)
|
||||
reorderedServer.command = transformedServer.command;
|
||||
if (transformedServer.args)
|
||||
reorderedServer.args = transformedServer.args;
|
||||
if (transformedServer.env) reorderedServer.env = transformedServer.env;
|
||||
reorderedServer.type = 'stdio';
|
||||
|
||||
// Add any other properties that might exist
|
||||
Object.keys(transformedServer).forEach((key) => {
|
||||
if (!['command', 'args', 'env', 'type'].includes(key)) {
|
||||
reorderedServer[key] = transformedServer[key];
|
||||
}
|
||||
});
|
||||
|
||||
vscodeConfig.servers[serverName] = reorderedServer;
|
||||
} else {
|
||||
// If no env block, just add type at the end
|
||||
transformedServer.type = 'stdio';
|
||||
vscodeConfig.servers[serverName] = transformedServer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vscodeConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle function called after MCP config generation to transform to VS Code format
|
||||
* @param {string} targetDir - Target project directory
|
||||
* @param {string} assetsDir - Assets directory (unused for VS Code)
|
||||
*/
|
||||
function onPostConvertRulesProfile(targetDir, assetsDir) {
|
||||
const vscodeConfigPath = path.join(targetDir, '.vscode', 'mcp.json');
|
||||
|
||||
if (!fs.existsSync(vscodeConfigPath)) {
|
||||
log('debug', '[VS Code] No .vscode/mcp.json found to transform');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Read the generated standard MCP config
|
||||
const mcpConfigContent = fs.readFileSync(vscodeConfigPath, 'utf8');
|
||||
const mcpConfig = JSON.parse(mcpConfigContent);
|
||||
|
||||
// Check if it's already in VS Code format (has servers instead of mcpServers)
|
||||
if (mcpConfig.servers) {
|
||||
log(
|
||||
'info',
|
||||
'[VS Code] mcp.json already in VS Code format, skipping transformation'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Transform to VS Code format
|
||||
const vscodeConfig = transformToVSCodeFormat(mcpConfig);
|
||||
|
||||
// Write back the transformed config with proper formatting
|
||||
fs.writeFileSync(
|
||||
vscodeConfigPath,
|
||||
JSON.stringify(vscodeConfig, null, 2) + '\n'
|
||||
);
|
||||
|
||||
log('info', '[VS Code] Transformed mcp.json to VS Code format');
|
||||
log('debug', `[VS Code] Renamed mcpServers->servers, added type: "stdio"`);
|
||||
} catch (error) {
|
||||
log('error', `[VS Code] Failed to transform mcp.json: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lifecycle function called when removing VS Code profile
|
||||
* @param {string} targetDir - Target project directory
|
||||
*/
|
||||
function onRemoveRulesProfile(targetDir) {
|
||||
const vscodeConfigPath = path.join(targetDir, '.vscode', 'mcp.json');
|
||||
|
||||
if (!fs.existsSync(vscodeConfigPath)) {
|
||||
log('debug', '[VS Code] No .vscode/mcp.json found to clean up');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Read the current config
|
||||
const configContent = fs.readFileSync(vscodeConfigPath, 'utf8');
|
||||
const config = JSON.parse(configContent);
|
||||
|
||||
// Check if it has the servers section and task-master-ai server
|
||||
if (config.servers && config.servers['task-master-ai']) {
|
||||
// Remove task-master-ai server
|
||||
delete config.servers['task-master-ai'];
|
||||
|
||||
// Check if there are other MCP servers
|
||||
const remainingServers = Object.keys(config.servers);
|
||||
|
||||
if (remainingServers.length === 0) {
|
||||
// No other servers, remove entire file
|
||||
fs.rmSync(vscodeConfigPath, { force: true });
|
||||
log('info', '[VS Code] Removed empty mcp.json file');
|
||||
|
||||
// Also remove .vscode directory if it's empty
|
||||
const vscodeDir = path.dirname(vscodeConfigPath);
|
||||
try {
|
||||
const dirContents = fs.readdirSync(vscodeDir);
|
||||
if (dirContents.length === 0) {
|
||||
fs.rmSync(vscodeDir, { recursive: true, force: true });
|
||||
log('debug', '[VS Code] Removed empty .vscode directory');
|
||||
}
|
||||
} catch (err) {
|
||||
// Directory might not be empty or might not exist, that's fine
|
||||
}
|
||||
} else {
|
||||
// Write back the modified config
|
||||
fs.writeFileSync(
|
||||
vscodeConfigPath,
|
||||
JSON.stringify(config, null, 2) + '\n'
|
||||
);
|
||||
log(
|
||||
'info',
|
||||
'[VS Code] Removed TaskMaster from mcp.json, preserved other configurations'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log('debug', '[VS Code] TaskMaster not found in mcp.json');
|
||||
}
|
||||
} catch (error) {
|
||||
log('error', `[VS Code] Failed to clean up mcp.json: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export vscode profile using the base factory
|
||||
export const vscodeProfile = createProfile({
|
||||
name: 'vscode',
|
||||
@@ -8,6 +164,8 @@ export const vscodeProfile = createProfile({
|
||||
url: 'code.visualstudio.com',
|
||||
docsUrl: 'code.visualstudio.com/docs',
|
||||
rulesDir: '.github/instructions', // VS Code instructions location
|
||||
profileDir: '.vscode', // VS Code configuration directory
|
||||
mcpConfigName: 'mcp.json', // VS Code uses mcp.json in .vscode directory
|
||||
customReplacements: [
|
||||
// Core VS Code directory structure changes
|
||||
{ from: /\.cursor\/rules/g, to: '.github/instructions' },
|
||||
@@ -28,5 +186,10 @@ export const vscodeProfile = createProfile({
|
||||
// VS Code specific terminology
|
||||
{ from: /rules directory/g, to: 'instructions directory' },
|
||||
{ from: /cursor rules/gi, to: 'VS Code instructions' }
|
||||
]
|
||||
],
|
||||
onPostConvert: onPostConvertRulesProfile,
|
||||
onRemove: onRemoveRulesProfile
|
||||
});
|
||||
|
||||
// Export lifecycle functions separately to avoid naming conflicts
|
||||
export { onPostConvertRulesProfile, onRemoveRulesProfile };
|
||||
|
||||
Reference in New Issue
Block a user