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
Release files for mcp-observer 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mcp_observer-0.1.0.tar.gz | 17.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_observer-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.9 kB
Release files / mcp_observer-0.1.0.tar.gz
| Download URL | mcp_observer-0.1.0.tar.gz |
|---|---|
| Size | 17.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d446ea1bc8b9bbd42c60f3ee5c0f4b95023b0d3c6202a6a6ae9ab2cc454d7f0a
|
|
BLAKE2b-256 checksum How to use checksums |
90210046bfd25dbd17a541791fe58ed458a7f3f74ac647296964df96666a5c77
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.13
|
Release files / mcp_observer-0.1.0-py3-none-any.whl
| Download URL | mcp_observer-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2729a05a3a9fbee4e6f0550a5f1a651fcc205d20a341120ac59fcc6911aa3e69
|
|
BLAKE2b-256 checksum How to use checksums |
47be163325840fe76b7c9e1ac9630cb7c53f7eb875489463d6273cd14ef82b1a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.13
|