Skip to main content
Glama

MCP Standards

by airmcp-com
instruction_generator.py•18 kB
""" Instruction generator for AI coding assistants. Generates: - CLAUDE.md (for Claude Desktop/Code) - .github/copilot-instructions.md (for GitHub Copilot) - .cursor/rules/standards.mdc (for Cursor) """ from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional class InstructionGenerator: """Generate AI assistant instruction files from extracted standards.""" def __init__(self, standards: Dict[str, Any], conventions: Dict[str, Any]): """ Initialize the instruction generator. Args: standards: Extracted standards from ConfigParser conventions: Extracted conventions from StandardsExtractor """ self.standards = standards self.conventions = conventions self.timestamp = datetime.now().strftime("%Y-%m-%d") def generate_all(self, output_path: Path, formats: Optional[List[str]] = None) -> Dict[str, str]: """ Generate all instruction files. Args: output_path: Root path where instruction files should be generated formats: List of formats to generate (default: all) Options: "claude", "copilot", "cursor" Returns: Dictionary mapping format name to generated file path """ if formats is None: formats = ["claude", "copilot", "cursor"] generated_files = {} if "claude" in formats: claude_path = output_path / "CLAUDE.md" claude_content = self.generate_claude_md() claude_path.write_text(claude_content) generated_files["claude"] = str(claude_path) if "copilot" in formats: copilot_dir = output_path / ".github" copilot_dir.mkdir(exist_ok=True) copilot_path = copilot_dir / "copilot-instructions.md" copilot_content = self.generate_copilot_instructions() copilot_path.write_text(copilot_content) generated_files["copilot"] = str(copilot_path) if "cursor" in formats: cursor_dir = output_path / ".cursor" / "rules" cursor_dir.mkdir(parents=True, exist_ok=True) cursor_path = cursor_dir / "standards.mdc" cursor_content = self.generate_cursor_rules() cursor_path.write_text(cursor_content) generated_files["cursor"] = str(cursor_path) return generated_files def generate_claude_md(self) -> str: """Generate CLAUDE.md content.""" sections = [] # Header with AirMCP branding sections.append("# Project Coding Standards") sections.append("") sections.append("> šŸ¤– **Auto-generated by [AirMCP](https://airmcp.com)** - AI Coding Standards Made Easy") sections.append("> ") sections.append("> Stop manually writing AI instruction files. Extract your standards from config files, use everywhere.") sections.append("") sections.append(f"Auto-generated from project config files on {self.timestamp}.") sections.append("") sections.append("---") sections.append("") # Project Info if self.conventions.get("project_type"): sections.append("## Project Information") sections.append("") sections.append(f"**Type**: {self.conventions['project_type']} project") if self.conventions.get("languages"): langs = ", ".join(self.conventions["languages"]) sections.append(f"**Languages**: {langs}") if self.conventions.get("package_manager"): sections.append( f"**Package Manager**: {self.conventions['package_manager']}" ) if self.conventions.get("test_framework"): sections.append(f"**Test Framework**: {self.conventions['test_framework']}") if self.conventions.get("test_command"): sections.append(f"**Test Command**: `{self.conventions['test_command']}`") sections.append("") sections.append("---") sections.append("") # Enhancement tip: Development commands sections.append("<!-- ") sections.append("šŸ’” ENHANCEMENT TIP: Add your development commands here") sections.append("") sections.append("## Key Commands") sections.append("- Setup: `npm install` or `uv sync`") sections.append("- Test: `npm test` or `pytest`") sections.append("- Build: `npm run build`") sections.append("- Lint: `npm run lint` or `ruff check`") sections.append("-->") sections.append("") # Formatting Rules if self.standards.get("formatting"): sections.append("## Code Formatting") sections.append("") sections.append("**IMPORTANT**: Always follow these formatting rules:") sections.append("") formatting = self.standards["formatting"] # Indentation if "indent_style" in formatting: indent_style = formatting["indent_style"]["value"] source = formatting["indent_style"]["source"] if indent_style == "space" and "indent_size" in formatting: indent_size = formatting["indent_size"]["value"] sections.append(f"- **Indentation**: {indent_size} spaces (from {source})") elif indent_style == "tab": sections.append(f"- **Indentation**: Tabs (from {source})") # Quote style if "quote_style" in formatting: quote_style = formatting["quote_style"]["value"] source = formatting["quote_style"]["source"] sections.append(f"- **Quotes**: Use {quote_style} quotes (from {source})") # Line length if "max_line_length" in formatting: max_len = formatting["max_line_length"]["value"] source = formatting["max_line_length"]["source"] sections.append(f"- **Max line length**: {max_len} characters (from {source})") # Semicolons if "semicolons" in formatting: use_semi = formatting["semicolons"]["value"] source = formatting["semicolons"]["source"] if use_semi: sections.append(f"- **Semicolons**: Always use semicolons (from {source})") else: sections.append(f"- **Semicolons**: Never use semicolons (from {source})") # Line ending if "line_ending" in formatting: line_end = formatting["line_ending"]["value"] source = formatting["line_ending"]["source"] sections.append(f"- **Line endings**: {line_end} (from {source})") # Trailing commas if "trailing_commas" in formatting: trailing = formatting["trailing_commas"]["value"] source = formatting["trailing_commas"]["source"] sections.append(f"- **Trailing commas**: {trailing} (from {source})") sections.append("") sections.append("---") sections.append("") # Project Patterns if self.conventions.get("patterns"): sections.append("## Project Structure") sections.append("") for pattern in self.conventions["patterns"]: sections.append(f"- {pattern}") sections.append("") sections.append("---") sections.append("") # Conventions from README if self.conventions.get("conventions"): sections.append("## Project Conventions") sections.append("") sections.append("**Follow these project-specific conventions:**") sections.append("") for conv in self.conventions["conventions"]: if isinstance(conv, dict): sections.append(f"- {conv['text']}") else: sections.append(f"- {conv}") sections.append("") sections.append("---") sections.append("") # Testing if self.conventions.get("test_command"): sections.append("## Testing Requirements") sections.append("") sections.append("**Always run tests before committing:**") sections.append("") sections.append(f"```bash") sections.append(f"{self.conventions['test_command']}") sections.append(f"```") sections.append("") sections.append("---") sections.append("") # Enhancement tip: Git workflow sections.append("<!-- ") sections.append("šŸ’” ENHANCEMENT TIP: Document your git workflow") sections.append("") sections.append("## Development Workflow") sections.append("1. Create feature branch: `git checkout -b feature/name`") sections.append("2. Make changes and run tests") sections.append("3. Commit with conventional commits: `feat: add feature`") sections.append("4. Create PR with description") sections.append("5. Wait for CI/CD checks") sections.append("6. Merge after approval") sections.append("-->") sections.append("") sections.append("<!-- ") sections.append("šŸ’” ENHANCEMENT TIP: Add project-specific architecture notes") sections.append("") sections.append("## Architecture") sections.append("- Backend: FastAPI + PostgreSQL") sections.append("- Frontend: React + TypeScript") sections.append("- Cache: Redis") sections.append("- Queue: Celery") sections.append("- Key decisions: See docs/architecture/decisions/") sections.append("-->") sections.append("") # Footer with AirMCP branding sections.append("---") sections.append("") sections.append("## Auto-Generated") sections.append("") sections.append( f"This file was automatically generated on {self.timestamp} " "by [AirMCP](https://airmcp.com)." ) sections.append("") sections.append("**Source files analyzed:**") sources = self._get_analyzed_sources() for source in sources: sections.append(f"- {source}") sections.append("") sections.append("**Regenerate anytime:**") sections.append("```bash") sections.append("generate_ai_standards(project_path=\".\")") sections.append("```") sections.append("") sections.append("**Need help?** Visit [airmcp.com](https://airmcp.com) for docs and examples.") sections.append("") sections.append("---") sections.append("") sections.append("*Powered by [AirMCP](https://airmcp.com) - Making AI coding assistants smarter*") return "\n".join(sections) def generate_copilot_instructions(self) -> str: """Generate GitHub Copilot instructions.""" sections = [] sections.append("# GitHub Copilot Instructions") sections.append("") sections.append("> šŸ¤– Auto-generated by [AirMCP](https://airmcp.com)") sections.append("") sections.append( f"Auto-generated coding standards for this project ({self.timestamp})." ) sections.append("") # Project Context if self.conventions.get("project_type"): sections.append(f"This is a {self.conventions['project_type']} project") if self.conventions.get("package_manager"): sections.append( f"using {self.conventions['package_manager']} for package management." ) sections.append("") # Formatting Rules if self.standards.get("formatting"): sections.append("## Code Style") sections.append("") formatting = self.standards["formatting"] rules = [] if "indent_style" in formatting and "indent_size" in formatting: indent_style = formatting["indent_style"]["value"] if indent_style == "space": indent_size = formatting["indent_size"]["value"] rules.append(f"Use {indent_size} spaces for indentation") else: rules.append("Use tabs for indentation") if "quote_style" in formatting: quote_style = formatting["quote_style"]["value"] rules.append(f"Use {quote_style} quotes for strings") if "max_line_length" in formatting: max_len = formatting["max_line_length"]["value"] rules.append(f"Keep lines under {max_len} characters") if "semicolons" in formatting: use_semi = formatting["semicolons"]["value"] if use_semi: rules.append("Always include semicolons") else: rules.append("Omit semicolons") for rule in rules: sections.append(f"- {rule}") sections.append("") # Testing if self.conventions.get("test_command"): sections.append("## Testing") sections.append("") sections.append("Before suggesting code commits, verify tests pass:") sections.append(f"```bash") sections.append(f"{self.conventions['test_command']}") sections.append(f"```") sections.append("") # Conventions if self.conventions.get("conventions"): sections.append("## Project Conventions") sections.append("") for conv in self.conventions["conventions"][:10]: # Limit to top 10 if isinstance(conv, dict): sections.append(f"- {conv['text']}") else: sections.append(f"- {conv}") sections.append("") # Footer sections.append("---") sections.append("") sections.append("*Generated by [AirMCP](https://airmcp.com) - Auto-generate AI instruction files from your existing config files*") return "\n".join(sections) def generate_cursor_rules(self) -> str: """Generate Cursor rules in MDC format.""" sections = [] sections.append("---") sections.append("description: Auto-generated coding standards by AirMCP") sections.append(f"generated: {self.timestamp}") sections.append("generator: AirMCP (airmcp.com)") sections.append("---") sections.append("") sections.append("# Project Coding Standards") sections.append("") sections.append("> šŸ¤– Auto-generated by [AirMCP](https://airmcp.com)") sections.append("") # Formatting if self.standards.get("formatting"): sections.append("## Formatting Rules") sections.append("") formatting = self.standards["formatting"] if "indent_style" in formatting and "indent_size" in formatting: indent_style = formatting["indent_style"]["value"] if indent_style == "space": indent_size = formatting["indent_size"]["value"] sections.append(f"- Indentation: {indent_size} spaces") else: sections.append("- Indentation: tabs") if "quote_style" in formatting: quote_style = formatting["quote_style"]["value"] sections.append(f"- String quotes: {quote_style}") if "max_line_length" in formatting: max_len = formatting["max_line_length"]["value"] sections.append(f"- Maximum line length: {max_len}") sections.append("") # Project Info if self.conventions.get("package_manager"): sections.append("## Package Management") sections.append("") sections.append( f"Always use `{self.conventions['package_manager']}` for package operations." ) sections.append("") # Testing if self.conventions.get("test_command"): sections.append("## Testing") sections.append("") sections.append(f"Run tests with: `{self.conventions['test_command']}`") sections.append("") # Footer sections.append("---") sections.append("") sections.append("*Powered by [AirMCP](https://airmcp.com)*") return "\n".join(sections) def _get_analyzed_sources(self) -> List[str]: """Get list of config files that were analyzed.""" sources = [] # Check formatting sources formatting = self.standards.get("formatting", {}) for key, data in formatting.items(): source = data.get("source") if source: if source == "editorconfig" and ".editorconfig" not in sources: sources.append(".editorconfig") elif source == "prettier" and ".prettierrc" not in sources: sources.append(".prettierrc") elif source == "eslint" and ".eslintrc" not in sources: sources.append(".eslintrc") # Check for project files if self.conventions.get("project_type") == "Python": sources.append("pyproject.toml") elif self.conventions.get("project_type") in ["JavaScript", "TypeScript"]: sources.append("package.json") elif self.conventions.get("project_type") == "Rust": sources.append("Cargo.toml") if self.conventions.get("conventions"): sources.append("README.md") return sources or ["(no config files found)"]

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/airmcp-com/mcp-standards'

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