Skip to main content
Glama

rules

Manage rule profiles in projects by adding or removing specific configurations like Cursor, Claude, or VSCode. Ensure precise control over project settings through defined actions and profiles.

Instructions

Add or remove rule profiles from the project.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesWhether to add or remove rule profiles.
forceNoDANGEROUS: Force removal even if it would leave no rule profiles. Only use if you are absolutely certain.
profilesYesList of rule profiles to add or remove (e.g., ["cursor", "roo"]). Available options: amp, claude, cline, codex, cursor, gemini, kiro, opencode, roo, trae, vscode, windsurf, zed
projectRootYesThe root directory of the project. Must be an absolute path.

Implementation Reference

  • Registers the MCP 'rules' tool with server.addTool, defining name, description, parameters schema, and execute handler that delegates to rulesDirect.
    export function registerRulesTool(server) {
    	server.addTool({
    		name: 'rules',
    		description: 'Add or remove rule profiles from the project.',
    		parameters: z.object({
    			action: z
    				.enum(['add', 'remove'])
    				.describe('Whether to add or remove rule profiles.'),
    			profiles: z
    				.array(z.enum(RULE_PROFILES))
    				.min(1)
    				.describe(
    					`List of rule profiles to add or remove (e.g., [\"cursor\", \"roo\"]). Available options: ${RULE_PROFILES.join(', ')}`
    				),
    			projectRoot: z
    				.string()
    				.describe(
    					'The root directory of the project. Must be an absolute path.'
    				),
    			force: z
    				.boolean()
    				.optional()
    				.default(false)
    				.describe(
    					'DANGEROUS: Force removal even if it would leave no rule profiles. Only use if you are absolutely certain.'
    				)
    		}),
    		execute: withNormalizedProjectRoot(async (args, { log, session }) => {
    			try {
    				log.info(
    					`[rules tool] Executing action: ${args.action} for profiles: ${args.profiles.join(', ')} in ${args.projectRoot}`
    				);
    				const result = await rulesDirect(args, log, { session });
    				return handleApiResult({
    					result,
    					log,
    					projectRoot: args.projectRoot
    				});
    			} catch (error) {
    				log.error(`[rules tool] Error: ${error.message}`);
    				return createErrorResponse(error.message, { details: error.stack });
    			}
    		})
    	});
    }
  • Core handler implementation for the rules tool. Handles 'add' and 'remove' actions on rule profiles, performs safety checks, file conversions/removals, and returns structured results.
    export async function rulesDirect(args, log, context = {}) {
    	enableSilentMode();
    	try {
    		const { action, profiles, projectRoot, yes, force } = args;
    		if (
    			!action ||
    			!Array.isArray(profiles) ||
    			profiles.length === 0 ||
    			!projectRoot
    		) {
    			return {
    				success: false,
    				error: {
    					code: 'MISSING_ARGUMENT',
    					message: 'action, profiles, and projectRoot are required.'
    				}
    			};
    		}
    
    		const removalResults = [];
    		const addResults = [];
    
    		if (action === RULES_ACTIONS.REMOVE) {
    			// Safety check: Ensure this won't remove all rule profiles (unless forced)
    			if (!force && wouldRemovalLeaveNoProfiles(projectRoot, profiles)) {
    				const installedProfiles = getInstalledProfiles(projectRoot);
    				const remainingProfiles = installedProfiles.filter(
    					(profile) => !profiles.includes(profile)
    				);
    				return {
    					success: false,
    					error: {
    						code: 'CRITICAL_REMOVAL_BLOCKED',
    						message: `CRITICAL: This operation would remove ALL remaining rule profiles (${profiles.join(', ')}), leaving your project with no rules configurations. This could significantly impact functionality. Currently installed profiles: ${installedProfiles.join(', ')}. If you're certain you want to proceed, set force: true or use the CLI with --force flag.`
    					}
    				};
    			}
    
    			for (const profile of profiles) {
    				if (!isValidProfile(profile)) {
    					removalResults.push({
    						profileName: profile,
    						success: false,
    						error: `The requested rule profile for '${profile}' is unavailable. Supported profiles are: ${RULE_PROFILES.join(', ')}.`
    					});
    					continue;
    				}
    				const profileConfig = getRulesProfile(profile);
    				const result = removeProfileRules(projectRoot, profileConfig);
    				removalResults.push(result);
    			}
    			const successes = removalResults
    				.filter((r) => r.success)
    				.map((r) => r.profileName);
    			const skipped = removalResults
    				.filter((r) => r.skipped)
    				.map((r) => r.profileName);
    			const errors = removalResults.filter(
    				(r) => r.error && !r.success && !r.skipped
    			);
    			const withNotices = removalResults.filter((r) => r.notice);
    
    			let summary = '';
    			if (successes.length > 0) {
    				summary += `Successfully removed Task Master rules: ${successes.join(', ')}.`;
    			}
    			if (skipped.length > 0) {
    				summary += `Skipped (default or protected): ${skipped.join(', ')}.`;
    			}
    			if (errors.length > 0) {
    				summary += errors
    					.map((r) => `Error removing ${r.profileName}: ${r.error}`)
    					.join(' ');
    			}
    			if (withNotices.length > 0) {
    				summary += ` Notices: ${withNotices.map((r) => `${r.profileName} - ${r.notice}`).join('; ')}.`;
    			}
    			disableSilentMode();
    			return {
    				success: errors.length === 0,
    				data: { summary, results: removalResults }
    			};
    		} else if (action === RULES_ACTIONS.ADD) {
    			for (const profile of profiles) {
    				if (!isValidProfile(profile)) {
    					addResults.push({
    						profileName: profile,
    						success: false,
    						error: `Profile not found: static import missing for '${profile}'. Valid profiles: ${RULE_PROFILES.join(', ')}`
    					});
    					continue;
    				}
    				const profileConfig = getRulesProfile(profile);
    				const { success, failed } = convertAllRulesToProfileRules(
    					projectRoot,
    					profileConfig
    				);
    
    				// Determine paths
    				const rulesDir = profileConfig.rulesDir;
    				const profileRulesDir = path.join(projectRoot, rulesDir);
    				const profileDir = profileConfig.profileDir;
    				const mcpConfig = profileConfig.mcpConfig !== false;
    				const mcpPath =
    					mcpConfig && profileConfig.mcpConfigPath
    						? path.join(projectRoot, profileConfig.mcpConfigPath)
    						: null;
    
    				// Check what was created
    				const mcpConfigCreated =
    					mcpConfig && mcpPath ? fs.existsSync(mcpPath) : undefined;
    				const rulesDirCreated = fs.existsSync(profileRulesDir);
    				const profileFolderCreated = fs.existsSync(
    					path.join(projectRoot, profileDir)
    				);
    
    				const error =
    					failed > 0 ? `${failed} rule files failed to convert.` : null;
    				const resultObj = {
    					profileName: profile,
    					mcpConfigCreated,
    					rulesDirCreated,
    					profileFolderCreated,
    					skipped: false,
    					error,
    					success:
    						(mcpConfig ? mcpConfigCreated : true) &&
    						rulesDirCreated &&
    						success > 0 &&
    						!error
    				};
    				addResults.push(resultObj);
    			}
    
    			const successes = addResults
    				.filter((r) => r.success)
    				.map((r) => r.profileName);
    			const errors = addResults.filter((r) => r.error && !r.success);
    
    			let summary = '';
    			if (successes.length > 0) {
    				summary += `Successfully added rules: ${successes.join(', ')}.`;
    			}
    			if (errors.length > 0) {
    				summary += errors
    					.map((r) => ` Error adding ${r.profileName}: ${r.error}`)
    					.join(' ');
    			}
    			disableSilentMode();
    			return {
    				success: errors.length === 0,
    				data: { summary, results: addResults }
    			};
    		} else {
    			disableSilentMode();
    			return {
    				success: false,
    				error: {
    					code: 'INVALID_ACTION',
    					message: `Unknown action. Use "${RULES_ACTIONS.ADD}" or "${RULES_ACTIONS.REMOVE}".`
    				}
    			};
    		}
    	} catch (error) {
    		disableSilentMode();
    		log.error(`[rulesDirect] Error: ${error.message}`);
    		return {
    			success: false,
    			error: {
    				code: error.code || 'RULES_ERROR',
    				message: error.message
    			}
    		};
    	}
    }
  • toolRegistry entry that maps 'rules' tool name to its registration function registerRulesTool, used for dynamic tool registration.
    rules: registerRulesTool,
  • Zod input schema for the rules tool parameters.
    parameters: z.object({
    	action: z
    		.enum(['add', 'remove'])
    		.describe('Whether to add or remove rule profiles.'),
    	profiles: z
    		.array(z.enum(RULE_PROFILES))
    		.min(1)
    		.describe(
    			`List of rule profiles to add or remove (e.g., [\"cursor\", \"roo\"]). Available options: ${RULE_PROFILES.join(', ')}`
    		),
    	projectRoot: z
    		.string()
    		.describe(
    			'The root directory of the project. Must be an absolute path.'
    		),
    	force: z
    		.boolean()
    		.optional()
    		.default(false)
    		.describe(
    			'DANGEROUS: Force removal even if it would leave no rule profiles. Only use if you are absolutely certain.'
    		)
    }),
  • Constants for rules actions used in the handler logic.
    export const RULES_ACTIONS = {
    	ADD: 'add',
    	REMOVE: 'remove'
    };
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description carries the full burden of behavioral disclosure. It mentions the core action (add/remove rule profiles) but doesn't explain what rule profiles are, what effects the changes have, or what permissions might be required. The dangerous nature of the 'force' parameter is documented in the schema, not the description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that gets straight to the point. It's appropriately sized for a tool with good schema documentation and wastes no words on repetition or unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and no output schema, the description is minimal but functional. It states what the tool does, but doesn't provide context about what rule profiles are, what happens after modification, or error conditions. Given the complexity of modifying project configuration, more context would be helpful.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema already documents all 4 parameters thoroughly. The description doesn't add any meaningful parameter semantics beyond what's in the schema - it doesn't explain what rule profiles are, why you'd add/remove them, or how they affect the project.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('add or remove') and resource ('rule profiles from the project'), making the purpose immediately understandable. However, it doesn't distinguish this tool from its many siblings, particularly those like 'add_dependency' or 'add_tag' that also perform addition operations on different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. With 35 sibling tools including various 'add_' and 'remove_' operations, there's no indication of what makes 'rule profiles' different from other project elements or when this specific tool is appropriate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/eyaltoledano/claude-task-master'

If you have feedback or need assistance with the MCP directory API, please join our Discord server