Skip to main content

A lightweight, flexible implementation of the Model Context Protocol (MCP) for Python applications, specializing in robust HTTP/SSE transport.

Project description

pymcp-sse: Python MCP over SSE Library

A lightweight, flexible implementation of the Model Context Protocol (MCP) for Python applications, specializing in robust HTTP/SSE transport.

Features

  • Modular Framework: Clean implementation of BaseMCPServer, BaseMCPClient, and MultiMCPClient.
  • HTTP/SSE Transport: Robust HTTP/SSE implementation with automatic session management, configurable timeouts, and reconnection handling.
  • Server Lifecycle: Support for standard FastAPI lifespan context managers (BaseMCPServer(lifespan=...)) for managing resources when using server.run().
  • Concurrent Task Execution: BaseMCPServer.run_with_tasks() method for easily running servers with persistent background asynchronous tasks, using shutdown_callbacks for cleanup.
  • Tool Registration & Discovery: Simple decorator-based tool registration (@server.register_tool()) and a standard describe_tools endpoint for clients to dynamically query detailed tool capabilities (parameters, descriptions).
  • Server Push: Built-in support for server-initiated push notifications to clients and periodic keep-alive pings. Includes NotificationScheduler helper class.
  • LLM Integration: Includes BaseLLMClient abstraction for easy integration with various LLM providers (an Anthropic Claude example is provided).
  • Flexible Logging: Configurable logging via pymcp_sse.utils.

Installation

To install the library locally for development:

# Navigate to the directory containing pyproject.toml
cd /path/to/your/pymcp-sse

# Install in editable mode
pip install -e .

(Once published, installation via pip install pymcp-sse will be available.)

Basic Usage

Creating an MCP Server (Simple)

from pymcp_sse.server import BaseMCPServer
from pymcp_sse.utils import configure_logging

configure_logging() # Configure logging (optional)

# Create a server instance
server = BaseMCPServer("My Simple Server")

# Register tools using the decorator
# Type hints are used by describe_tools
@server.register_tool("echo")
async def echo_tool(text: str) -> dict:
    '''Echoes the provided text back.'''
    return {"response": f"Echo: {text}"}

# Run the server using the standard method
if __name__ == "__main__":
    # Additional kwargs are passed to uvicorn.run (e.g., timeout_keep_alive=65)
    server.run(host="0.0.0.0", port=8000)

Creating an MCP Server (with Background Tasks)

import asyncio
from pymcp_sse.server import BaseMCPServer
from pymcp_sse.utils import configure_logging

configure_logging() # Configure logging (optional)

# Create a server instance
server = BaseMCPServer("My Background Task Server")

# Define your background task
async def my_periodic_task():
    while True:
        print("Task running...")
        await asyncio.sleep(5)

# Define a shutdown callback
async def cleanup():
    print("Cleaning up...")

# Run the server using run_with_tasks
async def main():
    await server.run_with_tasks(
        host="0.0.0.0", 
        port=8001,
        concurrent_tasks=[my_periodic_task],
        shutdown_callbacks=[cleanup]
    )

if __name__ == "__main__":
    asyncio.run(main())

Creating a Single Client

import asyncio
from pymcp_sse.client import BaseMCPClient
from pymcp_sse.utils import configure_logging

configure_logging() # Configure logging (optional)

async def main():
    # Configure timeouts for stability (read timeout > server ping interval)
    client = BaseMCPClient(
        "http://localhost:8000", # Point to your server
        http_read_timeout=65, 
        http_connect_timeout=10
    )
    
    try:
        # Connect and initialize
        if await client.connect() and await client.initialize():
            print(f"Connected. Available tools: {client.available_tools}")
            # Call a tool
            result = await client.call_tool("echo", text="Hello, world!")
            print(f"Tool Result: {result}")
            # Assign a notification handler if needed
            # client.notification_handler = your_async_handler
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        await client.close()

if __name__ == "__main__":
    asyncio.run(main())

Creating a Multi-Server Client

import asyncio
from pymcp_sse.client import MultiMCPClient
from pymcp_sse.utils import configure_logging

configure_logging() # Configure logging (optional)

async def main():
    # Use servers from the examples section
    servers = {
        "server_basic": "http://localhost:8101",
        "server_tasks": "http://localhost:8102"
    }
    # Configure timeouts for stability (read timeout > server ping interval)
    client = MultiMCPClient(
        servers,
        http_read_timeout=65,
        http_connect_timeout=10
    )
    
    try:
        # Connect to all servers (automatically fetches tool details if describe_tools exists)
        connection_results = await client.connect_all()
        print(f"Connection Results: {connection_results}")
        
        # Get info about connected servers (including tool details)
        server_info = client.get_server_info()
        print("\nServer Info:")
        for name, info in server_info.items():
             print(f"- {name}: Status={info['status']}, Tools={len(info.get('available_tools', []))}, Details Fetched={bool(info.get('tool_details'))}")

        # Call a tool on a specific server
        if server_info.get("server_basic", {}).get("status") == "connected":
            result = await client.call_tool("server_basic", "echo", text="Hello from MultiClient!")
            print(f"\nServer Basic Echo Result: {result}")
    except Exception as e:
        print(f"An error occurred: {e}")    
    finally:
        await client.close()

if __name__ == "__main__":
    asyncio.run(main())

Documentation

For more detailed usage instructions, notes on the HTTP/SSE implementation, guides on LLM integration, and the protocol specification, please refer to the documentation in the docs/ directory.

Examples

See the examples/ directory for complete working examples, including:

  • server_basic: Demonstrates a simple server using server.run().
  • server_tasks: Demonstrates a server with background tasks (notification scheduler) using server.run_with_tasks().
  • client: A multi-server client using MultiMCPClient and an LLMAgent to interact with both servers via natural language. Requires an API key (set ANTHROPIC_API_KEY in a .env file in the project root).
  • run_all.py: A launcher script to easily start server_basic, server_tasks, and the client simultaneously.
  • notification_listener.py: A simple standalone client for receiving push notifications from any compatible server.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pymcp_sse-0.4.0.tar.gz (28.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pymcp_sse-0.4.0-py3-none-any.whl (30.1 kB view details)

Uploaded Python 3

File details

Details for the file pymcp_sse-0.4.0.tar.gz.

File metadata

  • Download URL: pymcp_sse-0.4.0.tar.gz
  • Upload date:
  • Size: 28.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.11

File hashes

Hashes for pymcp_sse-0.4.0.tar.gz
Algorithm Hash digest
SHA256 15ff42a96e2b4380b077de26c8588fda27ca5b98eab72af58c4062bb672dd2de
MD5 6e0e5353e00c66a974327bcf8c4435f7
BLAKE2b-256 231cf3f1161ddf0d7b9b635533365357b034537229ff02229d122645314a6b7c

See more details on using hashes here.

File details

Details for the file pymcp_sse-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: pymcp_sse-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 30.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.11.11

File hashes

Hashes for pymcp_sse-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 83f43448c73b3e70f64b68a022174ae8ef3d499b66cab82267aa540c5d798507
MD5 4cd64fa82380e278efa01ff48666d674
BLAKE2b-256 8bc4908238e22fca2d417e9436175fa41eb26a66a65b168935f354acb8bbafc9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page