Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/steps/add-mcp-server-to-clients/MCPClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export abstract class DefaultMCPClient extends MCPClient {
}

async addServer(apiKey: string): Promise<{ success: boolean }> {
return this._addServerType(apiKey, 'streamable-http');
return this._addServerType(apiKey, 'sse');
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the default server type from 'streamable-http' to 'sse' is a breaking change that affects all existing MCP clients. This should be documented and may require version migration logic.

Copilot uses AI. Check for mistakes.
}

async _addServerType(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ describe('ClaudeMCPClient', () => {

expect(getDefaultServerConfigMock).toHaveBeenCalledWith(
mockApiKey,
'streamable-http',
'sse',
);
});
});
Expand Down
66 changes: 66 additions & 0 deletions src/steps/add-mcp-server-to-clients/clients/claude-code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { DefaultMCPClient } from '../MCPClient';
import { DefaultMCPClientConfig, getDefaultServerConfig } from '../defaults';
import { z } from 'zod';
import { execSync } from 'child_process';

export const ClaudeCodeMCPConfig = DefaultMCPClientConfig;

export type ClaudeCodeMCPConfig = z.infer<typeof DefaultMCPClientConfig>;

export class ClaudeCodeMCPClient extends DefaultMCPClient {
name = 'Claude Code';

constructor() {
super();
}

isClientSupported(): Promise<boolean> {
try {
execSync('claude --version', { stdio: 'ignore' });
return Promise.resolve(true);
} catch {
return Promise.resolve(false);
}
}

isServerInstalled(): Promise<boolean> {
try {
// check if posthog in output
const output = execSync('claude mcp list', {
stdio: 'pipe',
});

if (output.toString().includes('posthog')) {
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding 'posthog' as the server name makes this check specific to one server type. Consider making this configurable or using a more generic approach to detect installed servers.

Suggested change
if (output.toString().includes('posthog')) {
if (output.toString().includes(this.serverName)) {

Copilot uses AI. Check for mistakes.
return Promise.resolve(true);
}
} catch {
//
}

return Promise.resolve(false);
}

getConfigPath(): Promise<string> {
throw new Error('Not implemented');
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getConfigPath method throws 'Not implemented' but this method is part of the MCPClient interface. Either implement this method or mark it as optional in the interface if it's not needed for Claude Code.

Suggested change
throw new Error('Not implemented');
// Assuming Claude Code stores config at ~/.claude/config.json
const configPath = `${process.env.HOME || process.env.USERPROFILE}/.claude/config.json`;
return Promise.resolve(configPath);

Copilot uses AI. Check for mistakes.
}

addServer(apiKey: string): Promise<{ success: boolean }> {
const config = getDefaultServerConfig(apiKey, 'sse');

const command = `claude mcp add-json posthog -s user '${JSON.stringify(
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding 'posthog' as the server name in the command makes this client specific to PostHog servers. Consider parameterizing the server name to make this more generic.

Suggested change
const command = `claude mcp add-json posthog -s user '${JSON.stringify(
const command = `claude mcp add-json ${this.serverName} -s user '${JSON.stringify(

Copilot uses AI. Check for mistakes.
config,
)}'`;

execSync(command);

Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using execSync with a command that includes JSON.stringify(config) could be vulnerable to command injection if the config contains malicious content. Consider using safer command execution methods or proper escaping.

Suggested change
// Use argument array to avoid command injection
execSync(
'claude',
[
'mcp',
'add-json',
'posthog',
'-s',
'user',
JSON.stringify(config),
],
{ stdio: 'ignore', shell: false }
);

Copilot uses AI. Check for mistakes.
return Promise.resolve({ success: true });
}

removeServer(): Promise<{ success: boolean }> {
const command = `claude mcp remove --scope user posthog`;
Copy link

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding 'posthog' as the server name in the remove command creates the same maintainability issue as in addServer. Consider making the server name configurable.

Suggested change
const command = `claude mcp remove --scope user posthog`;
const command = `claude mcp remove --scope user ${this.serverName}`;

Copilot uses AI. Check for mistakes.

execSync(command);

return Promise.resolve({ success: true });
}
}
7 changes: 6 additions & 1 deletion src/steps/add-mcp-server-to-clients/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ import { CursorMCPClient } from './clients/cursor';
import { ClaudeMCPClient } from './clients/claude';
import { getPersonalApiKey } from '../../mcp';
import type { CloudRegion } from '../../utils/types';
import { ClaudeCodeMCPClient } from './clients/claude-code';

export const getSupportedClients = async (): Promise<MCPClient[]> => {
const allClients = [new CursorMCPClient(), new ClaudeMCPClient()];
const allClients = [
new CursorMCPClient(),
new ClaudeMCPClient(),
new ClaudeCodeMCPClient(),
];
const supportedClients: MCPClient[] = [];

for (const client of allClients) {
Expand Down
Loading