Skip to content

Proposal: Split Server class into MCPCore (handler management) (tentative name) and Server (runtime) #1779

@sreenaths

Description

@sreenaths

Summary

The current Server class in src/mcp/server/lowlevel/server.py combines two distinct responsibilities:

  1. Handler registration and management - decorators, capabilities, validation
  2. 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

  1. Do you see value in this split for the broader ecosystem?
  2. Naming preference: MCPCore, HandlerManager, ServerBase, or something else?
  3. File organization: Should we keep both in server.py or split into separate files as in the proposal?
  4. 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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions