install
Registers this MCP server into an IDE's configuration files for Claude, Cursor, Codex, Gemini, or Windsurf.
Instructions
Register this kit-mcp server into an IDE's MCP config (Claude/Cursor/Codex/Gemini/Windsurf).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ||
| target | No | IDE id. Use action=targets to list. | |
| scope | No | Default: user | |
| name | No | Server name in the IDE config. Default: kit | |
| via | No | How the IDE will invoke the server. Default: local (this clone) | |
| pkg | No | npm package name (only with via=npx). Default: @luanpdd/kit-mcp | |
| force | No | Overwrite existing entry with same name | |
| projectRoot | No |
Implementation Reference
- src/mcp-server/index.js:108-126 (registration)Tool registration: 'install' tool is defined with name, description, and inputSchema (action, target, scope, name, via, pkg, force, projectRoot).
{ name: 'install', description: 'Register this kit-mcp server into an IDE\'s MCP config (Claude/Cursor/Codex/Gemini/Windsurf).', inputSchema: { type: 'object', properties: { action: { type: 'string', enum: ['targets', 'install', 'dry-run'] }, target: { type: 'string', description: 'IDE id. Use action=targets to list.' }, scope: { type: 'string', enum: ['user', 'project'], description: 'Default: user' }, name: { type: 'string', description: 'Server name in the IDE config. Default: kit' }, via: { type: 'string', enum: ['local', 'npx', 'global'], description: 'How the IDE will invoke the server. Default: local (this clone)' }, pkg: { type: 'string', description: 'npm package name (only with via=npx). Default: @luanpdd/kit-mcp' }, force: { type: 'boolean', description: 'Overwrite existing entry with same name' }, projectRoot: { type: 'string' }, }, required: ['action'], }, }, ]; - src/mcp-server/index.js:237-244 (handler)Handler function 'handleInstall' dispatches by action: 'targets' calls listInstallTargets(), 'install' and 'dry-run' call installMcp() from install.js.
async function handleInstall(args) { switch (args.action) { case 'targets': return listInstallTargets(); case 'install': return installMcp(args.target, { scope: args.scope, name: args.name, via: args.via, pkg: args.pkg, force: args.force, projectRoot: args.projectRoot }); case 'dry-run': return installMcp(args.target, { scope: args.scope, name: args.name, via: args.via, pkg: args.pkg, force: args.force, projectRoot: args.projectRoot, dryRun: true }); default: return { error: `Unknown action: ${args.action}` }; } } - src/mcp-server/install.js:20-44 (handler)Core handler 'installMcp' resolves target config, builds server entry, resolves config path, then delegates to mergeJson() or appendToml() based on the target's strategy.
export async function installMcp(targetId, opts = {}) { const target = getTarget(targetId); if (!target.mcpConfig) { return { ok: false, target: targetId, reason: `${target.label} has no MCP config integration in registry.` }; } const scope = opts.scope ?? 'user'; // 'user' | 'project' const name = opts.name ?? 'kit'; const dryRun = !!opts.dryRun; const force = !!opts.force; const entry = buildServerEntry(opts); const configPath = resolveConfigPath(target.mcpConfig, scope, opts.projectRoot); if (!configPath) { return { ok: false, target: targetId, reason: `Could not resolve config path for scope=${scope}.` }; } if (target.mcpConfig.strategy === 'merge-mcpServers-json') { return await mergeJson(configPath, target.mcpConfig.userKey ?? 'mcpServers', name, entry, { dryRun, force, target: targetId }); } if (target.mcpConfig.strategy === 'append-toml-snippet') { return await appendToml(configPath, name, entry, { dryRun, force, target: targetId }); } return { ok: false, target: targetId, reason: `Unknown strategy: ${target.mcpConfig.strategy}` }; } - src/mcp-server/install.js:52-77 (helper)Helper 'buildServerEntry' constructs the command/args for the MCP server entry based on via mode (local, npx, or global).
function buildServerEntry(opts) { // Three modes: // via=local (default) — point at this clone's bin/mcp.js with the running node // via=npx — `npx -y @luanpdd/kit-mcp` (portable, works on any machine after publish) // via=global — `kit-mcp` (assumes user has `npm install -g @luanpdd/kit-mcp`) // Override anything with explicit --command / --args. const via = opts.via ?? 'local'; let command, args; if (via === 'npx') { command = 'npx'; args = ['-y', opts.pkg ?? '@luanpdd/kit-mcp']; } else if (via === 'global') { command = 'kit-mcp'; args = []; } else { command = process.execPath; args = [path.join(REPO_ROOT, 'bin', 'mcp.js')]; } return { command: opts.command ?? command, args: opts.args ?? args, env: opts.env ?? {}, }; } - src/mcp-server/install.js:92-117 (helper)Helper 'mergeJson' reads/parses a JSON config file, merges the MCP server entry under the specified key, and writes back (or returns a preview in dry-run mode).
async function mergeJson(filePath, key, name, entry, { dryRun, force, target }) { let json = {}; try { const raw = await fs.readFile(filePath, 'utf8'); json = JSON.parse(raw); } catch (e) { if (e.code !== 'ENOENT') { return { ok: false, target, reason: `Failed to parse existing config at ${filePath}: ${e.message}` }; } } json[key] ??= {}; if (json[key][name] && !force) { return { ok: false, target, configPath: filePath, reason: `An MCP server named "${name}" already exists in ${filePath}. Re-run with --force to replace, or pass --name <other>.`, }; } json[key][name] = entry; if (dryRun) { return { ok: true, target, configPath: filePath, dryRun: true, preview: json }; } await fs.mkdir(path.dirname(filePath), { recursive: true }); await fs.writeFile(filePath, JSON.stringify(json, null, 2) + '\n', 'utf8'); return { ok: true, target, configPath: filePath, name, entry }; }