ch02-03-code-review
You've been asked to review a colleague's MCP server code before it goes to production. The server is supposed to process user messages and return responses, but something isn't quite right.
This exercise develops a crucial skill: code review. When working with AI assistants, you'll often need to review generated code for issues. Even when you write code yourself, a critical eye catches bugs before users do.
Your task: Find at least 5 issues in this code, categorize them by severity, and suggest fixes.
🎯 Learning Objectives
💬 Discussion
- What's your usual approach when reviewing code?
- What categories of issues should you look for?
- How do you prioritize fixes?
💡 Hints
Hint 1: Where to look
Focus on these areas:
- How is the mutex being used?
- What happens with all those
.unwrap()calls? - Does the server actually run?
- What gets logged?
Hint 2: Critical issues
The most critical issues:
- The mutex lock usage has a problem with mutable access
- The server is built but never started with a transport
- Multiple
.unwrap()calls can panic
Hint 3: Full list
Issues to find:
- Critical: Mutex borrow issue - needs
mutfor*count += 1 - High:
.lock().unwrap()panics if mutex poisoned - High: Server never starts (no transport)
- High: Multiple
.unwrap()calls can panic - Medium: Global mutable state hurts testing/scaling
- Medium: Raw user input logged (security)
- Low:
.len() > 0should be!.is_empty() - Low: Version "0.1" should be "0.1.0" for semver
- Low: main() should return Result
⚠️ Try the exercise first! Show Solution
#![allow(unused)] fn main() { let count = MESSAGE_COUNT.lock().unwrap(); *count += 1; // Error: count is not mutable! }
Explanation
Fix: let mut count = MESSAGE_COUNT.lock().unwrap();
2. High - Panic on Poisoned Mutex
Fix: Handle PoisonError or use lock().unwrap_or_else(|e| e.into_inner())
3. High - Server Never Starts
Fix: Add server.run_stdio().await?; or HTTP transport
4. High - Unwrap on Serialization
Fix: Use ? operator: Ok(serde_json::to_value(response)?)
5. Medium - Global Mutable State Fix: Use per-request or per-connection state, or Arc<Mutex<>> passed to handlers
6. Medium - Logging User Input Fix: Use structured logging (tracing), sanitize/truncate input
7. Low - Non-idiomatic Empty Check
Fix: if !input.message.is_empty()
8. Low - Semver Version Format
Fix: .version("0.1.0")
9. Low - main() Return Type
Fix: async fn main() -> Result<(), Box<dyn std::error::Error>>
🤔 Reflection
- What's your process for reviewing unfamiliar code?
- How do you prioritize which issues to fix first?
- How would you give feedback to the author without being discouraging?
- What tools could help catch some of these issues automatically?