A decorator-based observability SDK for MCP (Model Context Protocol) tools with OpenTelemetry integration
Project description
MCP Observer SDK
A lightweight, decorator-based observability SDK for Model Context Protocol (MCP) tools. Add comprehensive telemetry and insights to your MCP servers with a single line of code.
Features
- Zero-friction Integration: Add observability with a simple decorator
- OpenTelemetry Support: Built-in tracing, metrics, and distributed context propagation
- Privacy-First: Configurable I/O tracking with dual-consent system
- Universal Compatibility: Works with all MCP tool function signatures
- Dual Storage: Durable storage for analytics + real-time streaming via OpenTelemetry
- Session Tracking: Automatic session and request correlation
Installation
From PyPI
pip install mcp-observer
Using uv (recommended)
uv pip install mcp-observer
For development
# Clone the repository
git clone https://github.com/yourusername/mcp-observer-sdk.git
cd mcp-observer-sdk
# Install in development mode
pip install -e ".[dev]"
Quick Start
from mcp_observer import MCPObserver
from fastmcp import FastMCP
# Initialize your MCP server
mcp = FastMCP("MyServer")
# Initialize the observer (project is automatically determined from your API key)
observer = MCPObserver(
name="MyServer",
version="1.0.0",
api_key="your-generated-api-key"
)
# Decorate your tools
@mcp.tool()
@observer.track(track_io=True)
async def my_tool(data: dict) -> dict:
# Your tool logic here
return {"result": "success"}
Examples
Example 1: Simple Tool (No Context)
from mcp_observer import MCPObserver
from fastmcp import FastMCP
mcp = FastMCP("MathServer")
observer = MCPObserver(
name="MathServer",
version="1.0.0",
api_key="your-api-key"
)
@mcp.tool(name="adder", description="Add two numbers")
@observer.track(track_io=True)
async def add(a: int, b: int) -> int:
"""Add two numbers together"""
return a + b
Example 2: Tool with Session Context
from mcp_observer import MCPObserver
from fastmcp import FastMCP, Context
from typing import Optional
mcp = FastMCP("EchoServer")
observer = MCPObserver(
name="EchoServer",
version="1.0.0",
api_key="your-api-key"
)
@mcp.tool(name="echo", description="Echo the input with session tracking")
@observer.track(track_io=True)
async def echo(message: str, ctx: Optional[Context] = None) -> str:
"""Echo input string with session ID"""
if ctx:
return f"{message} (Session: {ctx.session_id})"
return message
Example 3: Fingerprint-Only Tracking (Default)
For tools that handle sensitive data, omit track_io=True to only store fingerprints:
@mcp.tool(name="process_sensitive_data")
@observer.track() # Only fingerprints stored, no full I/O
async def process_sensitive_data(user_data: dict) -> dict:
"""Process sensitive user data"""
# Only metadata is logged, not the actual data
return {"status": "processed"}
Parameters on MCP Observer:
Constructor
name: Name of your server or application (This is what appears in logging)version: Version of your server/applicationapi_key: Your API key for authentication (project is automatically determined from this key)
Decorator: @observer.track()
track_io(bool): If True, enables full input/output tracking (requires project consent)- Default: False (only fingerprints are stored)
Advanced Features
OpenTelemetry Integration
The SDK automatically integrates with OpenTelemetry for distributed tracing and metrics:
observer = MCPObserver(
name="MyServer",
version="1.0.0",
api_key="your-api-key",
otlp_endpoint="http://localhost:4317", # Optional: Send to OTLP collector
enable_console_export=True # Optional: Enable console debugging
)
Environment Variables:
OTEL_EXPORTER_OTLP_ENDPOINT: Configure OTLP endpoint for production tracingOTEL_CONSOLE_EXPORT: Set to"true"to enable console span/metric export
Automatic Metrics:
mcp.tool.calls: Counter for tool invocationsmcp.tool.duration: Histogram of tool execution times (ms)mcp.tool.errors: Counter for tool errors
Automatic Spans:
- Each tool call creates a span named
mcp.tool.{function_name} - Spans include: call_id, session_id, latency, status, error details
Tracking Policy System
The SDK uses a dual-consent system for full I/O tracking:
- Developer declares safety: Use
@observer.track(track_io=True) - Project admin enables: Backend API controls per-tool policy
- Results are cached: Policy responses cached for 1 hour (configurable)
This ensures sensitive data is only stored when both developer and admin consent.
Custom Logging
Pass your own logger for integration with existing logging infrastructure:
import logging
my_logger = logging.getLogger("MyApp")
my_logger.setLevel(logging.DEBUG)
observer = MCPObserver(
name="MyServer",
version="1.0.0",
api_key="your-api-key",
logger=my_logger
)
Running the Example
# Install dependencies
uv pip install -e ".[dev]"
# Run the example server
python tests/simple_example.py
API Reference
MCPObserver(name, version, api_key, **kwargs)
Initialize the observer for your MCP server.
Parameters:
name(str): Your server/application nameversion(str): Your server/application versionapi_key(str): Authentication key (project is auto-determined)otlp_endpoint(str, optional): OTLP collector endpointenable_console_export(bool, optional): Enable console span/metric outputlogger(logging.Logger, optional): Custom logger instance
@observer.track(track_io=False)
Decorator to add observability to MCP tools.
Parameters:
track_io(bool, optional): Enable full I/O tracking (requires project consent). Default: False
Returns:
- Decorated async function with telemetry
Development
Running Tests
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run with coverage
pytest --cov=mcp_observer --cov-report=html
Code Quality
# Format code
black src tests
# Type checking
mypy src
# Linting
ruff check src tests
Project Structure
mcp-observer-sdk/
├── src/
│ └── mcp_observer/
│ ├── __init__.py # Package exports
│ ├── observer.py # Main MCPObserver class
│ └── wrapper.py # Decorator and telemetry logic
├── tests/
│ └── simple_example.py # Example MCP server
├── pyproject.toml # Package configuration
├── README.md # This file
└── LICENSE # MIT License
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Issues: GitHub Issues
- Documentation: Full Documentation
- Email: support@yourdomain.com
Acknowledgments
- Built for the Model Context Protocol
- Powered by OpenTelemetry
- Inspired by the need for better MCP tool observability
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 mcp_observer-0.1.0.tar.gz.
File metadata
- Download URL: mcp_observer-0.1.0.tar.gz
- Upload date:
- Size: 17.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d446ea1bc8b9bbd42c60f3ee5c0f4b95023b0d3c6202a6a6ae9ab2cc454d7f0a
|
|
| MD5 |
f17d3c4e47fed305e777b97c33775125
|
|
| BLAKE2b-256 |
90210046bfd25dbd17a541791fe58ed458a7f3f74ac647296964df96666a5c77
|
File details
Details for the file mcp_observer-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_observer-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2729a05a3a9fbee4e6f0550a5f1a651fcc205d20a341120ac59fcc6911aa3e69
|
|
| MD5 |
717437b117585882310fe6b014ba4d66
|
|
| BLAKE2b-256 |
47be163325840fe76b7c9e1ac9630cb7c53f7eb875489463d6273cd14ef82b1a
|