mcp-sdk-migration.md•6.99 kB
# MCP SDK Migration Plan
**Date**: 2025-10-28
**Status**: Planning
**Priority**: High
## Overview
Migrate from custom MCP protocol implementation to the official MCP Python SDK (`mcp` package). This will improve maintainability, reliability, and future compatibility with MCP specification updates.
## Current State
### What We Have
- Custom JSON-RPC 2.0 parser/generator
- Manual stdio-based communication handling
- Hand-crafted MCP protocol implementation in `server.py`
- Dependencies: `pydantic` only (no `mcp` package)
### Pain Points
- Manual protocol maintenance burden
- Risk of spec drift as MCP evolves
- Boilerplate code for request/response handling
- Potential edge case bugs in custom implementation
## Target State
### What We'll Have
- Official `mcp` SDK for protocol handling
- Modern async/await patterns
- Type-safe server implementation
- Automatic protocol compliance
- Reduced code complexity
### Key Changes
1. **Dependencies**
- Add: `mcp>=1.0.0` (official SDK)
- Keep: `pydantic>=2.0.0` (for domain models)
- Update: `pyproject.toml` and `requirements.txt`
2. **Server Architecture**
```python
# Before: Custom stdio loop + manual JSON-RPC
class MCPServer:
def run(self):
for line in sys.stdin:
request = json.loads(line)
response = self.handle_request(request)
print(json.dumps(response))
# After: SDK-based with decorators
from mcp.server import Server
from mcp.server.stdio import stdio_server
server = Server("python-debug")
@server.list_tools()
async def list_tools():
return [...]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
return [...]
```
3. **Code Organization**
- `server.py`: Replace with SDK-based implementation
- `schemas.py`: Keep domain models, remove MCP protocol structures
- `sessions.py`, `debugger.py`, `runner.py`: Minor async updates
- New: `server_handlers.py` for tool handler logic
## Migration Strategy
### Phase 1: Preparation (Low Risk)
1. Add `mcp` SDK to dependencies
2. Create parallel SDK-based server implementation
3. Keep old server for backward compatibility
4. Run both implementations side-by-side in tests
### Phase 2: Implementation (Medium Risk)
1. Implement SDK-based server with all 5 tools
2. Migrate request/response handling to SDK patterns
3. Update integration tests to use new server
4. Verify feature parity with old implementation
### Phase 3: Cleanup (Low Risk)
1. Remove old custom server code
2. Simplify schemas (remove protocol-specific types)
3. Update documentation and examples
4. Remove backward compatibility shims
## Detailed Changes
### File-by-File Impact
#### High Impact (Major Rewrite)
- `src/mcp_debug_tool/server.py`
- Replace custom JSON-RPC with SDK
- Use `@server.list_tools()` and `@server.call_tool()` decorators
- Convert to async/await pattern
- Remove manual stdio handling
#### Medium Impact (Refactoring)
- `src/mcp_debug_tool/sessions.py`
- Add async support to public API
- Keep synchronous core logic for now
- Use `asyncio.to_thread()` for blocking operations
- `src/mcp_debug_tool/schemas.py`
- Keep domain models (breakpoint, session state, etc.)
- Remove MCP protocol-specific structures
- Simplify response wrapping
#### Low Impact (Minor Updates)
- `pyproject.toml` / `requirements.txt`
- Add `mcp>=1.0.0` dependency
- `tests/integration/*.py`
- Update to use SDK client if needed
- May need async test fixtures
- `tests/unit/*.py`
- Minimal changes (testing core logic, not protocol)
#### No Impact
- `src/mcp_debug_tool/debugger.py` (core debugging logic)
- `src/mcp_debug_tool/runner.py` (subprocess management)
- `src/mcp_debug_tool/utils.py` (helpers)
### API Compatibility
**Good News**: Tool interface remains the same!
```json
// Tool definitions stay identical
{
"name": "sessions_create",
"description": "Create a new debug session...",
"inputSchema": { /* same */ }
}
```
Client-facing behavior is unchanged, only internal implementation differs.
### Risk Assessment
| Risk | Likelihood | Impact | Mitigation |
|------|------------|--------|------------|
| Breaking changes in SDK | Low | High | Pin version, thorough testing |
| Async conversion bugs | Medium | Medium | Gradual migration, comprehensive tests |
| Performance regression | Low | Low | Benchmark before/after |
| Integration test failures | Medium | Medium | Run old & new in parallel initially |
## Success Criteria
- [ ] All 5 tools work identically to current implementation
- [ ] All existing tests pass without modification
- [ ] Code size reduced by >30% (less boilerplate)
- [ ] No performance regression (< 5% slower acceptable)
- [ ] MCP Inspector can connect and list tools
- [ ] Documentation updated with SDK examples
## Testing Strategy
### Unit Tests
- Existing unit tests should pass with minimal changes
- Focus on `sessions.py`, `debugger.py`, `runner.py` (unchanged logic)
### Integration Tests
1. Keep existing integration tests as-is
2. Add new test: SDK compliance check
3. Add new test: Async request handling
4. Verify all 5 tools via SDK client
### Manual Testing
1. Test with MCP Inspector UI
2. Test with VS Code Copilot
3. Verify error handling edge cases
4. Stress test with multiple concurrent sessions
## Timeline Estimate
| Phase | Duration | Tasks |
|-------|----------|-------|
| Preparation | 1-2 hours | Dependency setup, SDK exploration |
| Implementation | 3-4 hours | Server rewrite, async conversion |
| Testing | 2-3 hours | Integration tests, manual verification |
| Cleanup | 1 hour | Remove old code, update docs |
| **Total** | **7-10 hours** | |
## Rollback Plan
If migration fails:
1. Git revert to pre-migration state
2. Keep `mcp` dependency for future retry
3. Document lessons learned
4. Schedule retry with better preparation
## References
- [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)
- [MCP Specification](https://spec.modelcontextprotocol.io/)
- [SDK Examples](https://github.com/modelcontextprotocol/python-sdk/tree/main/examples)
- [Current Implementation](../../src/mcp_debug_tool/server.py)
## Open Questions
1. **Async vs Sync**: Should we keep debugger/sessions sync or convert to async?
- **Recommendation**: Keep core logic sync, wrap in `asyncio.to_thread()`
2. **Backward Compatibility**: Support old custom protocol?
- **Recommendation**: No, clean break acceptable for v0.1.0 → v0.2.0
3. **CLI Impact**: Does Typer CLI need updates?
- **Recommendation**: CLI can stay sync, call async server via `asyncio.run()`
4. **Error Handling**: How to map exceptions to MCP error codes?
- **Recommendation**: Let SDK handle protocol errors, keep domain errors
## Next Steps
1. Review this plan with team ✓
2. Create tasks in `tasks.md` (see below)
3. Set up feature branch: `feature/mcp-sdk-migration`
4. Begin Phase 1 (Preparation)