import os import sys import subprocess from mcp.server.fastmcp import FastMCP # 1. Initialize with System Instructions # These instructions tell the LLM *how* to use this server when it connects. mcp = FastMCP( "VibeCodingTutor", instructions=""" This server provides file system access and code execution for a Python Tutor. - Always 'list_directory' first to understand the student's current workspace. - Use 'read_file' to diagnose errors in existing code. - Use 'run_python_script' to verify your examples work before showing them. """ ) # --- 2. New Tool: Context Awareness --- @mcp.tool() def list_directory() -> str: """Lists all files in the current directory to understand the project structure.""" try: files = os.listdir(".") # Filter out hidden files/dirs to keep context clean visible_files = [f for f in files if not f.startswith('.')] if not visible_files: return "The directory is empty." return "Current Project Files:\n- " + "\n- ".join(visible_files) except Exception as e: return f"Error listing directory: {str(e)}" # --- 3. Existing Tools (Enhanced) --- @mcp.tool() def write_file(filename: str, content: str) -> str: """Writes code or text to a file. Overwrites if exists.""" try: with open(filename, "w") as f: f.write(content) return f"✅ Successfully wrote {len(content)} bytes to '{filename}'.\nYou can now run this file." except Exception as e: return f"❌ Error writing file: {str(e)}" @mcp.tool() def read_file(filename: str) -> str: """Reads a file's content. Use this to debug code.""" try: if not os.path.exists(filename): return f"❌ File '{filename}' not found. Did you forget to write it first?" with open(filename, "r") as f: return f.read() except Exception as e: return f"Error reading file: {str(e)}" @mcp.tool() def run_python_script(filename: str) -> str: """Runs a Python script and captures output/errors.""" try: # Check if file exists first to avoid confusing subprocess errors if not os.path.exists(filename): return f"❌ Cannot run '{filename}' because it does not exist. Write it first." # Run with timeout to prevent infinite loops (common with students) result = subprocess.run( [sys.executable, filename], capture_output=True, text=True, timeout=10 ) output = "" if result.stdout: output += f"[STDOUT]\n{result.stdout}\n" if result.stderr: output += f"[STDERR]\n{result.stderr}\n" if not output: return "[Process finished with no output]" return output except subprocess.TimeoutExpired: return "❌ Error: Script execution timed out (limit: 10s). Check for infinite loops." except Exception as e: return f"Execution failed: {str(e)}" # --- 4. New Resource: Static Knowledge --- # The agent can "read" this resource URL to get its core curriculum @mcp.resource("tutor://curriculum") def get_curriculum() -> str: """Returns the standard teaching curriculum for this session.""" return """ # Python Vibe Coding Curriculum 1. Basics: Variables, Loops, functions. 2. Data: Lists, Dictionaries, Sets. 3. Advanced: Decorators, Generators, Context Managers. 4. Data Science: Pandas, Matplotlib. TEACHING STYLE: - Don't just explain. CODING IS DOING. - Always create a file, run it, and show the output. - If the user is wrong, be encouraging but precise. """ if __name__ == "__main__": mcp.run()