# Directory Structure ``` ├── .gitignore ├── coding_todo.py ├── minimal_server.py ├── README.md └── requirements.txt ``` # Files -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- ``` # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so *.dylib # Distribution / packaging .Python env/ venv/ .venv build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written into a _MEIPASS folder, but if PyInstaller # creates a self-extracting executable, it will use a temp folder instead. _MEIPASS/ _MEI*/ # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mypy .mypy_cache/ .dmypy.json dmypy.sock # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # General ignores tmp/ temp/ *.tmp *.log *.DS_Store # MCP directory mcp/ ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- ```markdown # Coding Todo Server This MCP server provides tools and resources for managing a coding project's todo list. ## Overview This server allows you to: - View the current todo list - View details of specific todo items - Add new todo items - Update the status of todo items - Delete todo items - Update todo item details ## Resources - `todo://list`: Provides a list of all todo items with their status, title, priority and tags. - `todo://item/{todo_id}`: Provides detailed information about a specific todo item, including status, priority, creation date, project, tags, and description. ## Tools - `add_todo`: Adds a new todo item to the list. - Arguments: - `title`: Title of the todo item (required) - `description`: Detailed description of the todo item (required) - `project`: Project name (optional) - `priority`: Priority from 1 (lowest) to 5 (highest) (optional, default: 1) - `tags`: List of tags related to the todo (optional) - `update_todo_status`: Updates the status of an existing todo item. - Arguments: - `id`: The ID of the todo item to update (required) - `status`: New status (pending/in_progress/completed) (required) - `delete_todo`: Deletes a todo item from the list. - Arguments: - `id`: The ID of the todo item to delete (required) - `update_todo`: Updates the details of an existing todo item. - Arguments: - `id`: The ID of the todo item to update (required) - `title`: New title (optional) - `description`: New description (optional) - `project`: New project name (optional) - `priority`: New priority from 1 (lowest) to 5 (highest) (optional) - `tags`: New list of tags (optional) ## Installation Before running the server, you need to install the required Python packages. You can do this using pip: ```bash pip install -r requirements.txt ``` ## Usage To run the server, execute the `coding_todo.py` script. ```bash python coding_todo.py ``` This will start the MCP server, making its tools and resources available to MCP clients. ``` -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- ``` mcp-sdk pydantic ``` -------------------------------------------------------------------------------- /minimal_server.py: -------------------------------------------------------------------------------- ```python #!/usr/bin/env python import asyncio from mcp.server.fastmcp import FastMCP mcp = FastMCP("minimal-server") @mcp.tool() def hello_world() -> str: """A simple hello world tool""" return "Hello, world from minimal MCP server!" if __name__ == "__main__": print("Starting MCP server...") mcp.run() ``` -------------------------------------------------------------------------------- /coding_todo.py: -------------------------------------------------------------------------------- ```python import asyncio from datetime import datetime from enum import Enum from typing import Dict, List, Optional from mcp.server.fastmcp import FastMCP, Context from pydantic import BaseModel # Todo status enum class TodoStatus(str, Enum): PENDING = "pending" IN_PROGRESS = "in_progress" COMPLETED = "completed" # Todo model with coding project specific fields class Todo(BaseModel): id: str title: str description: str status: TodoStatus = TodoStatus.PENDING created_at: datetime = datetime.now() updated_at: Optional[datetime] = None project: Optional[str] = None priority: int = 1 # 1 (lowest) to 5 (highest) tags: List[str] = [] # Store todos in memory todos: Dict[str, Todo] = {} # Create an MCP server using FastMCP mcp = FastMCP("coding-todo-server") # Resource to list all todos @mcp.resource("todo://list") def get_todo_list() -> str: """List of all coding project todos""" if not todos: return "No todos found." result = "# Coding Project Todos\n\n" for todo_id, todo in todos.items(): status_marker = "[ ]" if todo.status != TodoStatus.COMPLETED else "[x]" result += f"{status_marker} **{todo.title}** (ID: {todo_id}, Priority: {todo.priority})\n" if todo.tags: result += f" Tags: {', '.join(todo.tags)}\n" return result # Resource to view a specific todo @mcp.resource("todo://item/{todo_id}") def get_todo_item(todo_id: str) -> str: """Get details of a specific todo item""" if todo_id not in todos: raise ValueError(f"Todo not found: {todo_id}") todo = todos[todo_id] result = f"# Todo: {todo.title}\n\n" result += f"**Status:** {todo.status.value}\n" result += f"**Priority:** {todo.priority}/5\n" result += f"**Created:** {todo.created_at.strftime('%Y-%m-%d %H:%M')}\n" if todo.updated_at: result += f"**Updated:** {todo.updated_at.strftime('%Y-%m-%d %H:%M')}\n" if todo.project: result += f"**Project:** {todo.project}\n" if todo.tags: result += f"**Tags:** {', '.join(todo.tags)}\n" result += f"\n**Description:**\n{todo.description}\n" return result # Prompt to summarize todos @mcp.prompt() def summarize_todos(status: str = "pending", project: str = None) -> str: """Creates a summary of todos with optional filtering Args: status: Filter by status (pending/in_progress/completed/all) project: Filter by project name """ filtered_todos = list(todos.values()) if status != "all": filtered_todos = [t for t in filtered_todos if t.status.value == status] if project: filtered_todos = [t for t in filtered_todos if t.project == project] status_text = f"{status} " if status != "all" else "" project_text = f"for project {project} " if project else "" return f"""Here are the current {status_text}todos {project_text}to summarize: {chr(10).join(f"- {t.title} (Priority: {t.priority}): {t.description}" for t in filtered_todos)} Please provide a concise summary of these todos and suggest an approach to tackle them efficiently.""" # Prompt to suggest which todo to tackle next @mcp.prompt() def suggest_next_todo() -> str: """Suggests which todo to tackle next based on priority and status""" pending_todos = [t for t in todos.values() if t.status != TodoStatus.COMPLETED] if not pending_todos: return "There are no pending todos. Would you like suggestions for new coding tasks to add?" # Sort by priority (highest first) sorted_todos = sorted(pending_todos, key=lambda t: (-t.priority, t.created_at)) return f"""Here are the current pending todos in order of priority: {chr(10).join(f"- {t.title} (Priority: {t.priority}, Status: {t.status.value}): {t.description}" for t in sorted_todos)} Based on these todos, which one should I tackle next and why? Please provide a brief recommendation.""" # Tool to add a new todo @mcp.tool() def add_todo(title: str, description: str, project: str = None, priority: int = 1, tags: List[str] = None) -> str: """Add a new todo item Args: title: Title of the todo item description: Detailed description of the todo item project: Project name (optional) priority: Priority from 1 (lowest) to 5 (highest) tags: List of tags related to the todo """ # Generate a new todo ID todo_id = f"todo{len(todos) + 1}" new_todo = Todo( id=todo_id, title=title, description=description, project=project, priority=priority, tags=tags or [], ) todos[todo_id] = new_todo return f"Added todo '{title}' with ID: {todo_id}" # Tool to update the status of a todo @mcp.tool() def update_todo_status(id: str, status: str) -> str: """Update the status of a todo item Args: id: The ID of the todo item status: New status (pending/in_progress/completed) """ if id not in todos: raise ValueError(f"Todo not found: {id}") try: todos[id].status = TodoStatus(status) todos[id].updated_at = datetime.now() except ValueError: raise ValueError(f"Invalid status: {status}. Must be one of: pending, in_progress, completed") return f"Updated todo '{todos[id].title}' status to {status}" # Tool to delete a todo @mcp.tool() def delete_todo(id: str) -> str: """Delete a todo item Args: id: The ID of the todo item to delete """ if id not in todos: raise ValueError(f"Todo not found: {id}") title = todos[id].title del todos[id] return f"Deleted todo '{title}' (ID: {id})" # Tool to update a todo's details @mcp.tool() def update_todo(id: str, title: str = None, description: str = None, project: str = None, priority: int = None, tags: List[str] = None) -> str: """Update a todo item's details Args: id: The ID of the todo item title: New title (optional) description: New description (optional) project: New project name (optional) priority: New priority from 1 (lowest) to 5 (highest) (optional) tags: New list of tags (optional) """ if id not in todos: raise ValueError(f"Todo not found: {id}") todo = todos[id] if title is not None: todo.title = title if description is not None: todo.description = description if project is not None: todo.project = project if priority is not None: if not 1 <= priority <= 5: raise ValueError("Priority must be between 1 and 5") todo.priority = priority if tags is not None: todo.tags = tags # Update the timestamp todo.updated_at = datetime.now() return f"Updated todo '{todo.title}' (ID: {id})" # Initialize with example todos def initialize_example_todos(): example_todos = [ Todo( id="todo1", title="Implement user authentication", description="Add JWT-based authentication to the API endpoints", priority=4, project="Backend API", tags=["backend", "security"], ), Todo( id="todo2", title="Fix CSS responsiveness", description="The dashboard layout breaks on mobile devices", priority=3, project="Frontend UI", tags=["frontend", "css", "bugfix"], ), Todo( id="todo3", title="Write unit tests", description="Create tests for the new data processing module", priority=2, project="Backend API", tags=["testing", "quality"], ), ] for todo in example_todos: todos[todo.id] = todo # Initialize and run server if __name__ == "__main__": initialize_example_todos() mcp.run() ```