#
tokens: 3973/50000 5/5 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── coding_todo.py
├── minimal_server.py
├── README.md
└── requirements.txt
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Byte-compiled / optimized / DLL files
 2 | __pycache__/
 3 | *.py[cod]
 4 | *$py.class
 5 | 
 6 | # C extensions
 7 | *.so
 8 | *.dylib
 9 | 
10 | # Distribution / packaging
11 | .Python
12 | env/
13 | venv/
14 | .venv
15 | build/
16 | develop-eggs/
17 | dist/
18 | downloads/
19 | eggs/
20 | .eggs/
21 | lib/
22 | lib64/
23 | parts/
24 | sdist/
25 | var/
26 | wheels/
27 | pip-wheel-metadata/
28 | share/python-wheels/
29 | *.egg-info/
30 | .installed.cfg
31 | *.egg
32 | MANIFEST
33 | 
34 | # PyInstaller
35 | #  Usually these files are written into a _MEIPASS folder, but if PyInstaller
36 | #  creates a self-extracting executable, it will use a temp folder instead.
37 | _MEIPASS/
38 | _MEI*/
39 | 
40 | # Environments
41 | .env
42 | .venv
43 | env/
44 | venv/
45 | ENV/
46 | env.bak/
47 | venv.bak/
48 | 
49 | # Spyder project settings
50 | .spyderproject
51 | .spyproject
52 | 
53 | # Rope project settings
54 | .ropeproject
55 | 
56 | # mypy
57 | .mypy_cache/
58 | .dmypy.json
59 | dmypy.sock
60 | 
61 | # Environments
62 | .env
63 | .venv
64 | env/
65 | venv/
66 | ENV/
67 | env.bak/
68 | venv.bak/
69 | 
70 | # General ignores
71 | tmp/
72 | temp/
73 | *.tmp
74 | *.log
75 | *.DS_Store
76 | 
77 | # MCP directory
78 | mcp/
79 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Coding Todo Server
 2 | 
 3 | This MCP server provides tools and resources for managing a coding project's todo list.
 4 | 
 5 | ## Overview
 6 | 
 7 | This server allows you to:
 8 | 
 9 | - View the current todo list
10 | - View details of specific todo items
11 | - Add new todo items
12 | - Update the status of todo items
13 | - Delete todo items
14 | - Update todo item details
15 | 
16 | ## Resources
17 | 
18 | - `todo://list`:  Provides a list of all todo items with their status, title, priority and tags.
19 | - `todo://item/{todo_id}`: Provides detailed information about a specific todo item, including status, priority, creation date, project, tags, and description.
20 | 
21 | ## Tools
22 | 
23 | - `add_todo`: Adds a new todo item to the list.
24 |     - Arguments:
25 |         - `title`: Title of the todo item (required)
26 |         - `description`: Detailed description of the todo item (required)
27 |         - `project`: Project name (optional)
28 |         - `priority`: Priority from 1 (lowest) to 5 (highest) (optional, default: 1)
29 |         - `tags`: List of tags related to the todo (optional)
30 | 
31 | - `update_todo_status`: Updates the status of an existing todo item.
32 |     - Arguments:
33 |         - `id`: The ID of the todo item to update (required)
34 |         - `status`: New status (pending/in_progress/completed) (required)
35 | 
36 | - `delete_todo`: Deletes a todo item from the list.
37 |     - Arguments:
38 |         - `id`: The ID of the todo item to delete (required)
39 | 
40 | - `update_todo`: Updates the details of an existing todo item.
41 |     - Arguments:
42 |         - `id`: The ID of the todo item to update (required)
43 |         - `title`: New title (optional)
44 |         - `description`: New description (optional)
45 |         - `project`: New project name (optional)
46 |         - `priority`: New priority from 1 (lowest) to 5 (highest) (optional)
47 |         - `tags`: New list of tags (optional)
48 | 
49 | ## Installation
50 | 
51 | Before running the server, you need to install the required Python packages. You can do this using pip:
52 | 
53 | ```bash
54 | pip install -r requirements.txt
55 | ```
56 | 
57 | ## Usage
58 | 
59 | To run the server, execute the `coding_todo.py` script.
60 | 
61 | ```bash
62 | python coding_todo.py
63 | ```
64 | 
65 | This will start the MCP server, making its tools and resources available to MCP clients.
66 | 
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
1 | mcp-sdk
2 | pydantic
3 | 
```

--------------------------------------------------------------------------------
/minimal_server.py:
--------------------------------------------------------------------------------

```python
 1 | #!/usr/bin/env python
 2 | import asyncio
 3 | from mcp.server.fastmcp import FastMCP
 4 | 
 5 | mcp = FastMCP("minimal-server")
 6 | 
 7 | @mcp.tool()
 8 | def hello_world() -> str:
 9 |     """A simple hello world tool"""
