Official Python SDK for MCPulse - Analytics and observability for MCP servers
Project description
MCPulse Python SDK
Official Python SDK for MCPulse - the analytics and observability platform for MCP servers.
Features
- ✅ gRPC transport - High-performance gRPC communication
- ✅ Query API - Retrieve analytics data, metrics, and insights
- ✅ Decorator-based tracking - Simple
@tracker.track_tool_call()decorator - ✅ Automatic buffering - Metrics are buffered and flushed in background thread
- ✅ Parameter sanitization - Automatically redacts sensitive keys like passwords and tokens
- ✅ Retry logic - Built-in exponential backoff for failed requests
- ✅ Sampling support - Control metric collection with configurable sample rates
- ✅ Session management - Context manager for session tracking
- ✅ Async/sync support - Works with both async and sync code
- ✅ Automatic error capture - Exceptions are automatically recorded
- ✅ Type hints - Full type annotations for better IDE support
Installation
Using uv (Recommended)
uv is a fast Python package installer and resolver.
# Install uv if you haven't already
curl -LsSf https://astral.sh/uv/install.sh | sh
# Install mcpulse
uv pip install mcpulse
Using pip
pip install mcpulse
Development Installation
For local development with uv:
# Clone the repository
git clone https://github.com/sirrobot01/mcpulse-python.git
# Install in development mode with dev dependencies
uv pip install -e ".[dev]"
# Or use the Makefile
make dev
Quick Start
Authentication
If your MCPulse server requires authentication, you need an API key:
- Log in to your MCPulse dashboard
- Navigate to API Keys page
- Click Create API Key and give it a name
- Copy the generated key (shown only once!)
Basic Usage with Decorator
from mcpulse import AnalyticsTracker, Config
# Create configuration
config = Config(
server_id="my-mcp-server",
transport="grpc",
grpc_endpoint="localhost:50051",
api_key="mcpulse_...", # API key from MCPulse UI
)
# Create tracker
tracker = AnalyticsTracker(config)
# Use decorator to track tool calls
@tracker.track_tool_call("calculate")
def calculate(operation: str, a: float, b: float):
if operation == "add":
return a + b
elif operation == "multiply":
return a * b
else:
raise ValueError(f"Unknown operation: {operation}")
# Use the tool - metrics are automatically tracked
result = calculate(operation="add", a=5, b=3)
print(f"Result: {result}")
# Close tracker when done
tracker.close()
Querying Analytics Data
import grpc
from mcpulse_python.query import QueryClient
from mcpulse_python.types import TimeRange
from datetime import datetime, timedelta
# Create gRPC channel
channel = grpc.insecure_channel("localhost:50051")
# Create query client
client = QueryClient(channel=channel, api_key="mcpulse_...")
# List all servers
servers, pagination = client.list_servers(limit=10)
for server in servers:
print(f"Server: {server.name} ({server.id})")
# Get server metrics
time_range = TimeRange(
start=datetime.now() - timedelta(days=1),
end=datetime.now()
)
metrics = client.get_server_metrics(
server_id="my-server",
time_range=time_range,
interval="1h"
)
print(f"Total Calls: {metrics.total_calls}")
print(f"Success Rate: {metrics.success_rate * 100:.1f}%")
print(f"Avg Latency: {metrics.avg_latency_ms}ms")
# Get tool performance
tools, _ = client.get_tools(
server_id="my-server",
time_range=time_range,
limit=10,
sort_by="call_count"
)
for tool in tools:
print(f"{tool.name}: {tool.call_count} calls")
channel.close()
With Session Tracking
# Track a session
with tracker.session() as session_id:
print(f"Session ID: {session_id}")
# All tracked calls within this context are associated with the session
calculate(operation="add", a=5, b=3)
calculate(operation="multiply", a=4, b=7)
Async Support
import asyncio
@tracker.track_tool_call("async_search")
async def search_database(query: str):
await asyncio.sleep(0.1) # Simulate database query
return [{"id": 1, "title": "Result"}]
# Works with async functions
result = await search_database(query="test")
MCP Server Integration
Integrate MCPulse into your MCP server using the official MCP Python SDK:
from mcp.server.fastmcp import FastMCP
from mcp.server.stdio import stdio_server
from mcpulse_python import AnalyticsTracker, Config
# Initialize MCPulse tracker
mcpulse_config = Config(
server_id="my-mcp-server",
grpc_endpoint="localhost:50051",
api_key="mcpulse_...",
)
tracker = AnalyticsTracker(mcpulse_config)
# Create MCP server
mcp = FastMCP("My Server")
@mcp.tool()
@tracker.track_tool_call("calculate")
async def calculate(a: float, b: float) -> float:
"""Add two numbers with analytics tracking."""
return a + b
# Run server
async def main():
async with stdio_server() as (read, write):
await mcp.run(read, write, mcp.create_initialization_options())
tracker.flush()
tracker.close()
See examples/mcp_server_integration.py for a complete working example.
Local Testing
Running Tests
# Using uv (recommended)
make test
# Or directly with uv
uv run pytest
# With coverage report
make test-cov
Running Examples
# Basic usage example
make example-basic
# Query API example
make example-query
# MCP server integration example (requires official mcp package)
uv pip install ".[mcp]"
python examples/mcp_server_integration.py
# Or directly
uv run python examples/basic_usage.py
uv run python examples/query_example.py
Development Workflow
# Install development dependencies
make dev
# Run linters
make lint
# Format code
make format
# Run all checks (lint + test)
make check
# Clean build artifacts
make clean
Configuration
from mcpulse_python import Config
config = Config(
# Server identification
server_id="my-mcp-server",
# Transport (only gRPC supported)
transport="grpc",
grpc_endpoint="localhost:50051",
# Authentication
api_key="mcpulse_...",
# Collection settings
enable_param_collection=True,
async_mode=True,
buffer_size=100,
flush_interval=5.0, # seconds
max_batch_size=1000,
# Privacy
sanitize_params=True,
sensitive_keys=["password", "token", "api_key", "secret"],
# Sampling
sample_rate=1.0, # 1.0 = 100%, 0.1 = 10%
# Retry
max_retries=3,
retry_backoff=1.0, # seconds
# Timeout
timeout=10.0,
# Protocol metadata
protocol_version="2024-11-05",
client_name="mcpulse-python",
client_version="0.1.0",
)
# Validate configuration
config.validate()
API Reference
AnalyticsTracker
High-level tracker with decorators and context managers.
__init__(config)- Create a new trackertrack_tool_call(tool_name, enable_param_collection=None)- Decorator to track tool callssession(session_id=None)- Context manager for session trackingtrack_manual(...)- Manually track a metricflush()- Manually flush buffered metricsclose()- Close and flush remaining metrics
QueryClient
Client for querying analytics data.
list_servers(limit, offset)- List all registered serversget_server(server_id)- Get specific server detailsget_server_metrics(server_id, time_range, interval)- Get aggregated metricsget_tools(server_id, time_range, limit, offset, sort_by)- List tools and their metricsget_tool_timeline(server_id, tool_name, time_range, interval)- Get time-series dataget_errors(server_id, time_range, tool_name, limit, offset)- Get error eventsget_sessions(query)- Get session dataget_anomalies(server_id, time_range, sensitivity)- Get detected anomaliesstream_metrics(server_id, topics)- Stream real-time updates
AnalyticsClient
Low-level client for direct API access.
__init__(transport, grpc_endpoint, timeout, api_key)- Create a new clientingest_metrics(metrics)- Send a batch of metricsingest_metrics_stream(batches)- Stream batchesclose()- Close the client
Collector
Buffered collector with automatic flushing.
__init__(config)- Create a new collectorcollect(metric)- Add a metric to the bufferflush()- Flush all buffered metricsclose()- Close and flush remaining metrics
Environment Variables
Configure the SDK using environment variables:
# Server
export MCP_ANALYTICS_SERVER_ID=my-server
export MCP_ANALYTICS_GRPC_ENDPOINT=localhost:50051
# Authentication
export MCP_ANALYTICS_API_KEY=mcpulse_...
# Behavior
export MCP_ANALYTICS_ASYNC=true
export MCP_ANALYTICS_BUFFER_SIZE=100
export MCP_ANALYTICS_FLUSH_INTERVAL=5
# Privacy
export MCP_ANALYTICS_SANITIZE=true
export MCP_ANALYTICS_SAMPLE_RATE=1.0
Project Structure
mcpulse-python/
├── mcpulse_python/ # Main package
│ ├── __init__.py # Public API exports
│ ├── client.py # Low-level gRPC client
│ ├── collector.py # Buffered metric collector
│ ├── config.py # Configuration
│ ├── query.py # Query API client
│ ├── sanitizer.py # Parameter sanitization
│ ├── tracker.py # High-level tracker
│ ├── types.py # Type definitions
│ ├── _convert.py # Protobuf conversions
│ └── pb/ # Generated protobuf code
├── tests/ # Test suite
│ ├── conftest.py # Pytest fixtures
│ ├── test_tracker.py # Tracker tests
│ ├── test_config.py # Config tests
│ └── test_sanitizer.py # Sanitizer tests
├── examples/ # Usage examples
│ ├── basic_usage.py # Basic tracking example
│ └── query_example.py # Query API example
├── pyproject.toml # Package metadata (uv compatible)
├── Makefile # Development commands
└── README.md # This file
Development Commands
All commands use uv for fast, reliable package management:
make help # Show all available commands
make install # Install package
make dev # Install with dev dependencies
make test # Run tests
make test-cov # Run tests with coverage
make lint # Run linters
make format # Format code
make clean # Clean build artifacts
make build # Build distribution
make check # Run all checks
Testing Locally Without Server
You can test the SDK locally even without a running MCPulse server:
from unittest.mock import Mock, patch
from mcpulse_python import AnalyticsTracker, Config
config = Config(
server_id="test-server",
grpc_endpoint="localhost:50051",
async_mode=False, # Synchronous for easier testing
)
tracker = AnalyticsTracker(config)
# Mock the collector to avoid network calls
with patch.object(tracker.collector, 'collect') as mock_collect:
@tracker.track_tool_call("test_function")
def test_function(x: int) -> int:
return x * 2
result = test_function(5)
assert result == 10
assert mock_collect.called # Verify metric was collected
tracker.close()
Troubleshooting
Import errors
If you see import errors, ensure the package is installed correctly:
uv pip install -e .
gRPC connection errors
Ensure the MCPulse server is running and accessible:
# Test gRPC connectivity
grpcurl -plaintext localhost:50051 list
Type checking errors
Run mypy to check for type issues:
make lint
# or
uv run mypy mcpulse_python
Contributing
See the main MCPulse repository for contribution guidelines.
License
Same as MCPulse project.
Links
- Homepage: https://github.com/sirrobot01/mcpulse
- Documentation: https://docs.mcpulse.io
- Issues: https://github.com/sirrobot01/mcpulse/issues
- PyPI: https://pypi.org/project/mcpulse/ (coming soon)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcpulse-0.1.0.tar.gz.
File metadata
- Download URL: mcpulse-0.1.0.tar.gz
- Upload date:
- Size: 21.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df02b43b2836a67fd63589f5c6e8cc11cba986875aa8d35d199f7d734b1a23a2
|
|
| MD5 |
c0456c12b4114b50dc8f21111e300c0d
|
|
| BLAKE2b-256 |
186c51f1881a38961152fadb9adfc225b338c0c309213422848a041e8d3b6215
|
File details
Details for the file mcpulse-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcpulse-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ec125bdf0ad595563af4b2fdd9cfb744f04bf31609ab32e2e1c4aefa8fe6e00
|
|
| MD5 |
c4bd1d00db6ec6d97c60e97e2d50cf86
|
|
| BLAKE2b-256 |
8fcec5589953cf0ec15e4207640e25de8330b1d126949865e750cc672a3e9e58
|