Skip to main content
Glama
wminson

GitHub Copilot CLI MCP Server

by wminson
server.py9.72 kB
""" GitHub Copilot CLI MCP Server - STDIO Transport Wraps the GitHub Copilot CLI (gh copilot) as an MCP server. """ from mcp.server.fastmcp import FastMCP import subprocess import re import shutil mcp = FastMCP("GitHub Copilot CLI") def strip_ansi(text: str) -> str: """Remove ANSI escape sequences from string.""" ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|[\[0-?]*[ -/]*[@-~])') return ansi_escape.sub('', text) def filter_stderr(stderr: str) -> str: """ Filter out Copilot CLI noise from stderr, keeping only real errors. Filters out: - Progress indicators - Status messages - Informational output """ if not stderr: return "" # Patterns to filter out (noise, not real errors) noise_patterns = [ r'^\[.*\].*$', # Progress/status messages in brackets r'^Loading.*$', # Loading messages r'^Initializing.*$', # Initialization messages r'^Connected.*$', # Connection status r'^\s*$', # Empty lines ] # Compile patterns compiled_patterns = [re.compile(p, re.MULTILINE) for p in noise_patterns] # Filter lines lines = stderr.strip().split('\n') filtered_lines = [] for line in lines: line = line.strip() if not line: continue is_noise = False for pattern in compiled_patterns: if pattern.match(line): is_noise = True break if not is_noise: filtered_lines.append(line) return '\n'.join(filtered_lines) def process_copilot_output(result: subprocess.CompletedProcess) -> str: """ Process Copilot CLI output, handling stdout and stderr appropriately. Args: result: The subprocess result to process. Returns clean output with only relevant errors included. """ # Get stdout output = strip_ansi(result.stdout).strip() if result.stdout else "" # Filter and process stderr filtered_stderr = filter_stderr(strip_ansi(result.stderr)) if result.stderr else "" # Only append stderr if there are real errors if filtered_stderr: if output: output += f"\n\n[ERRORS]\n{filtered_stderr}" else: output = f"[ERRORS]\n{filtered_stderr}" # Check return code for unexpected failures if result.returncode != 0 and not output: return f"Error: Copilot CLI exited with code {result.returncode}" return output if output else "No output returned" def get_gh_path() -> str: """Get the path to the gh executable.""" gh_path = shutil.which("gh") if not gh_path: raise FileNotFoundError("'gh' executable not found") return gh_path @mcp.tool() def copilot_suggest( prompt: str, target: str = "shell" ) -> str: """ Get a command suggestion from GitHub Copilot based on natural language. Args: prompt: Natural language description of what you want to do. target: Target type for suggestion - 'shell' (default), 'gh', or 'git'. Examples: - "Install git" with target="shell" - "Create pull request" with target="gh" - "Undo the most recent local commits" with target="git" """ try: gh_path = get_gh_path() except FileNotFoundError: return "Error: 'gh' executable not found. Please install GitHub CLI (https://cli.github.com/)." if target not in ["shell", "gh", "git"]: return f"Error: Invalid target '{target}'. Must be 'shell', 'gh', or 'git'." cmd = [gh_path, "copilot", "suggest", "-t", target, prompt] try: # Run with input to handle any interactive prompts result = subprocess.run( cmd, capture_output=True, text=True, check=False, encoding='utf-8', input="\n" # Auto-accept first suggestion ) return process_copilot_output(result) except Exception as e: return f"Error executing Copilot suggest: {str(e)}" @mcp.tool() def copilot_explain(command: str) -> str: """ Get an explanation of a command from GitHub Copilot. Args: command: The command to explain (e.g., "git log --oneline --graph"). Examples: - "du -sh | sort -h" - Explain disk usage command - "git log --oneline --graph --decorate --all" - Explain git history command """ try: gh_path = get_gh_path() except FileNotFoundError: return "Error: 'gh' executable not found. Please install GitHub CLI (https://cli.github.com/)." cmd = [gh_path, "copilot", "explain", command] try: result = subprocess.run( cmd, capture_output=True, text=True, check=False, encoding='utf-8' ) return process_copilot_output(result) except Exception as e: return f"Error executing Copilot explain: {str(e)}" @mcp.tool() def copilot_version() -> str: """ Get the GitHub Copilot CLI version information. """ try: gh_path = get_gh_path() except FileNotFoundError: return "Error: 'gh' executable not found. Please install GitHub CLI (https://cli.github.com/)." cmd = [gh_path, "copilot", "--version"] try: result = subprocess.run( cmd, capture_output=True, text=True, check=False, encoding='utf-8' ) return process_copilot_output(result) except Exception as e: return f"Error getting version: {str(e)}" @mcp.tool() def copilot_help(command: str = "") -> str: """ Get GitHub Copilot CLI help information. Args: command: Optional command to get help for ('suggest', 'explain', 'config', 'alias'). """ try: gh_path = get_gh_path() except FileNotFoundError: return "Error: 'gh' executable not found. Please install GitHub CLI (https://cli.github.com/)." if command: cmd = [gh_path, "copilot", command, "--help"] else: cmd = [gh_path, "copilot", "--help"] try: result = subprocess.run( cmd, capture_output=True, text=True, check=False, encoding='utf-8' ) return process_copilot_output(result) except Exception as e: return f"Error getting help: {str(e)}" @mcp.tool() def copilot_config_get(key: str = "") -> str: """ Get GitHub Copilot CLI configuration. Args: key: Optional specific config key to get. If empty, shows all config. """ try: gh_path = get_gh_path() except FileNotFoundError: return "Error: 'gh' executable not found. Please install GitHub CLI (https://cli.github.com/)." if key: cmd = [gh_path, "copilot", "config", "get", key] else: cmd = [gh_path, "copilot", "config", "list"] try: result = subprocess.run( cmd, capture_output=True, text=True, check=False, encoding='utf-8' ) return process_copilot_output(result) except Exception as e: return f"Error getting config: {str(e)}" @mcp.tool() def copilot_alias(shell: str = "bash") -> str: """ Generate shell aliases for GitHub Copilot CLI convenience commands. Args: shell: Shell type - 'bash', 'zsh', 'fish', or 'powershell'. """ try: gh_path = get_gh_path() except FileNotFoundError: return "Error: 'gh' executable not found. Please install GitHub CLI (https://cli.github.com/)." if shell not in ["bash", "zsh", "fish", "powershell"]: return f"Error: Invalid shell '{shell}'. Must be 'bash', 'zsh', 'fish', or 'powershell'." cmd = [gh_path, "copilot", "alias", shell] try: result = subprocess.run( cmd, capture_output=True, text=True, check=False, encoding='utf-8' ) return process_copilot_output(result) except Exception as e: return f"Error generating aliases: {str(e)}" @mcp.tool() def copilot_suggest_git(prompt: str) -> str: """ Get a git command suggestion from GitHub Copilot. Convenience wrapper for copilot_suggest with target='git'. Args: prompt: Natural language description of the git operation. Examples: - "Undo the most recent local commits" - "Clean up local branches" - "Setup LFS for images" """ return copilot_suggest(prompt, target="git") @mcp.tool() def copilot_suggest_gh(prompt: str) -> str: """ Get a GitHub CLI (gh) command suggestion from GitHub Copilot. Convenience wrapper for copilot_suggest with target='gh'. Args: prompt: Natural language description of the GitHub operation. Examples: - "Create pull request" - "List pull requests waiting for my review" - "Summarize work I have done in issues and pull requests" """ return copilot_suggest(prompt, target="gh") @mcp.tool() def copilot_suggest_shell(prompt: str) -> str: """ Get a shell command suggestion from GitHub Copilot. Convenience wrapper for copilot_suggest with target='shell'. Args: prompt: Natural language description of the shell operation. Examples: - "Kill processes holding onto deleted files" - "Test whether there are SSL/TLS issues with github.com" - "Convert SVG to PNG and resize" """ return copilot_suggest(prompt, target="shell") if __name__ == "__main__": mcp.run()

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/wminson/copilot-mcp-server'

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