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.3.1.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.3.1-py3-none-any.whl (18.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: quartermaster_mcp_client-0.3.1.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.3.1.tar.gz
Algorithm Hash digest
SHA256 ea21be5088063aafbee6c09fae78d19fa329a77e953d36eb24b0ec87672d1d14
MD5 722b53afdd529f0c04184886a559d8df
BLAKE2b-256 f94a7cd8944c674d38c5daad5b2e1e5e83dbe61cc2f0e456beb4acf79c9f2405

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for quartermaster_mcp_client-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8646b5cb605d6d36802ec14634458568d65ba741f6deff56d16384e786bc3dfe
MD5 ed857b46af6dd4965f5c46185bfb0ae8
BLAKE2b-256 85f94b6f7898c1ee91b3ec4866a0de1844d9ad991ef6f2fb9ae08b0a6d806e0c

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