Skip to content

Commit

Permalink
refactor: enhance client adapters and multi-client support
Browse files Browse the repository at this point in the history
- Add comprehensive documentation and examples to all client adapters
- Remove legacy supportedClients and supportedTransports fields
- Add multi-client selection for package installation/uninstallation
- Update configuration validation per client requirements
- Add source attribution and official documentation links

Co-Authored-By: Michael Latman <[email protected]>
  • Loading branch information
devin-ai-integration[bot] and michaellatman committed Dec 11, 2024
1 parent b806db7 commit f604f98
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 12 deletions.
24 changes: 24 additions & 0 deletions src/clients/claude-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
/**
* Claude Desktop Adapter
* Source: Internal implementation and configuration schema
*
* Example configuration:
* ```json
* {
* "mcpServers": {
* "my-server": {
* "runtime": "node",
* "command": "/path/to/server",
* "args": ["run"],
* "env": {}
* }
* }
* }
* ```
* Support level: Full (Resources, Prompts, Tools)
* Required fields: command, runtime
* Transports: stdio, sse
* Configuration paths:
* - Windows: %AppData%\Roaming\Claude\claude_desktop_config.json
* - macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
*/
import { ClientAdapter } from './base-adapter.js';
import { ServerConfig, ClientConfig } from '../types/client-config.js';
import * as fs from 'fs/promises';
Expand Down
22 changes: 22 additions & 0 deletions src/clients/continue-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
/**
* Continue Adapter
* Documentation: https://docs.continue.dev
* Source: Continue official documentation and implementation
*
* Example configuration:
* ```json
* {
* "experimental": {
* "modelContextProtocolServer": {
* "command": "/path/to/server",
* "args": ["run"],
* "transport": "stdio"
* }
* }
* }
* ```
* Support level: Full (Resources, Prompts, Tools) through experimental support
* Transports: stdio, sse, websocket
* Installation: VS Code extension or JetBrains plugin
* Configuration path: ~/.continue/config.json
*/
import { ClientAdapter } from './base-adapter.js';
import { ServerConfig, ClientConfig } from '../types/client-config.js';
import * as fs from 'fs/promises';
Expand Down
21 changes: 21 additions & 0 deletions src/clients/firebase-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
/**
* Firebase Genkit Adapter
* Source: Firebase implementation and configuration schema
*
* Example configuration:
* ```json
* {
* "name": "my-server",
* "serverProcess": {
* "command": "/path/to/server",
* "args": ["run"],
* "env": {}
* },
* "transport": "stdio"
* }
* ```
* Support level: Partial (Prompts and Tools, partial Resources)
* Transports: stdio, sse
* Installation: Requires firebase CLI and firebase.json
* Configuration path: .firebase/mcp-config.json
*/
import { ClientAdapter } from './base-adapter.js';
import { ServerConfig, ClientConfig } from '../types/client-config.js';
import * as fs from 'fs/promises';
Expand Down
24 changes: 24 additions & 0 deletions src/clients/zed-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
/**
* Zed Context Server Adapter
* Documentation: https://zed.dev/docs/assistant/context-servers
* Source: Official Zed documentation
*
* Example configuration (from official docs):
* ```json
* {
* "context_servers": {
* "my-server": {
* "command": "/path/to/server",
* "args": ["run"],
* "env": {}
* }
* }
* }
* ```
* Note: transport and runtime fields are not required per official documentation
* Support level: Partial (Prompts only via slash commands)
* Configuration paths:
* - Windows: %AppData%\Zed\settings.json
* - macOS: ~/Library/Application Support/Zed/settings.json
* - Linux: ~/.config/zed/settings.json
*/
import { ClientAdapter } from './base-adapter.js';
import { ServerConfig, ClientConfig } from '../types/client-config.js';
import * as fs from 'fs/promises';
Expand Down
4 changes: 2 additions & 2 deletions src/types/package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export interface Package {
sourceUrl: string;
homepage: string;
license: string;
supportedClients: ('claude' | 'zed' | 'continue' | 'firebase')[];
supportedTransports: ('stdio' | 'sse' | 'websocket')[];
supportedClients?: ('claude' | 'zed' | 'continue' | 'firebase')[];
supportedTransports?: ('stdio' | 'sse' | 'websocket')[];
}

