Skip to main content

Lightweight MCP (Model Context Protocol) client with async/sync support, SSE and Streamable HTTP transports

Project description

quartermaster-mcp-client

Lightweight async/sync Python client for the Model Context Protocol (MCP), implementing JSON-RPC 2.0 over SSE or Streamable HTTP transports.

PyPI version Python 3.11+ License: Apache 2.0

Features

  • Dual API: Full async (async with) and synchronous (with) interfaces
  • Two Transports: Server-Sent Events (SSE) and Streamable HTTP
  • Auto-Retry: Exponential backoff with jitter on transient failures
  • Type-Safe: Dataclass responses with complete type hints
  • Zero Framework Dependencies: Only requires httpx
  • Auth Support: Bearer token and custom header authentication
  • Rich Error Hierarchy: Typed exceptions for connection, protocol, timeout, and auth errors

Installation

pip install quartermaster-mcp-client

Quick Start

Async Usage

import asyncio
from quartermaster_mcp_client import McpClient

async def main():
    async with McpClient("http://localhost:8000/mcp") as client:
        # Get server info
        info = await client.server_info()
        print(f"Server: {info.name} v{info.version}")

        # Discover available tools
        tools = await client.list_tools()
        for tool in tools:
            print(f"  {tool.name}: {tool.description}")

        # Call a tool
        result = await client.call_tool("weather", {"location": "San Francisco"})
        print(f"Result: {result}")

asyncio.run(main())

Sync Usage

Sync methods use the _sync suffix and work with a standard with block:

from quartermaster_mcp_client import McpClient

with McpClient("http://localhost:8000/mcp") as client:
    tools = client.list_tools_sync()
    print(f"Available tools: {[t.name for t in tools]}")

    result = client.call_tool_sync("weather", {"location": "London"})
    print(f"Result: {result}")

Error Handling

import asyncio
from quartermaster_mcp_client import McpClient
from quartermaster_mcp_client.errors import (
    McpConnectionError,
    McpTimeoutError,
    McpToolNotFoundError,
    McpAuthenticationError,
    McpServerError,
)

async def main():
    try:
        async with McpClient("http://localhost:8000/mcp", timeout=10.0) as client:
            result = await client.call_tool("unknown_tool", {})
    except McpToolNotFoundError as e:
        print(f"Tool not found: {e}")
    except McpTimeoutError as e:
        print(f"Request timed out: {e}")
    except McpConnectionError as e:
        print(f"Connection failed: {e}")
    except McpAuthenticationError as e:
        print(f"Auth failed: {e}")
    except McpServerError as e:
        print(f"Server error (code {e.code}): {e}")

asyncio.run(main())

Integration with quartermaster-tools

MCP tools discovered via the client can be registered in a ToolRegistry for use alongside local tools:

import asyncio
from quartermaster_mcp_client import McpClient
from quartermaster_tools import ToolRegistry, tool

registry = ToolRegistry()

# Register a local tool
@registry.tool()
def local_calculator(expression: str) -> dict:
    """Evaluate a math expression.

    Args:
        expression: The expression to evaluate.
    """
    return {"result": eval(expression)}

# Discover and use MCP remote tools
async def main():
    async with McpClient("http://localhost:8000/mcp") as client:
        tools = await client.list_tools()
        for t in tools:
            print(f"Remote tool: {t.name} -- {t.description}")

        result = await client.call_tool("weather", {"location": "Berlin"})
        print(result)

asyncio.run(main())

API Reference

McpClient

The main client class. Supports both async and sync context managers.

client = McpClient(
    url="http://localhost:8000/mcp",  # MCP server URL (http/https required)
    transport="sse",       # "sse" (default) or "streamable"
    timeout=30.0,          # Request timeout in seconds
    max_retries=3,         # Retries on transient failures
    auth_token="sk-...",   # Optional Bearer token
    headers={"X-Custom": "value"},  # Additional HTTP headers
)

Async Methods

Method Returns Description
await client.server_info() McpServerInfo Server name, version, protocol version, capabilities
await client.list_tools() list[McpTool] All tools with parameter metadata
await client.call_tool(name, arguments) Any Invoke a tool and return its result
await client.list_resources() list[dict] List available resources
await client.read_resource(uri) str Read resource content by URI

Sync Methods

Every async method has a sync counterpart with _sync suffix:

