Skip to content

Commit 2f60fd5

Browse files
authored
feat: add vscode mcp client (#126)
1 parent abe2113 commit 2f60fd5

3 files changed

Lines changed: 91 additions & 7 deletions

File tree

src/steps/add-mcp-server-to-clients/MCPClient.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { merge } from 'lodash';
66
export abstract class MCPClient {
77
name: string;
88
abstract getConfigPath(): Promise<string>;
9+
abstract getServerPropertyName(): string;
910
abstract isServerInstalled(): Promise<boolean>;
1011
abstract addServer(apiKey: string): Promise<{ success: boolean }>;
1112
abstract removeServer(): Promise<{ success: boolean }>;
@@ -18,6 +19,11 @@ export abstract class DefaultMCPClient extends MCPClient {
1819
constructor() {
1920
super();
2021
}
22+
23+
getServerPropertyName(): string {
24+
return 'mcpServers';
25+
}
26+
2127
async isServerInstalled(): Promise<boolean> {
2228
try {
2329
const configPath = await this.getConfigPath();
@@ -28,8 +34,10 @@ export abstract class DefaultMCPClient extends MCPClient {
2834

2935
const configContent = await fs.promises.readFile(configPath, 'utf8');
3036
const config = JSON.parse(configContent);
31-
32-
return 'mcpServers' in config && 'posthog' in config.mcpServers;
37+
const serverPropertyName = this.getServerPropertyName();
38+
return (
39+
serverPropertyName in config && 'posthog' in config[serverPropertyName]
40+
);
3341
} catch {
3442
return false;
3543
}
@@ -49,8 +57,9 @@ export abstract class DefaultMCPClient extends MCPClient {
4957

5058
await fs.promises.mkdir(configDir, { recursive: true });
5159

60+
const serverPropertyName = this.getServerPropertyName();
5261
const newServerConfig = {
53-
mcpServers: {
62+
[serverPropertyName]: {
5463
posthog: getDefaultServerConfig(apiKey, type),
5564
},
5665
};
@@ -87,9 +96,13 @@ export abstract class DefaultMCPClient extends MCPClient {
8796

8897
const configContent = await fs.promises.readFile(configPath, 'utf8');
8998
const config = JSON.parse(configContent);
99+
const serverPropertyName = this.getServerPropertyName();
90100

91-
if ('mcpServers' in config && 'posthog' in config.mcpServers) {
92-
delete config.mcpServers.posthog;
101+
if (
102+
serverPropertyName in config &&
103+
'posthog' in config[serverPropertyName]
104+
) {
105+
delete config[serverPropertyName].posthog;
93106

94107
await fs.promises.writeFile(
95108
configPath,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import z from 'zod';
2+
import * as path from 'path';
3+
import * as os from 'os';
4+
import { DefaultMCPClient } from '../MCPClient';
5+
6+
export const VisualStudioCodeMCPConfig = z
7+
.object({
8+
servers: z.record(
9+
z.string(),
10+
z.object({
11+
command: z.string().optional(),
12+
args: z.array(z.string()).optional(),
13+
env: z.record(z.string(), z.string()).optional(),
14+
}),
15+
),
16+
})
17+
.passthrough();
18+
19+
export type VisualStudioCodeMCPConfig = z.infer<
20+
typeof VisualStudioCodeMCPConfig
21+
>;
22+
23+
export class VisualStudioCodeClient extends DefaultMCPClient {
24+
name = 'Visual Studio Code';
25+
26+
getServerPropertyName(): string {
27+
return 'servers';
28+
}
29+
30+
async isClientSupported(): Promise<boolean> {
31+
return Promise.resolve(
32+
process.platform === 'darwin' ||
33+
process.platform === 'win32' ||
34+
process.platform === 'linux',
35+
);
36+
}
37+
38+
async getConfigPath(): Promise<string> {
39+
const homeDir = os.homedir();
40+
const isWindows = process.platform === 'win32';
41+
const isMac = process.platform === 'darwin';
42+
const isLinux = process.platform === 'linux';
43+
44+
if (isMac) {
45+
return Promise.resolve(
46+
path.join(
47+
homeDir,
48+
'Library',
49+
'Application Support',
50+
'Code',
51+
'User',
52+
'mcp.json',
53+
),
54+
);
55+
}
56+
57+
if (isWindows) {
58+
return Promise.resolve(
59+
path.join(process.env.APPDATA || '', 'Code', 'User', 'mcp.json'),
60+
);
61+
}
62+
63+
if (isLinux) {
64+
return Promise.resolve(
65+
path.join(homeDir, '.config', 'Code', 'User', 'mcp.json'),
66+
);
67+
}
68+
69+
throw new Error(`Unsupported platform: ${process.platform}`);
70+
}
71+
}

src/steps/add-mcp-server-to-clients/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import { ClaudeMCPClient } from './clients/claude';
1010
import { getPersonalApiKey } from '../../mcp';
1111
import type { CloudRegion } from '../../utils/types';
1212
import { ClaudeCodeMCPClient } from './clients/claude-code';
13+
import { VisualStudioCodeClient } from './clients/visual-studio-code';
1314

1415
export const getSupportedClients = async (): Promise<MCPClient[]> => {
1516
const allClients = [
1617
new CursorMCPClient(),
1718
new ClaudeMCPClient(),
1819
new ClaudeCodeMCPClient(),
20+
new VisualStudioCodeClient(),
1921
];
2022
const supportedClients: MCPClient[] = [];
2123

@@ -146,7 +148,6 @@ export const removeMCPServerFromClientsStep = async ({
146148
integration?: Integration;
147149
}): Promise<string[]> => {
148150
const installedClients = await getInstalledClients();
149-
150151
if (installedClients.length === 0) {
151152
analytics.capture('wizard interaction', {
152153
action: 'no mcp servers to remove',
@@ -198,7 +199,6 @@ export const removeMCPServerFromClientsStep = async ({
198199

199200
export const getInstalledClients = async (): Promise<MCPClient[]> => {
200201
const clients = await getSupportedClients();
201-
202202
const installedClients: MCPClient[] = [];
203203

204204
for (const client of clients) {

0 commit comments

Comments
 (0)