# Observatory MCP Python SDK
[](https://badge.fury.io/py/observatory-mcp)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
**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
```bash
pip install observatory-mcp
```
For MCP server integration:
```bash
pip install observatory-mcp[mcp]
```
For development:
```bash
pip install observatory-mcp[dev]
```
## ๐ Quick Start
### Basic Integration (2 lines!)
```python
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
```python
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
```python
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
```python
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
```python
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:
```python
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:
```python
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.
```python
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](#configuration) section for detailed configuration options.
## ๐งช Testing
Run the test suite:
```bash
pytest
```
With coverage:
```bash
pytest --cov=observatory_mcp --cov-report=html
```
## ๐ Examples
See the [examples/](examples/) directory for complete examples:
- [basic_integration.py](examples/basic_integration.py) - Simple integration
- [advanced_config.py](examples/advanced_config.py) - Custom configuration
- [custom_sampling.py](examples/custom_sampling.py) - Sampling strategies
## ๐ค Contributing
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
## ๐ License
This project is licensed under the MIT License - see the [LICENSE](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](https://www.anthropic.com/) for creating the Model Context Protocol
- The MCP community for feedback and contributions
Raw data
{
"_id": null,
"home_page": null,
"name": "observatory-mcp",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": "Observatory Team <team@observatory.dev>",
"keywords": "mcp, model-context-protocol, observability, analytics, monitoring, telemetry, metrics, tracking, sdk",
"author": null,
"author_email": "Observatory Team <team@observatory.dev>",
"download_url": "https://files.pythonhosted.org/packages/32/c2/c30020e8704b9865ea507e7d43d1a58729c5d3ae37a128cd02430ba347dc/observatory_mcp-0.0.2.dev0.tar.gz",
"platform": null,
"description": "# Observatory MCP Python SDK\n\n[](https://badge.fury.io/py/observatory-mcp)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n\n**Add comprehensive analytics and monitoring to your MCP servers with just 2-3 lines of code.**\n\nObservatory 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.\n\n## \u2728 Features\n\n- \ud83d\ude80 **2-Line Integration**: Add observability with minimal code changes\n- \ud83d\udcca **Complete Analytics**: Protocol messages, performance metrics, error tracking\n- \ud83d\udd12 **Privacy-First**: Built-in PII detection and data masking\n- \u26a1 **Lightweight**: <1ms overhead per message, async processing\n- \ud83c\udfaf **Smart Sampling**: Adaptive sampling with error prioritization\n- \ud83d\udd0c **Zero Server Modification**: Works via protocol message interception\n- \ud83d\udcc8 **Real-Time Monitoring**: Live dashboards and alerting\n- \ud83d\udc0d **Type-Safe**: Full type hints for IDE autocomplete\n\n## \ud83d\udce6 Installation\n\n```bash\npip install observatory-mcp\n```\n\nFor MCP server integration:\n```bash\npip install observatory-mcp[mcp]\n```\n\nFor development:\n```bash\npip install observatory-mcp[dev]\n```\n\n## \ud83d\ude80 Quick Start\n\n### Basic Integration (2 lines!)\n\n```python\nfrom mcp.server import Server\nfrom observatory_mcp import ObservatorySDK\n\n# Create your MCP server as usual\napp = Server(\"my-awesome-mcp-server\")\n\n# Add Observatory with 2 lines!\nobservatory = ObservatorySDK(\n api_key=\"obs_live_xyz123\",\n server_name=\"my-awesome-mcp-server\",\n server_version=\"1.0.0\"\n)\napp = observatory.wrap_server(app)\n\n# Your handlers work exactly the same - Observatory tracks automatically!\n@app.list_tools()\nasync def list_tools():\n return [...]\n\n@app.call_tool()\nasync def call_tool(name: str, arguments: dict):\n return [...]\n```\n\nThat's it! Observatory now tracks all your MCP protocol messages, performance metrics, and errors.\n\n### With Context Manager\n\n```python\nfrom observatory_mcp import ObservatorySDK, ObservatoryConfig\n\nasync def main():\n # Configure Observatory\n config = ObservatoryConfig.create_default()\n \n async with ObservatorySDK(\n api_key=\"obs_live_xyz123\",\n server_name=\"my-server\",\n server_version=\"1.0.0\",\n config=config\n ) as observatory:\n # SDK starts automatically\n app = Server(\"my-server\")\n app = observatory.wrap_server(app)\n \n # Run your server\n await app.run()\n \n # SDK stops automatically\n```\n\n## \ud83d\udcca What Gets Tracked?\n\n### Protocol Messages\n- All JSON-RPC requests and responses\n- Message types, sizes, and timing\n- Client-to-server and server-to-client messages\n- Request/response correlation\n\n### Performance Metrics\n- Request latency (p50, p95, p99)\n- Throughput and message rates\n- Error rates and types\n- Memory and CPU usage\n\n### Error Tracking\n- All exceptions and JSON-RPC errors\n- Error patterns and frequencies\n- Stack traces (sanitized)\n- Error recovery metrics\n\n### Behavioral Analytics\n- Tool usage patterns\n- Resource access patterns\n- Session analytics\n- Feature adoption rates\n\n## \u2699\ufe0f Configuration\n\n### Preset Configurations\n\n```python\nfrom observatory_mcp import ObservatoryConfig\n\n# Default (recommended)\nconfig = ObservatoryConfig.create_default()\n\n# Minimal overhead\nconfig = ObservatoryConfig.create_minimal()\n\n# High-volume servers\nconfig = ObservatoryConfig.create_high_performance()\n```\n\n### Custom Configuration\n\n```python\nfrom observatory_mcp import (\n ObservatoryConfig,\n SamplingConfig,\n PrivacyConfig,\n PerformanceConfig\n)\n\nconfig = ObservatoryConfig(\n # Tracking controls\n track_protocol_messages=True,\n track_performance_metrics=True,\n track_behavioral_analytics=False,\n \n # Sampling\n sampling=SamplingConfig(\n rate=1.0, # 100% sampling\n adaptive_sampling=True,\n prioritize_errors=True,\n max_events_per_second=1000\n ),\n \n # Privacy\n privacy=PrivacyConfig(\n enable_pii_detection=True,\n hash_identifiers=True,\n sensitive_field_masks=[\"password\", \"token\", \"api_key\"],\n max_message_size_capture=10_000,\n data_retention_days=90\n ),\n \n # Performance\n performance=PerformanceConfig(\n async_processing=True,\n batch_size=10,\n flush_interval=5.0,\n heartbeat_interval=30.0,\n memory_limit_mb=100\n ),\n \n # Debug\n debug=False,\n log_level=\"INFO\"\n)\n\nobservatory = ObservatorySDK(\n api_key=\"obs_live_xyz123\",\n server_name=\"my-server\",\n server_version=\"1.0.0\",\n config=config\n)\n```\n\n## \ud83d\udd12 Privacy & Security\n\nObservatory is designed with privacy in mind:\n\n- **PII Detection**: Automatic detection of emails, SSNs, credit cards, phone numbers\n- **Data Masking**: Sensitive fields are automatically masked\n- **Identifier Hashing**: User/session IDs can be hashed with SHA-256\n- **Configurable Retention**: Set data retention policies (default: 90 days)\n- **Error Sanitization**: Stack traces and error messages are sanitized\n\n```python\nfrom observatory_mcp import PrivacyConfig\n\nprivacy = PrivacyConfig(\n enable_pii_detection=True,\n hash_identifiers=True,\n sensitive_field_masks=[\n \"password\", \"token\", \"api_key\", \"secret\",\n \"authorization\", \"ssn\", \"credit_card\"\n ],\n redact_errors=True\n)\n```\n\n## \ud83d\udcc8 Performance\n\nObservatory is designed to be lightweight:\n\n- **<1ms overhead** per message with default settings\n- **Async processing** - tracking doesn't block your server\n- **Smart sampling** - reduce overhead with adaptive sampling\n- **Batching** - efficient batch processing of events\n- **Memory efficient** - configurable memory limits\n\n### Benchmarks\n\n| Operation | Overhead | Notes |\n|-----------|----------|-------|\n| Message tracking | <0.5ms | With 100% sampling |\n| Request logging | <0.1ms | Async processing |\n| Privacy scanning | <0.2ms | PII detection enabled |\n| **Total** | **<1ms** | Per tracked message |\n\n## \ud83c\udfaf Smart Sampling\n\nReduce overhead while maintaining visibility:\n\n```python\nfrom observatory_mcp import SamplingConfig\n\nsampling = SamplingConfig(\n rate=0.1, # Sample 10% of messages\n adaptive_sampling=True, # Increase rate when errors occur\n prioritize_errors=True, # Always sample error cases\n always_sample_first_n=10, # First 10 per session\n always_sample_last_n=10, # Last 10 per session\n)\n```\n\n## \ud83d\udd0c Manual Tracking (Advanced)\n\nFor advanced use cases, you can manually track messages:\n\n```python\nobservatory = ObservatorySDK(...)\nawait observatory.start()\n\n# Track a message\nawait observatory.track_message({\n \"jsonrpc\": \"2.0\",\n \"method\": \"tools/call\",\n \"params\": {...},\n \"id\": 1\n}, session_id=\"sess_123\")\n\n# Get statistics\nstats = observatory.get_stats()\nprint(f\"Tracked {stats['interceptor_stats']['total_count']} messages\")\n```\n\n## \ud83d\udcda API Reference\n\n### ObservatorySDK\n\nThe main SDK class.\n\n```python\nclass ObservatorySDK:\n def __init__(\n self,\n api_key: str,\n server_name: str,\n server_version: str,\n description: Optional[str] = None,\n capabilities: Optional[List[str]] = None,\n config: Optional[ObservatoryConfig] = None,\n base_url: str = \"http://localhost:8081\"\n )\n \n async def start(self) -> str # Returns server_id\n async def stop(self)\n def wrap_server(self, server: Server) -> Server\n async def track_message(self, message: dict, session_id: Optional[str] = None)\n \n def is_enabled(self) -> bool\n def get_server_id(self) -> Optional[str]\n def get_stats(self) -> Dict[str, Any]\n```\n\n### Configuration Classes\n\nSee [Configuration](#configuration) section for detailed configuration options.\n\n## \ud83e\uddea Testing\n\nRun the test suite:\n\n```bash\npytest\n```\n\nWith coverage:\n\n```bash\npytest --cov=observatory_mcp --cov-report=html\n```\n\n## \ud83d\udcd6 Examples\n\nSee the [examples/](examples/) directory for complete examples:\n\n- [basic_integration.py](examples/basic_integration.py) - Simple integration\n- [advanced_config.py](examples/advanced_config.py) - Custom configuration\n- [custom_sampling.py](examples/custom_sampling.py) - Sampling strategies\n\n## \ud83e\udd1d Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.\n\n## \ud83d\udcc4 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## \ud83d\udd17 Links\n\n- **Documentation**: https://observatory.dev/docs/python-sdk\n- **GitHub**: https://github.com/observatory/observatory\n- **PyPI**: https://pypi.org/project/observatory-mcp/\n- **Observatory Backend**: https://github.com/observatory/observatory-backend\n\n## \ud83d\udcac Support\n\n- **Issues**: https://github.com/observatory/observatory/issues\n- **Discord**: https://discord.gg/observatory\n- **Email**: support@observatory.dev\n\n## \ud83d\ude4f Acknowledgments\n\nBuilt with \u2764\ufe0f for the MCP community.\n\nSpecial thanks to:\n- [Anthropic](https://www.anthropic.com/) for creating the Model Context Protocol\n- The MCP community for feedback and contributions\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Observatory SDK for MCP server analytics and monitoring - Add comprehensive observability to your MCP servers with just 2 lines of code",
"version": "0.0.2.dev0",
"project_urls": {
"Changelog": "https://github.com/observatory/observatory/blob/main/CHANGELOG.md",
"Documentation": "https://observatory.dev/docs/python-sdk",
"Homepage": "https://observatory.dev",
"Issues": "https://github.com/observatory/observatory/issues",
"Repository": "https://github.com/observatory/observatory"
},
"split_keywords": [
"mcp",
" model-context-protocol",
" observability",
" analytics",
" monitoring",
" telemetry",
" metrics",
" tracking",
" sdk"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "23568812ccbb6458def25d44a5f9c3eac811dae4c22d5a4a1d804ee0616be84c",
"md5": "cd805ab8943d6b851fd0afd5453db78f",
"sha256": "533c3f890f441b646087b3a8574b2c21e7986904e97a9648219ceb9f77f9d8a1"
},
"downloads": -1,
"filename": "observatory_mcp-0.0.2.dev0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cd805ab8943d6b851fd0afd5453db78f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 21776,
"upload_time": "2025-10-09T04:53:10",
"upload_time_iso_8601": "2025-10-09T04:53:10.601779Z",
"url": "https://files.pythonhosted.org/packages/23/56/8812ccbb6458def25d44a5f9c3eac811dae4c22d5a4a1d804ee0616be84c/observatory_mcp-0.0.2.dev0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "32c2c30020e8704b9865ea507e7d43d1a58729c5d3ae37a128cd02430ba347dc",
"md5": "6fcb088f3463e1966c6c9a3b9a355f00",
"sha256": "c9ff243b52c92d72c171c498be14cbd070724a54dff8b5aabb2112336c04a153"
},
"downloads": -1,
"filename": "observatory_mcp-0.0.2.dev0.tar.gz",
"has_sig": false,
"md5_digest": "6fcb088f3463e1966c6c9a3b9a355f00",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 12396277,
"upload_time": "2025-10-09T04:53:12",
"upload_time_iso_8601": "2025-10-09T04:53:12.059048Z",
"url": "https://files.pythonhosted.org/packages/32/c2/c30020e8704b9865ea507e7d43d1a58729c5d3ae37a128cd02430ba347dc/observatory_mcp-0.0.2.dev0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-09 04:53:12",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "observatory",
"github_project": "observatory",
"github_not_found": true,
"lcname": "observatory-mcp"
}