Method Returns
client.server_info_sync() McpServerInfo
client.list_tools_sync() list[McpTool]
client.call_tool_sync(name, arguments) Any
client.list_resources_sync() list[dict]
client.read_resource_sync(uri) str

Properties

Property Type Description
client.is_connected bool Whether the client has an active transport

Data Types

McpTool -- a tool exposed by the server:

@dataclass
class McpTool:
    name: str                        # Tool identifier
    description: str                 # Human-readable description
    parameters: list[ToolParameter]  # Parameter metadata
    input_schema: dict[str, Any]     # Full JSON Schema

McpServerInfo -- server metadata returned by server_info():

@dataclass
class McpServerInfo:
    name: str                     # Server name
    version: str                  # Server version
    protocol_version: str         # MCP protocol version
    capabilities: dict[str, Any]  # Supported capabilities

ToolParameter -- metadata about a single tool parameter:

@dataclass
class ToolParameter:
    name: str
    type: str             # JSON Schema type (string, number, integer, boolean, etc.)
    description: str
    required: bool = False
    default: Any = None
    enum: list[str] | None = None
    options: list[ToolParameterOption] = []
    min_value: float | None = None
    max_value: float | None = None
    min_length: int | None = None
    max_length: int | None = None
    pattern: str | None = None

Transports

SSE (Server-Sent Events) -- the default and recommended transport. Sends JSON-RPC as HTTP POST and reads the response as an SSE stream.

Streamable HTTP -- standard HTTP POST with JSON responses. Use when SSE is unavailable.

# SSE transport (default)
client = McpClient("http://localhost:8000/mcp", transport="sse")

# Streamable HTTP transport
client = McpClient("http://localhost:8000/mcp", transport="streamable")

Errors

All exceptions inherit from McpError:

Exception When
McpConnectionError Connection to server fails
McpTimeoutError Request exceeds timeout
McpProtocolError Malformed JSON-RPC or SSE response
McpServerError Server returns a JSON-RPC error (has .code attribute)
McpToolNotFoundError Requested tool does not exist
McpAuthenticationError Authentication fails

Errors can be imported from quartermaster_mcp_client.errors or directly from quartermaster_mcp_client.

Configuration

Authentication

# Bearer token
client = McpClient(
    "https://mcp.example.com/api",
    auth_token="your-api-key",
)

# Custom headers
client = McpClient(
    "https://mcp.example.com/api",
    headers={"X-API-Key": "your-key", "X-Org-Id": "org-123"},
)

Retry and Timeout

The client retries on McpConnectionError and McpTimeoutError with exponential backoff. Non-retriable errors (McpProtocolError, McpServerError, McpAuthenticationError) are raised immediately.

client = McpClient(
    "http://localhost:8000/mcp",
    timeout=60.0,      # 60-second timeout per request
    max_retries=5,     # Up to 5 attempts on transient failures
)

Contributing

Contributions welcome. See CONTRIBUTING.md for guidelines.

License

Apache License 2.0. See LICENSE for details.

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

quartermaster_mcp_client-0.4.7.tar.gz (45.2 kB view details)

Uploaded Source

Built Distribution

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

quartermaster_mcp_client-0.4.7-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

Details for the file quartermaster_mcp_client-0.4.7.tar.gz.

File metadata

  • Download URL: quartermaster_mcp_client-0.4.7.tar.gz
  • Upload date:
  • Size: 45.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for quartermaster_mcp_client-0.4.7.tar.gz
Algorithm Hash digest
SHA256 d315d23b7ed1c1cbd461c1e91490e50664159642558ab16001b37ba09f5bec6b
MD5 4dad67aeea9365f4c633d88c619bd9bc
BLAKE2b-256 c0057811b0fd9cd4711e39b8dc9fcec07870853c6fed2fde97056aa5da708148

See more details on using hashes here.

File details

Details for the file quartermaster_mcp_client-0.4.7-py3-none-any.whl.

File metadata

File hashes

Hashes for quartermaster_mcp_client-0.4.7-py3-none-any.whl
Algorithm Hash digest
SHA256 1a364bca9ec5130fe263cd8defcc277c6b78977b8996b33ea2964231df5bf2f1
MD5 1c412f91569bd72db714f63474270702
BLAKE2b-256 66f189ed6962bd2506765af032b7124b94397706ed754058b926bc7226815f13

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