This document provides guidance for developing and contributing to the TelemetryFlow Python MCP Server.
- Python 3.11 or higher
- Git
- Make (optional, for convenience commands)
git clone https://github.com/telemetryflow/telemetryflow-python-mcp.git
cd telemetryflow-python-mcppython -m venv .venv
source .venv/bin/activate # Linux/macOS
# or
.venv\Scripts\activate # Windows# Using make
make dev
# Or manually
pip install -e ".[dev]"
pre-commit installcp .env.example .env
# Edit .env and add your ANTHROPIC_API_KEYThe synchronized .env.example contains 25 configuration sections aligned with TFO Python-SDK patterns, covering MCP server, LLM, telemetry exporter, datasource, caching, queue, and Docker profile settings.
telemetryflow-python-mcp/
├── src/tfo_mcp/
│ ├── domain/ # Domain Layer (DDD)
│ │ ├── aggregates/ # Session, Conversation
│ │ ├── entities/ # Message, Tool, Resource, Prompt
│ │ ├── valueobjects/ # IDs, MCP types, Content types
│ │ ├── events/ # Domain events
│ │ ├── repositories/ # Repository interfaces
│ │ └── services/ # Service interfaces
│ ├── application/ # Application Layer (CQRS)
│ │ ├── commands/ # Write operations
│ │ ├── queries/ # Read operations
│ │ ├── handlers/ # Command/Query handlers
│ │ └── services/ # Application services (ContextCollector, PromptBuilder)
│ ├── infrastructure/ # Infrastructure Layer
│ │ ├── claude/ # LLM API client (12 providers)
│ │ ├── config/ # Configuration management
│ │ ├── logging/ # Structured logging
│ │ ├── cache/ # Redis cache (optional)
│ │ ├── queue/ # NATS queue (optional)
│ │ └── persistence/ # Repository implementations
│ ├── presentation/ # Presentation Layer
│ │ ├── server/ # MCP server (official MCP SDK mcp>=1.27.0)
│ │ ├── tools/ # Built-in tools (17 + ContextCollector + PromptBuilder)
│ │ ├── resources/ # Built-in resources
│ │ └── prompts/ # Built-in prompts
│ └── main.py # CLI entry point
├── tests/ # Test suite (1174 tests, 98% coverage)
│ ├── unit/ # Unit tests
│ │ ├── domain/ # Domain layer tests
│ │ ├── application/ # Application layer tests
│ │ ├── infrastructure/ # Infrastructure layer tests
│ │ └── presentation/ # Presentation layer tests
│ ├── integration/ # Integration tests
│ │ ├── datasource/ # PostgreSQL & ClickHouse tests
│ │ ├── handlers/ # Handler integration tests
│ │ └── server/ # Server integration tests
│ ├── e2e/ # End-to-end tests
│ │ ├── protocol/ # MCP protocol tests
│ │ └── flow/ # Full flow tests
│ ├── conftest.py # Shared fixtures
│ └── __init__.py
├── configs/ # Configuration files
├── migrations/ # Database migrations
├── docs/ # Documentation
└── pyproject.toml # Project configuration
# Standard run
make run
# Debug mode
make run-debug
# With custom config
tfo-mcp serve -c configs/tfo-mcp.yaml --debugThe project includes Docker Compose profiles for different development and deployment scenarios:
| Profile | Services | Use Case |
|---|---|---|
dev |
tfo-mcp + tfo-collector | Development with telemetry |
full |
dev + prometheus | Full observability stack |
platform |
tfo-mcp + postgres + clickhouse + redis + nats + tfo-backend + tfo-viz + tfo-collector | Full TFO Platform |
analytics |
clickhouse | ClickHouse analytics only |
observability |
otel-collector + jaeger + prometheus + grafana | Observability visualization |
# Development with telemetry
docker-compose --profile dev up -d
# Full observability stack
docker-compose --profile full up -d
# Full TFO Platform
docker-compose --profile platform up -d
# ClickHouse analytics only
docker-compose --profile analytics up -d
# Observability visualization
docker-compose --profile observability up -d# All tests (1174 tests)
make test
# With coverage (98%)
make test-cov
# Specific test directory
pytest tests/unit/domain/ -v
# Specific test file
pytest tests/unit/domain/test_aggregates.py -v
# Specific test
pytest tests/unit/domain/test_aggregates.py::TestSession::test_create_session -v# Run linters
make lint
# Format code
make format
# Type checking
mypy srcThe application/services/ directory contains application-level service classes that encapsulate cross-cutting concerns:
Collects and assembles telemetry context from multiple data sources, providing a unified view of observability data for prompt generation.
Builds system prompts and context prompts for LLM interactions, supporting 40+ specialized context types (metrics, logs, traces, alerts, Kubernetes resources, infrastructure, IAM, tenancy, database monitoring, etc.) with configurable system instructions and insight generation modes (chronology, prediction, recommendation, root-cause, pattern).
# src/tfo_mcp/presentation/tools/builtin_tools.py
async def _my_tool_handler(input_data: dict[str, Any]) -> ToolResult:
"""My tool handler."""
param = input_data.get("param")
if not param:
return ToolResult.error("param is required")
# Do something
result = f"Processed: {param}"
return ToolResult.text(result)# src/tfo_mcp/presentation/server/tool_registration.py
server.register_tool(
name="my_tool",
description="Description of my tool",
input_schema={
"type": "object",
"properties": {
"param": {
"type": "string",
"description": "The parameter",
}
},
"required": ["param"],
},
handler=_my_tool_handler,
)# tests/unit/presentation/test_my_tool.py
class TestMyTool:
@pytest.mark.asyncio
async def test_my_tool_success(self):
result = await _my_tool_handler({"param": "test"})
assert not result.is_error
assert "test" in result.content[0]["text"]
@pytest.mark.asyncio
async def test_my_tool_missing_param(self):
result = await _my_tool_handler({})
assert result.is_error# src/tfo_mcp/presentation/resources/builtin_resources.py
async def _my_resource_reader(uri: str, params: dict[str, str]) -> ResourceContent:
"""Read my resource."""
data = {"key": "value"}
return ResourceContent(
uri=uri,
mime_type=MimeType.APPLICATION_JSON,
text=json.dumps(data, indent=2),
)# src/tfo_mcp/presentation/server/resource_registration.py
server.register_resource(
uri="my://resource",
name="My Resource",
description="Description",
mime_type="application/json",
reader=_my_resource_reader,
)# src/tfo_mcp/presentation/prompts/builtin_prompts.py
async def _my_prompt_generator(args: dict[str, str]) -> list[PromptMessage]:
"""Generate my prompt messages."""
topic = args.get("topic", "")
return [
PromptMessage(
role=Role.USER,
content=f"Help me with {topic}",
)
]# src/tfo_mcp/presentation/server/prompt_registration.py
server.register_prompt(
name="my_prompt",
description="My prompt description",
arguments=[
{
"name": "topic",
"description": "The topic",
"required": True,
},
],
generator=_my_prompt_generator,
)- No framework dependencies - Domain should be pure Python
- Value objects are immutable - Use
frozen=Truedataclasses - Aggregates protect invariants - Use methods to modify state
- Domain events for side effects - Emit events, don't call services
- Commands change state - One command, one change
- Queries are read-only - No side effects
- Handlers are thin - Orchestrate, don't implement logic
- Services encapsulate cross-cutting concerns - ContextCollector and PromptBuilder coordinate across domain boundaries
- Implement domain interfaces - Repository implementations here
- Handle external concerns - HTTP, database, caching
- Configuration here - Environment, files, defaults
- Use official MCP SDK -
mcp>=1.27.0for protocol handling - Delegate to application layer - Don't implement business logic
- Tools are self-contained - Each tool is independent
Tests are organized to mirror the domain structure:
tests/
├── unit/ # Unit tests (isolated)
│ ├── domain/ # Domain layer
│ ├── application/ # Application layer (including services/)
│ ├── infrastructure/ # Infrastructure layer
│ └── presentation/ # Presentation layer
├── integration/ # Integration tests
│ ├── datasource/ # PostgreSQL & ClickHouse
│ ├── handlers/ # Handler integration
│ └── server/ # Server integration
└── e2e/ # End-to-end tests
├── protocol/ # MCP protocol
└── flow/ # Full flow
- Test domain entities and value objects
- Test tool handlers in isolation
- Test application services (ContextCollector, PromptBuilder)
- Mock external dependencies
- Test handler integration
- Test server request handling
- Test PostgreSQL and ClickHouse datasource tools
- Use in-memory repositories
- Test full JSON-RPC flow
- Test with real stdio
- Test error scenarios
- Update version in
pyproject.tomlandsrc/tfo_mcp/__init__.py(current: 1.2.0) - Update CHANGELOG.md
- Create release commit
- Tag release
- Build and publish
# Build
make build
# Publish (with credentials)
twine upload dist/*Import errors after changes:
pip install -e .Type checking failures:
mypy src --show-error-codesTest failures:
pytest -v --tb=longEnable debug logging:
tfo-mcp serve --debugOr set environment:
TELEMETRYFLOW_MCP_LOG_LEVEL=debug tfo-mcp serve