-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Summary
The current Server class in src/mcp/server/lowlevel/server.py combines two distinct responsibilities:
- Handler registration and management - decorators, capabilities, validation
- Server runtime and message handling - session and task management, request and notification handling
Proposed Design
This proposal suggests splitting Server into a two-class hierarchy - MCPCore (tentative name) and Server. This improves reusability and enables custom MCP server implementations.
- The core handler decorators and functions could be moved into a super class, tentatively named MCPCore.
- The server can inherit from MCPCore and implement the rest.
# src/mcp/server/lowlevel/mcp_core.py
class MCPCore:
def __init__(self, name, version, instructions, website_url, icons): ...
# Capability management
def create_initialization_options(...): ...
def get_capabilities(...): ...
def experimental(...): ...
# Handler registration decorators(...): ...
def list_prompts(...): ...
def get_prompt(...): ...
def list_resources(...): ...
def list_resource_templates(...): ...
def read_resource(...): ...
def set_logging_level(...): ...
def subscribe_resource(...): ...
def unsubscribe_resource(...): ...
def list_tools(...): ...
def call_tool(...): ...
def progress_notification(...): ...
def completion(...): ...
# Tool cache management
async def _get_cached_tool_definition(...): ...
# Module-level helper function
_ping_handler(...): ...
# src/mcp/server/lowlevel/server.py
class Server(MCPCore, Generic[LifespanResultT, RequestT]):
def __init__(name, version, instructions, website_url, icons, lifespan)
# Runtime and message handling
def run(...): ...
def _make_error_result(...): ...
def _handle_message(...): ...
def _handle_request(...): ...
def _handle_notification(...): ...
Benefits of splitting
- Reusability for framework builders - Custom MCP server frameworks can reuse the battle-tested handler registration logic
- Clearer separation of concerns - Single Responsibility Principle: one class for "what handlers exist", another for "how to run them"
- Flexibility for advanced use cases - Custom session and task management strategies, and alternative message handling interface
Motivation
I've built MiniMCP, a stateless, high-level framework for building MCP servers with a different architecture than the current low-level server. It currently has to work around the coupled design. More details regarding the same can be found here #1761. It uses a composition-based approach to reuse the low-level server for handler management and orchestration.
As MCP grows in popularity, more developers will want to build custom server implementations with the battle-tested handler management provided by the low-level server without running the server as it is.
This could enable
- Different execution models (stateless, serverless, event-driven)
- Integration with existing frameworks (FastAPI, Starlette, Django)
- Custom transport layers or message handling
- Specialized deployment scenarios
Backward Compatibility
✅ Fully backward compatible - The split point is very clean.
- Existing code continues to work without changes as the server inherits from MCPCore.
- No breaking changes to public API. Only internal refactoring of responsibilities.
Questions for Maintainers
- Do you see value in this split for the broader ecosystem?
- Naming preference:
MCPCore,HandlerManager,ServerBase, or something else? - File organization: Should we keep both in server.py or split into separate files as in the proposal?
- Any concerns or suggestions about the approach or implementation?
I'm happy to contribute a PR for this if there's interest from the maintainers. Let me know if you'd like any clarification or have suggestions for improving this proposal!