10 |     return "Hello, world from minimal MCP server!"
11 | 
12 | if __name__ == "__main__":
13 |     print("Starting MCP server...")
14 |     mcp.run()
15 | 
```

--------------------------------------------------------------------------------
/coding_todo.py:
--------------------------------------------------------------------------------

```python
  1 | import asyncio
  2 | from datetime import datetime
  3 | from enum import Enum
  4 | from typing import Dict, List, Optional
  5 | 
  6 | from mcp.server.fastmcp import FastMCP, Context
  7 | from pydantic import BaseModel
  8 | 
  9 | # Todo status enum
 10 | class TodoStatus(str, Enum):
 11 |     PENDING = "pending"
 12 |     IN_PROGRESS = "in_progress"
 13 |     COMPLETED = "completed"
 14 | 
 15 | # Todo model with coding project specific fields
 16 | class Todo(BaseModel):
 17 |     id: str
 18 |     title: str
 19 |     description: str
 20 |     status: TodoStatus = TodoStatus.PENDING
 21 |     created_at: datetime = datetime.now()
 22 |     updated_at: Optional[datetime] = None
 23 |     project: Optional[str] = None
 24 |     priority: int = 1  # 1 (lowest) to 5 (highest)
 25 |     tags: List[str] = []
 26 | 
 27 | # Store todos in memory
 28 | todos: Dict[str, Todo] = {}
 29 | 
 30 | # Create an MCP server using FastMCP
 31 | mcp = FastMCP("coding-todo-server")
 32 | 
 33 | # Resource to list all todos
 34 | @mcp.resource("todo://list")
 35 | def get_todo_list() -> str:
 36 |     """List of all coding project todos"""
 37 |     if not todos:
 38 |         return "No todos found."
 39 |     
 40 |     result = "# Coding Project Todos\n\n"
 41 |     for todo_id, todo in todos.items():
 42 |         status_marker = "[ ]" if todo.status != TodoStatus.COMPLETED else "[x]"
 43 |         result += f"{status_marker} **{todo.title}** (ID: {todo_id}, Priority: {todo.priority})\n"
 44 |         if todo.tags:
 45 |             result += f"   Tags: {', '.join(todo.tags)}\n"
 46 |     return result
 47 | 
 48 | # Resource to view a specific todo
 49 | @mcp.resource("todo://item/{todo_id}")
 50 | def get_todo_item(todo_id: str) -> str:
 51 |     """Get details of a specific todo item"""
 52 |     if todo_id not in todos:
 53 |         raise ValueError(f"Todo not found: {todo_id}")
 54 |     
 55 |     todo = todos[todo_id]
 56 |     result = f"# Todo: {todo.title}\n\n"
 57 |     result += f"**Status:** {todo.status.value}\n"
 58 |     result += f"**Priority:** {todo.priority}/5\n"
 59 |     result += f"**Created:** {todo.created_at.strftime('%Y-%m-%d %H:%M')}\n"
 60 |     if todo.updated_at:
 61 |         result += f"**Updated:** {todo.updated_at.strftime('%Y-%m-%d %H:%M')}\n"
 62 |     if todo.project:
 63 |         result += f"**Project:** {todo.project}\n"
 64 |     if todo.tags:
 65 |         result += f"**Tags:** {', '.join(todo.tags)}\n"
 66 |     result += f"\n**Description:**\n{todo.description}\n"
 67 |     return result
 68 | 
 69 | # Prompt to summarize todos
 70 | @mcp.prompt()
 71 | def summarize_todos(status: str = "pending", project: str = None) -> str:
 72 |     """Creates a summary of todos with optional filtering
 73 |     
 74 |     Args:
 75 |         status: Filter by status (pending/in_progress/completed/all)
 76 |         project: Filter by project name
 77 |     """
 78 |     filtered_todos = list(todos.values())
 79 |     if status != "all":
 80 |         filtered_todos = [t for t in filtered_todos if t.status.value == status]
 81 |     if project:
 82 |         filtered_todos = [t for t in filtered_todos if t.project == project]
 83 |     
 84 |     status_text = f"{status} " if status != "all" else ""
 85 |     project_text = f"for project {project} " if project else ""
 86 |     
 87 |     return f"""Here are the current {status_text}todos {project_text}to summarize:
 88 | 
 89 | {chr(10).join(f"- {t.title} (Priority: {t.priority}): {t.description}" for t in filtered_todos)}
 90 | 
 91 | Please provide a concise summary of these todos and suggest an approach to tackle them efficiently."""
 92 | 
 93 | # Prompt to suggest which todo to tackle next
 94 | @mcp.prompt()
 95 | def suggest_next_todo() -> str:
 96 |     """Suggests which todo to tackle next based on priority and status"""
 97 |     pending_todos = [t for t in todos.values() if t.status != TodoStatus.COMPLETED]
 98 |     
 99 |     if not pending_todos:
