Skip to content

Add the todos-server reference example - #3048

Open
maxisbey wants to merge 3 commits into
mainfrom
todos-server-example
Open

Add the todos-server reference example#3048
maxisbey wants to merge 3 commits into
mainfrom
todos-server-example

Polish the todos-server example after rebasing onto latest main

a05dd3d
Select commit
Loading
Failed to load commit list.
Claude / Claude Code Review completed Jul 16, 2026 in 13m 6s

Code review found 3 potential issues

Found 5 candidates, confirmed 3. See review comments for details.

Details

Severity Count
🔴 Important 0
🟡 Nit 3
🟣 Pre-existing 0
Severity File:Line Issue
🟡 Nit examples/servers/todos-server/mcp_todos_server/todos.py:590-599 Sync resolvers iterate tasks_by_id from a worker thread — races with event-loop mutations
🟡 Nit examples/servers/todos-server/mcp_todos_server/todos.py:200-204 catch_warnings held across await in log_info — global warning-filter race

Annotations

Check warning on line 599 in examples/servers/todos-server/mcp_todos_server/todos.py

See this annotation in the file changed.

@claude claude / Claude Code Review

Sync resolvers iterate tasks_by_id from a worker thread — races with event-loop mutations

The sync resolvers (`confirm_clear`, `rank_open_tasks`, and the brainstorm chain) run on a worker thread via `anyio.to_thread.run_sync`, where they iterate the module-global `tasks_by_id` while the event-loop thread stays free to mutate it (`add_task_record` inserts, `clear_done` pops) — a mutation landing mid-iteration raises `RuntimeError("dictionary changed size during iteration")` and fails the whole `tools/call`. Snapshot with `list(tasks_by_id.values())` before iterating, or declare the re

Check warning on line 204 in examples/servers/todos-server/mcp_todos_server/todos.py

See this annotation in the file changed.

@claude claude / Claude Code Review

catch_warnings held across await in log_info — global warning-filter race

log_info holds warnings.catch_warnings() across the awaited ctx.log(...) call; catch_warnings() saves/restores the process-global warnings.filters and is not task-safe, so two overlapping tool calls (easy over streamable HTTP, where every mutating tool logs) can interleave enter/exit non-LIFO and permanently leak the ignore filter into the global filter list. Since this is a reference example that teaches patterns, install the filter once at module import — warnings.filterwarnings("ignore", cate