Observatory SDK for MCP server analytics and monitoring - Add comprehensive observability to your MCP servers with just 2 lines of code
Project description
Observatory MCP Python SDK
Add comprehensive analytics and monitoring to your MCP servers with just 2-3 lines of code.
Observatory SDK provides lightweight, zero-configuration observability for Model Context Protocol (MCP) servers. Track performance metrics, protocol messages, errors, and user behavior without modifying your existing MCP server implementation.
✨ Features
- 🚀 2-Line Integration: Add observability with minimal code changes
- 📊 Complete Analytics: Protocol messages, performance metrics, error tracking
- 🔒 Privacy-First: Built-in PII detection and data masking
- ⚡ Lightweight: <1ms overhead per message, async processing
- 🎯 Smart Sampling: Adaptive sampling with error prioritization
- 🔌 Zero Server Modification: Works via protocol message interception
- 📈 Real-Time Monitoring: Live dashboards and alerting
- 🐍 Type-Safe: Full type hints for IDE autocomplete
📦 Installation
pip install observatory-mcp
For MCP server integration:
pip install observatory-mcp[mcp]
For development:
pip install observatory-mcp[dev]
🚀 Quick Start
Basic Integration (2 lines!)
from mcp.server import Server
from observatory_mcp import ObservatorySDK
# Create your MCP server as usual
app = Server("my-awesome-mcp-server")
# Add Observatory with 2 lines!
observatory = ObservatorySDK(
api_key="obs_live_xyz123",
server_name="my-awesome-mcp-server",
server_version="1.0.0"
)
app = observatory.wrap_server(app)
# Your handlers work exactly the same - Observatory tracks automatically!
@app.list_tools()
async def list_tools():
return [...]
@app.call_tool()
async def call_tool(name: str, arguments: dict):
return [...]
That's it! Observatory now tracks all your MCP protocol messages, performance metrics, and errors.
With Context Manager
from observatory_mcp import ObservatorySDK, ObservatoryConfig
async def main():
# Configure Observatory
config = ObservatoryConfig.create_default()
async with ObservatorySDK(
api_key="obs_live_xyz123",
server_name="my-server",
server_version="1.0.0",
config=config
) as observatory:
# SDK starts automatically
app = Server("my-server")
app = observatory.wrap_server(app)
# Run your server
await app.run()
# SDK stops automatically
📊 What Gets Tracked?
Protocol Messages
- All JSON-RPC requests and responses
- Message types, sizes, and timing
- Client-to-server and server-to-client messages
- Request/response correlation
Performance Metrics
- Request latency (p50, p95, p99)
- Throughput and message rates
- Error rates and types
- Memory and CPU usage
Error Tracking
- All exceptions and JSON-RPC errors
- Error patterns and frequencies
- Stack traces (sanitized)
- Error recovery metrics
Behavioral Analytics
- Tool usage patterns
- Resource access patterns
- Session analytics
- Feature adoption rates
⚙️ Configuration
Preset Configurations
from observatory_mcp import ObservatoryConfig
# Default (recommended)
config = ObservatoryConfig.create_default()
# Minimal overhead
config = ObservatoryConfig.create_minimal()
# High-volume servers
config = ObservatoryConfig.create_high_performance()
Custom Configuration
from observatory_mcp import (
ObservatoryConfig,
SamplingConfig,
PrivacyConfig,
PerformanceConfig
)
config = ObservatoryConfig(
# Tracking controls
track_protocol_messages=True,
track_performance_metrics=True,
track_behavioral_analytics=False,
# Sampling
sampling=SamplingConfig(
rate=1.0, # 100% sampling
adaptive_sampling=True,
prioritize_errors=True,
max_events_per_second=1000
),
# Privacy
privacy=PrivacyConfig(
enable_pii_detection=True,
hash_identifiers=True,
sensitive_field_masks=["password", "token", "api_key"],
max_message_size_capture=10_000,
data_retention_days=90
),
# Performance
performance=PerformanceConfig(
async_processing=True,
batch_size=10,
flush_interval=5.0,
heartbeat_interval=30.0,
memory_limit_mb=100
),
# Debug
debug=False,
log_level="INFO"
)
observatory = ObservatorySDK(
api_key="obs_live_xyz123",
server_name="my-server",
server_version="1.0.0",
config=config
)
🔒 Privacy & Security
Observatory is designed with privacy in mind:
- PII Detection: Automatic detection of emails, SSNs, credit cards, phone numbers
- Data Masking: Sensitive fields are automatically masked
- Identifier Hashing: User/session IDs can be hashed with SHA-256
- Configurable Retention: Set data retention policies (default: 90 days)
- Error Sanitization: Stack traces and error messages are sanitized
from observatory_mcp import PrivacyConfig
privacy = PrivacyConfig(
enable_pii_detection=True,
hash_identifiers=True,
sensitive_field_masks=[
"password", "token", "api_key", "secret",
"authorization", "ssn", "credit_card"
],
redact_errors=True
)
📈 Performance
Observatory is designed to be lightweight:
- <1ms overhead per message with default settings
- Async processing - tracking doesn't block your server
- Smart sampling - reduce overhead with adaptive sampling
- Batching - efficient batch processing of events
- Memory efficient - configurable memory limits
Benchmarks
| Operation | Overhead | Notes |
|---|---|---|
| Message tracking | <0.5ms | With 100% sampling |
| Request logging | <0.1ms | Async processing |
| Privacy scanning | <0.2ms | PII detection enabled |
| Total | <1ms | Per tracked message |
🎯 Smart Sampling
Reduce overhead while maintaining visibility:
from observatory_mcp import SamplingConfig
sampling = SamplingConfig(
rate=0.1, # Sample 10% of messages
adaptive_sampling=True, # Increase rate when errors occur
prioritize_errors=True, # Always sample error cases
always_sample_first_n=10, # First 10 per session
always_sample_last_n=10, # Last 10 per session
)
🔌 Manual Tracking (Advanced)
For advanced use cases, you can manually track messages:
observatory = ObservatorySDK(...)
await observatory.start()
# Track a message
await observatory.track_message({
"jsonrpc": "2.0",
"method": "tools/call",
"params": {...},
"id": 1
}, session_id="sess_123")
# Get statistics
stats = observatory.get_stats()
print(f"Tracked {stats['interceptor_stats']['total_count']} messages")
📚 API Reference
ObservatorySDK
The main SDK class.
class ObservatorySDK:
def __init__(
self,
api_key: str,
server_name: str,
server_version: str,
description: Optional[str] = None,
capabilities: Optional[List[str]] = None,
config: Optional[ObservatoryConfig] = None,
base_url: str = "http://localhost:8081"
)
async def start(self) -> str # Returns server_id
async def stop(self)
def wrap_server(self, server: Server) -> Server
async def track_message(self, message: dict, session_id: Optional[str] = None)
def is_enabled(self) -> bool
def get_server_id(self) -> Optional[str]
def get_stats(self) -> Dict[str, Any]
Configuration Classes
See Configuration section for detailed configuration options.
🧪 Testing
Run the test suite:
pytest
With coverage:
pytest --cov=observatory_mcp --cov-report=html
📖 Examples
See the examples/ directory for complete examples:
- basic_integration.py - Simple integration
- advanced_config.py - Custom configuration
- custom_sampling.py - Sampling strategies
🤝 Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
- Documentation: https://observatory.dev/docs/python-sdk
- GitHub: https://github.com/observatory/observatory
- PyPI: https://pypi.org/project/observatory-mcp/
- Observatory Backend: https://github.com/observatory/observatory-backend
💬 Support
- Issues: https://github.com/observatory/observatory/issues
- Discord: https://discord.gg/observatory
- Email: support@observatory.dev
🙏 Acknowledgments
Built with ❤️ for the MCP community.
Special thanks to:
- Anthropic for creating the Model Context Protocol
- The MCP community for feedback and contributions
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 observatory_mcp-0.0.2.dev0.tar.gz.
File metadata
- Download URL: observatory_mcp-0.0.2.dev0.tar.gz
- Upload date:
- Size: 12.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9ff243b52c92d72c171c498be14cbd070724a54dff8b5aabb2112336c04a153
|
|
| MD5 |
6fcb088f3463e1966c6c9a3b9a355f00
|
|
| BLAKE2b-256 |
32c2c30020e8704b9865ea507e7d43d1a58729c5d3ae37a128cd02430ba347dc
|
Provenance
The following attestation bundles were made for observatory_mcp-0.0.2.dev0.tar.gz:
Publisher:
publish.yml on amannhq/observatory-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
observatory_mcp-0.0.2.dev0.tar.gz -
Subject digest:
c9ff243b52c92d72c171c498be14cbd070724a54dff8b5aabb2112336c04a153 - Sigstore transparency entry: 596823825
- Sigstore integration time:
-
Permalink:
amannhq/observatory-python-sdk@1a9fc3979620da7daf2415275534658300208479 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/amannhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1a9fc3979620da7daf2415275534658300208479 -
Trigger Event:
release
-
Statement type:
File details
Details for the file observatory_mcp-0.0.2.dev0-py3-none-any.whl.
File metadata
- Download URL: observatory_mcp-0.0.2.dev0-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
533c3f890f441b646087b3a8574b2c21e7986904e97a9648219ceb9f77f9d8a1
|
|
| MD5 |
cd805ab8943d6b851fd0afd5453db78f
|
|
| BLAKE2b-256 |
23568812ccbb6458def25d44a5f9c3eac811dae4c22d5a4a1d804ee0616be84c
|
Provenance
The following attestation bundles were made for observatory_mcp-0.0.2.dev0-py3-none-any.whl:
Publisher:
publish.yml on amannhq/observatory-python-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
observatory_mcp-0.0.2.dev0-py3-none-any.whl -
Subject digest:
533c3f890f441b646087b3a8574b2c21e7986904e97a9648219ceb9f77f9d8a1 - Sigstore transparency entry: 596823828
- Sigstore integration time:
-
Permalink:
amannhq/observatory-python-sdk@1a9fc3979620da7daf2415275534658300208479 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/amannhq
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1a9fc3979620da7daf2415275534658300208479 -
Trigger Event:
release
-
Statement type: