Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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: 2 additions & 0 deletions packages/cli/lib/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
doc,
generate,
list,
mcp,
newCommand,
start,
test,
Expand Down Expand Up @@ -54,6 +55,7 @@ export async function run(args = null) {
.command(test)
.command(list)
.command(upgrade)
.command(mcp)
.version(false) // disable built-in `yargs.version` to override it with our custom option
.options({
version: {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/lib/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { default as config } from "./config";
export { default as doc } from "./doc";
export { default as generate } from "./generate";
export { default as list } from "./list";
export { default as mcp } from "./mcp";
export { default as newCommand } from "./new";
export { default as start } from "./start";
export { default as test } from "./test";
Expand Down
125 changes: 125 additions & 0 deletions packages/cli/lib/commands/mcp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { GoogleAnalytics, Util } from "@igniteui/cli-core";
import { ArgumentsCamelCase, CommandModule } from "yargs";
import * as path from "path";
import * as fs from "fs";
import { homedir } from "os";

const MCP_SERVER_KEY = "igniteui-mcp-server";


function resolveMcpEntry(): { command: string; args: string[] } {
// Resolve the MCP server entry from the CLI's own node_modules.
// This works in both the monorepo (file: dep) and when the CLI is globally installed.
try {
const pkgEntry = require.resolve("igniteui-mcp-server");
return { command: "node", args: [pkgEntry] };
} catch {
// Not installed alongside the CLI — download and run on demand via npx
return { command: "npx", args: ["-y", "igniteui-mcp-server"] };
Comment on lines +14 to +18
}
}

type Client = "vscode" | "claude";

interface McpServerEntry {
command: string;
args: string[];
}

interface VsCodeMcpConfig {
servers: Record<string, McpServerEntry>;
}

interface ClaudeDesktopConfig {
mcpServers: Record<string, McpServerEntry>;
}

function getConfigPath(client: Client): string {
switch (client) {
case "vscode":
return path.join(process.cwd(), ".vscode", "mcp.json");
case "claude": {
const platform = process.platform;
if (platform === "win32") {
return path.join(process.env.APPDATA || homedir(), "Claude", "claude_desktop_config.json");
} else if (platform === "darwin") {
return path.join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
} else {
return path.join(homedir(), ".config", "Claude", "claude_desktop_config.json");
}
}
}
}

function readJson<T>(filePath: string, fallback: T): T {
try {
return JSON.parse(fs.readFileSync(filePath, "utf8")) as T;
} catch {
return fallback;
Comment on lines +56 to +58
}
}

function writeJson(filePath: string, data: unknown): void {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf8");
}

function configureVsCode(entry: McpServerEntry): void {
const configPath = getConfigPath("vscode");
const config = readJson<VsCodeMcpConfig>(configPath, { servers: {} });
config.servers = config.servers || {};
config.servers[MCP_SERVER_KEY] = entry;
writeJson(configPath, config);
Util.log(Util.greenCheck() + ` MCP server configured in ${configPath}`);
}

function configureClaude(entry: McpServerEntry): void {
const configPath = getConfigPath("claude");
const config = readJson<ClaudeDesktopConfig>(configPath, { mcpServers: {} });
config.mcpServers = config.mcpServers || {};
config.mcpServers[MCP_SERVER_KEY] = entry;
writeJson(configPath, config);
Util.log(Util.greenCheck() + ` MCP server configured in ${configPath}`);
}

const command: CommandModule = {
command: "mcp",
describe: "Configure the Ignite UI MCP server for an AI client",
builder: (yargs) => {
Comment on lines +93 to +96
return yargs
.option("client", {
alias: "c",
describe: "The AI client to configure (vscode, claude)",
type: "string",
choices: ["vscode", "claude"],
default: "vscode"
})
.usage(""); // do not show any usage instructions before the commands list
},
async handler(argv: ArgumentsCamelCase) {
GoogleAnalytics.post({
t: "screenview",
cd: "MCP"
});

const client = argv.client as Client;
const entry = resolveMcpEntry();

Comment on lines +107 to +115
GoogleAnalytics.post({
t: "event",
ec: "$ig mcp",
ea: `client: ${client}`
});

switch (client) {
case "vscode":
configureVsCode(entry);
break;
case "claude":
configureClaude(entry);
break;
}
}
};

export default command;
4 changes: 3 additions & 1 deletion packages/cli/lib/commands/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const DOC_COMMAND_NAME = "doc";
export const TEST_COMMAND_NAME = "test";
export const LIST_COMMAND_NAME = "list";
export const UPGRADE_COMMAND_NAME = "upgrade-packages";
export const MCP_COMMAND_NAME = "mcp";

export const ALL_COMMANDS = new Set([
ADD_COMMAND_NAME,
Expand All @@ -23,7 +24,8 @@ export const ALL_COMMANDS = new Set([
DOC_COMMAND_NAME,
TEST_COMMAND_NAME,
LIST_COMMAND_NAME,
UPGRADE_COMMAND_NAME
UPGRADE_COMMAND_NAME,
MCP_COMMAND_NAME
]);

export interface PositionalArgs {
Expand Down
Loading