Skip to content

Commit a7217d5

Browse files
authored
feat: allow feature selection during MCP setup (#140)
1 parent b2d779e commit a7217d5

7 files changed

Lines changed: 132 additions & 27 deletions

File tree

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ export abstract class MCPClient {
88
abstract getConfigPath(): Promise<string>;
99
abstract getServerPropertyName(): string;
1010
abstract isServerInstalled(): Promise<boolean>;
11-
abstract addServer(apiKey: string): Promise<{ success: boolean }>;
11+
abstract addServer(
12+
apiKey: string,
13+
selectedFeatures?: string[],
14+
): Promise<{ success: boolean }>;
1215
abstract removeServer(): Promise<{ success: boolean }>;
1316
abstract isClientSupported(): Promise<boolean>;
1417
}
@@ -24,8 +27,12 @@ export abstract class DefaultMCPClient extends MCPClient {
2427
return 'mcpServers';
2528
}
2629

27-
getServerConfig(apiKey: string, type: 'sse' | 'streamable-http') {
28-
return getDefaultServerConfig(apiKey, type);
30+
getServerConfig(
31+
apiKey: string,
32+
type: 'sse' | 'streamable-http',
33+
selectedFeatures?: string[],
34+
) {
35+
return getDefaultServerConfig(apiKey, type, selectedFeatures);
2936
}
3037

3138
async isServerInstalled(): Promise<boolean> {
@@ -47,13 +54,17 @@ export abstract class DefaultMCPClient extends MCPClient {
4754
}
4855
}
4956

50-
async addServer(apiKey: string): Promise<{ success: boolean }> {
51-
return this._addServerType(apiKey, 'sse');
57+
async addServer(
58+
apiKey: string,
59+
selectedFeatures?: string[],
60+
): Promise<{ success: boolean }> {
61+
return this._addServerType(apiKey, 'sse', selectedFeatures);
5262
}
5363

5464
async _addServerType(
5565
apiKey: string,
5666
type: 'sse' | 'streamable-http',
67+
selectedFeatures?: string[],
5768
): Promise<{ success: boolean }> {
5869
try {
5970
const configPath = await this.getConfigPath();
@@ -70,7 +81,11 @@ export abstract class DefaultMCPClient extends MCPClient {
7081
existingConfig = jsonc.parse(configContent) || {};
7182
}
7283

73-
const newServerConfig = this.getServerConfig(apiKey, type);
84+
const newServerConfig = this.getServerConfig(
85+
apiKey,
86+
type,
87+
selectedFeatures,
88+
);
7489
const typedConfig = existingConfig as Record<string, any>;
7590
if (!typedConfig[serverPropertyName]) {
7691
typedConfig[serverPropertyName] = {};

src/steps/add-mcp-server-to-clients/clients/__tests__/claude.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ describe('ClaudeMCPClient', () => {
327327
expect(getDefaultServerConfigMock).toHaveBeenCalledWith(
328328
mockApiKey,
329329
'sse',
330+
undefined,
330331
);
331332
});
332333
});

src/steps/add-mcp-server-to-clients/clients/claude-code.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ export class ClaudeCodeMCPClient extends DefaultMCPClient {
4545
throw new Error('Not implemented');
4646
}
4747

48-
addServer(apiKey: string): Promise<{ success: boolean }> {
49-
const config = getDefaultServerConfig(apiKey, 'sse');
48+
addServer(
49+
apiKey: string,
50+
selectedFeatures?: string[],
51+
): Promise<{ success: boolean }> {
52+
const config = getDefaultServerConfig(apiKey, 'sse', selectedFeatures);
5053

5154
const command = `claude mcp add-json posthog -s user '${JSON.stringify(
5255
config,

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ export class CursorMCPClient extends DefaultMCPClient {
2525
return Promise.resolve(path.join(os.homedir(), '.cursor', 'mcp.json'));
2626
}
2727

28-
async addServer(apiKey: string): Promise<{ success: boolean }> {
29-
return this._addServerType(apiKey, 'sse');
28+
async addServer(
29+
apiKey: string,
30+
selectedFeatures?: string[],
31+
): Promise<{ success: boolean }> {
32+
return this._addServerType(apiKey, 'sse', selectedFeatures);
3033
}
3134
}

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ export class ZedClient extends DefaultMCPClient {
6161
throw new Error(`Unsupported platform: ${process.platform}`);
6262
}
6363

64-
getServerConfig(apiKey: string, type: 'sse' | 'streamable-http') {
65-
const baseConfig = getDefaultServerConfig(apiKey, type);
64+
getServerConfig(
65+
apiKey: string,
66+
type: 'sse' | 'streamable-http',
67+
selectedFeatures?: string[],
68+
) {
69+
const baseConfig = getDefaultServerConfig(apiKey, type, selectedFeatures);
6670
return {
6771
enabled: true,
6872
source: 'custom',

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

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,85 @@ export const DefaultMCPClientConfig = z
1313
})
1414
.passthrough();
1515

16+
export const AVAILABLE_FEATURES = {
17+
'Data & Analytics': [
18+
{
19+
value: 'dashboards',
20+
label: 'Dashboards',
21+
hint: 'Dashboard creation and management',
22+
},
23+
{
24+
value: 'insights',
25+
label: 'Insights',
26+
hint: 'Analytics insights and SQL queries',
27+
},
28+
{
29+
value: 'experiments',
30+
label: 'Experiments',
31+
hint: 'A/B testing experiments',
32+
},
33+
{
34+
value: 'llm-analytics',
35+
label: 'LLM Analytics',
36+
hint: 'LLM usage and cost tracking',
37+
},
38+
],
39+
'Development Tools': [
40+
{
41+
value: 'error-tracking',
42+
label: 'Error Tracking',
43+
hint: 'Error monitoring and debugging',
44+
},
45+
{ value: 'flags', label: 'Feature Flags', hint: 'Feature flag management' },
46+
],
47+
'Platform & Management': [
48+
{
49+
value: 'workspace',
50+
label: 'Workspace',
51+
hint: 'Organization and project management',
52+
},
53+
{
54+
value: 'docs',
55+
label: 'Documentation',
56+
hint: 'PostHog documentation search',
57+
},
58+
],
59+
};
60+
61+
export const ALL_FEATURE_VALUES = Object.values(AVAILABLE_FEATURES)
62+
.flat()
63+
.map((feature) => feature.value);
64+
1665
type MCPServerType = 'sse' | 'streamable-http';
1766

1867
export const getDefaultServerConfig = (
1968
apiKey: string,
2069
type: MCPServerType,
21-
) => ({
22-
command: 'npx',
23-
args: [
24-
'-y',
25-
'mcp-remote@latest',
26-
`https://mcp.posthog.com/${type === 'sse' ? 'sse' : 'mcp'}`,
27-
'--header',
28-
`Authorization:\${POSTHOG_AUTH_HEADER}`,
29-
],
30-
env: {
31-
POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,
32-
},
33-
});
70+
selectedFeatures?: string[],
71+
) => {
72+
const baseUrl = `https://mcp.posthog.com/${type === 'sse' ? 'sse' : 'mcp'}`;
73+
74+
const isAllFeaturesSelected =
75+
selectedFeatures &&
76+
selectedFeatures.length === ALL_FEATURE_VALUES.length &&
77+
ALL_FEATURE_VALUES.every((feature) => selectedFeatures.includes(feature));
78+
79+
const urlWithFeatures =
80+
selectedFeatures && selectedFeatures.length > 0 && !isAllFeaturesSelected
81+
? `${baseUrl}?features=${selectedFeatures.join(',')}`
82+
: baseUrl;
83+
84+
return {
85+
command: 'npx',
86+
args: [
87+
'-y',
88+
'mcp-remote@latest',
89+
urlWithFeatures,
90+
'--header',
91+
`Authorization:\${POSTHOG_AUTH_HEADER}`,
92+
],
93+
env: {
94+
POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,
95+
},
96+
};
97+
};

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { CloudRegion } from '../../utils/types';
1212
import { ClaudeCodeMCPClient } from './clients/claude-code';
1313
import { VisualStudioCodeClient } from './clients/visual-studio-code';
1414
import { ZedClient } from './clients/zed';
15+
import { AVAILABLE_FEATURES, ALL_FEATURE_VALUES } from './defaults';
1516

1617
export const getSupportedClients = async (): Promise<MCPClient[]> => {
1718
const allClients = [
@@ -61,6 +62,19 @@ export const addMCPServerToClientsStep = async ({
6162
return [];
6263
}
6364

65+
const { groupMultiselect } = await import('@clack/prompts');
66+
const selectedFeatures = await abortIfCancelled(
67+
groupMultiselect({
68+
message: `Select which PostHog features to enable as tools: ${chalk.dim(
69+
'(Toggle: Space, Confirm: Enter, Toggle All: A, Cancel: CTRL + C)',
70+
)}`,
71+
options: AVAILABLE_FEATURES,
72+
initialValues: [...ALL_FEATURE_VALUES],
73+
required: false,
74+
}),
75+
integration,
76+
);
77+
6478
const supportedClients = await getSupportedClients();
6579

6680
const { multiselect } = await import('@clack/prompts');
@@ -127,7 +141,7 @@ export const addMCPServerToClientsStep = async ({
127141
const personalApiKey = await getPersonalApiKey({ cloudRegion: region });
128142

129143
await traceStep('adding mcp servers', async () => {
130-
await addMCPServer(clients, personalApiKey);
144+
await addMCPServer(clients, personalApiKey, selectedFeatures);
131145
});
132146

133147
clack.log.success(
@@ -215,9 +229,10 @@ export const getInstalledClients = async (): Promise<MCPClient[]> => {
215229
export const addMCPServer = async (
216230
clients: MCPClient[],
217231
personalApiKey: string,
232+
selectedFeatures?: string[],
218233
): Promise<void> => {
219234
for (const client of clients) {
220-
await client.addServer(personalApiKey);
235+
await client.addServer(personalApiKey, selectedFeatures);
221236
}
222237
};
223238

0 commit comments

Comments
 (0)