export interface ResolvedPackage extends Package {
Expand Down
12 changes: 9 additions & 3 deletions src/utils/config-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,26 +109,32 @@ export class ConfigManager {
return configManager.preferences.getConfigPath();
}

static async installPackage(pkg: Package): Promise<void> {
static async installPackage(pkg: Package, selectedClients?: ClientType[]): Promise<void> {
const configManager = new ConfigManager();
const config = await configManager.preferences.readConfig();
config.mcpServers = config.mcpServers || {};
config.mcpServers[pkg.name] = {
const serverConfig: ServerConfig = {
name: pkg.name,
runtime: pkg.runtime,
command: `mcp-${pkg.name}`,
args: [],
env: {}
};
await configManager.configureClients(serverConfig, selectedClients);
await configManager.preferences.writeConfig(config);
}

static async uninstallPackage(pkg: Package): Promise<void> {
static async uninstallPackage(pkg: Package, selectedClients?: ClientType[]): Promise<void> {
const configManager = new ConfigManager();
const config = await configManager.preferences.readConfig();
if (config.mcpServers) {
delete config.mcpServers[pkg.name];
await configManager.preferences.writeConfig(config);
const clients = selectedClients || await configManager.getInstalledClients();
for (const clientType of clients) {
const adapter = configManager.getClientAdapter(clientType);
await adapter.writeConfig({ ...pkg, command: '' });
}
}
}

Expand Down
44 changes: 37 additions & 7 deletions src/utils/package-management.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { promisify } from 'util';
import { packageHelpers } from '../helpers/index.js';
import { checkUVInstalled, promptForUVInstall } from './runtime-utils.js';
import { ConfigManager } from './config-manager.js';
import { ClientType } from '../types/client-config.js';

declare function fetch(url: string, init?: any): Promise<{ ok: boolean; statusText: string }>;

Expand Down Expand Up @@ -207,6 +208,16 @@ async function promptForRestart(): Promise<boolean> {
return shouldRestart;
}

async function promptForClientSelection(clients: ClientType[]): Promise<ClientType> {
const { selectedClient } = await inquirer.prompt<{ selectedClient: ClientType }>([{
type: 'list',
name: 'selectedClient',
message: 'Select which client to configure:',
choices: clients
}]);
return selectedClient;
}

export async function installPackage(pkg: Package): Promise<void> {
try {
if (pkg.runtime === 'python') {
Expand All @@ -220,9 +231,18 @@ export async function installPackage(pkg: Package): Promise<void> {
}

const envVars = await promptForEnvVars(pkg.name);

await ConfigManager.installPackage(pkg);
console.log('Updated Claude desktop configuration');
const configManager = new ConfigManager();
const clients = await configManager.getInstalledClients();

if (clients.length > 1) {
const selectedClient = await promptForClientSelection(clients as ClientType[]);
await ConfigManager.installPackage(pkg, [selectedClient]);
} else if (clients.length === 1) {
await ConfigManager.installPackage(pkg, clients);
} else {
throw new Error('No MCP clients installed');
}
console.log(`Updated ${pkg.name} configuration`);

const analyticsAllowed = await checkAnalyticsConsent();
if (analyticsAllowed) {
Expand All @@ -245,11 +265,21 @@ export async function uninstallPackage(packageName: string): Promise<void> {
sourceUrl: '',
homepage: '',
license: '',
runtime: 'node',
supportedClients: ['claude', 'zed', 'continue', 'firebase'],
supportedTransports: ['stdio', 'sse', 'websocket']
runtime: 'node'
};
await ConfigManager.uninstallPackage(pkg);

const configManager = new ConfigManager();
const clients = await configManager.getInstalledClients();

if (clients.length > 1) {
const selectedClient = await promptForClientSelection(clients);
await ConfigManager.uninstallPackage(pkg, [selectedClient as ClientType]);
} else if (clients.length === 1) {
await ConfigManager.uninstallPackage(pkg, clients);
} else {
throw new Error('No MCP clients installed');
}

console.log(`\nUninstalled ${packageName}`);
await promptForRestart();
} catch (error) {
Expand Down

0 comments on commit f604f98

Please sign in to comment.