100 |         return "There are no pending todos. Would you like suggestions for new coding tasks to add?"
101 |     
102 |     # Sort by priority (highest first)
103 |     sorted_todos = sorted(pending_todos, key=lambda t: (-t.priority, t.created_at))
104 |     
105 |     return f"""Here are the current pending todos in order of priority:
106 | 
107 | {chr(10).join(f"- {t.title} (Priority: {t.priority}, Status: {t.status.value}): {t.description}" for t in sorted_todos)}
108 | 
109 | Based on these todos, which one should I tackle next and why? Please provide a brief recommendation."""
110 | 
111 | # Tool to add a new todo
112 | @mcp.tool()
113 | def add_todo(title: str, description: str, project: str = None, priority: int = 1, tags: List[str] = None) -> str:
114 |     """Add a new todo item
115 |     
116 |     Args:
117 |         title: Title of the todo item
118 |         description: Detailed description of the todo item
119 |         project: Project name (optional)
120 |         priority: Priority from 1 (lowest) to 5 (highest)
121 |         tags: List of tags related to the todo
122 |     """
123 |     # Generate a new todo ID
124 |     todo_id = f"todo{len(todos) + 1}"
125 |     
126 |     new_todo = Todo(
127 |         id=todo_id,
128 |         title=title,
129 |         description=description,
130 |         project=project,
131 |         priority=priority,
132 |         tags=tags or [],
133 |     )
134 |     
135 |     todos[todo_id] = new_todo
136 |     
137 |     return f"Added todo '{title}' with ID: {todo_id}"
138 | 
139 | # Tool to update the status of a todo
140 | @mcp.tool()
141 | def update_todo_status(id: str, status: str) -> str:
142 |     """Update the status of a todo item
143 |     
144 |     Args:
145 |         id: The ID of the todo item
146 |         status: New status (pending/in_progress/completed)
147 |     """
148 |     if id not in todos:
149 |         raise ValueError(f"Todo not found: {id}")
150 |     
151 |     try:
152 |         todos[id].status = TodoStatus(status)
153 |         todos[id].updated_at = datetime.now()
154 |     except ValueError:
155 |         raise ValueError(f"Invalid status: {status}. Must be one of: pending, in_progress, completed")
156 |     
157 |     return f"Updated todo '{todos[id].title}' status to {status}"
158 | 
159 | # Tool to delete a todo
160 | @mcp.tool()
161 | def delete_todo(id: str) -> str:
162 |     """Delete a todo item
163 |     
164 |     Args:
165 |         id: The ID of the todo item to delete
166 |     """
167 |     if id not in todos:
168 |         raise ValueError(f"Todo not found: {id}")
169 |     
170 |     title = todos[id].title
171 |     del todos[id]
172 |     
173 |     return f"Deleted todo '{title}' (ID: {id})"
174 | 
175 | # Tool to update a todo's details
176 | @mcp.tool()
177 | def update_todo(id: str, title: str = None, description: str = None, project: str = None, 
178 |                priority: int = None, tags: List[str] = None) -> str:
179 |     """Update a todo item's details
180 |     
181 |     Args:
182 |         id: The ID of the todo item
183 |         title: New title (optional)
184 |         description: New description (optional)
185 |         project: New project name (optional)
186 |         priority: New priority from 1 (lowest) to 5 (highest) (optional)
187 |         tags: New list of tags (optional)
188 |     """
189 |     if id not in todos:
190 |         raise ValueError(f"Todo not found: {id}")
191 |     
192 |     todo = todos[id]
193 |     
194 |     if title is not None:
195 |         todo.title = title
196 |     
197 |     if description is not None:
198 |         todo.description = description
199 |     
200 |     if project is not None:
201 |         todo.project = project
202 |     
203 |     if priority is not None:
204 |         if not 1 <= priority <= 5:
205 |             raise ValueError("Priority must be between 1 and 5")
206 |         todo.priority = priority
207 |     
208 |     if tags is not None:
209 |         todo.tags = tags
210 |     
211 |     # Update the timestamp
212 |     todo.updated_at = datetime.now()
213 |     
214 |     return f"Updated todo '{todo.title}' (ID: {id})"
215 | 
216 | # Initialize with example todos
217 | def initialize_example_todos():
218 |     example_todos = [
219 |         Todo(
220 |             id="todo1",
221 |             title="Implement user authentication",
222 |             description="Add JWT-based authentication to the API endpoints",
223 |             priority=4,
224 |             project="Backend API",
225 |             tags=["backend", "security"],
226 |         ),
227 |         Todo(
228 |             id="todo2",
229 |             title="Fix CSS responsiveness",
230 |             description="The dashboard layout breaks on mobile devices",
231 |             priority=3,
232 |             project="Frontend UI",
233 |             tags=["frontend", "css", "bugfix"],
234 |         ),
235 |         Todo(
236 |             id="todo3",
237 |             title="Write unit tests",
238 |             description="Create tests for the new data processing module",
239 |             priority=2,
240 |             project="Backend API",
241 |             tags=["testing", "quality"],
242 |         ),
243 |     ]
244 |     
245 |     for todo in example_todos:
246 |         todos[todo.id] = todo
247 | 
248 | # Initialize and run server
249 | if __name__ == "__main__":
250 |     initialize_example_todos()
251 |     mcp.run()
```