Skip to content

Commit 52d2285

Browse files
committed
Address copilot feedback
1 parent 2fbd53c commit 52d2285

File tree

6 files changed

+1007
-1009
lines changed

6 files changed

+1007
-1009
lines changed

.env-sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,7 @@ OLLAMA_API_KEY=ollama
1919
# OpenAI Configuration (default if API_HOST not set)
2020
OPENAI_MODEL=gpt-4o-mini
2121
OPENAI_API_KEY=your_openai_api_key_here
22+
23+
# OpenTelemetry Configuration (for Aspire Dashboard)
24+
# Uncomment to enable tracing, metrics, and logs export
25+
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,21 @@ You can use the [.NET Aspire Dashboard](https://learn.microsoft.com/dotnet/aspir
170170
mcr.microsoft.com/dotnet/aspire-dashboard:latest
171171
```
172172

173-
2. Set the environment variable and start the HTTP server:
173+
> The Aspire Dashboard exposes its OTLP endpoint on container port 18889. The mapping `-p 4317:18889` makes it available on the host's standard OTLP port 4317.
174+
175+
Get the dashboard URL and login token from the container logs:
176+
177+
```bash
178+
docker logs aspire-dashboard 2>&1 | grep "Login to the dashboard"
179+
```
180+
181+
2. Enable OpenTelemetry by adding this to your `.env` file:
182+
183+
```bash
184+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
185+
```
186+
187+
3. Start the HTTP server:
174188

175189
```bash
176190
uv run servers/basic_mcp_http.py

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dependencies = [
1818
"azure-cosmos>=4.9.0",
1919
"azure-monitor-opentelemetry>=1.6.4",
2020
"opentelemetry-instrumentation-starlette>=0.49b0",
21+
"opentelemetry-exporter-otlp-proto-grpc>=1.28.0",
2122
"logfire>=4.15.1",
2223
"azure-core-tracing-opentelemetry>=1.0.0b12"
2324
]

servers/basic_mcp_http.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,30 @@
66
from pathlib import Path
77
from typing import Annotated
88

9+
from dotenv import load_dotenv
910
from fastmcp import FastMCP
1011
from opentelemetry_middleware import OpenTelemetryMiddleware, configure_aspire_dashboard
1112

13+
load_dotenv(override=True)
14+
1215
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(message)s")
1316
logger = logging.getLogger("ExpensesMCP")
1417

1518

16-
# Configure Aspire Dashboard telemetry if OTEL_EXPORTER_OTLP_ENDPOINT is set
17-
if os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT"):
19+
otel_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT")
20+
middleware: list = []
21+
22+
if otel_endpoint:
1823
logger.info("Setting up Aspire Dashboard instrumentation (OTLP)")
1924
configure_aspire_dashboard(service_name="expenses-mcp")
25+
middleware = [OpenTelemetryMiddleware(tracer_name="expenses.mcp")]
2026

2127

2228
SCRIPT_DIR = Path(__file__).parent
2329
EXPENSES_FILE = SCRIPT_DIR / "expenses.csv"
2430

2531

26-
mcp = FastMCP(
27-
"Expenses Tracker",
28-
middleware=[OpenTelemetryMiddleware(tracer_name="expenses.mcp")]
29-
)
32+
mcp = FastMCP("Expenses Tracker", middleware=middleware)
3033

3134

3235
class PaymentMethod(Enum):

servers/opentelemetry_middleware.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import logging
22
import os
3-
from urllib.parse import urlparse
43

54
from fastmcp.server.middleware import Middleware, MiddlewareContext
65
from opentelemetry import metrics, trace
@@ -14,45 +13,36 @@
1413
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
1514
from opentelemetry.sdk.resources import Resource
1615
from opentelemetry.sdk.trace import TracerProvider
17-
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
16+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
1817
from opentelemetry.trace import Status, StatusCode
1918

2019

2120
def configure_aspire_dashboard(service_name: str = "expenses-mcp"):
2221
"""Configure OpenTelemetry to send telemetry to the Aspire standalone dashboard."""
2322
otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317")
24-
parsed_endpoint = urlparse(otlp_endpoint)
25-
use_insecure = parsed_endpoint.scheme not in ("https", "grpcs")
2623

2724
# Create resource with service name
2825
resource = Resource.create({"service.name": service_name})
2926

3027
# Configure Tracing
3128
tracer_provider = TracerProvider(resource=resource)
32-
tracer_provider.add_span_processor(
33-
SimpleSpanProcessor(OTLPSpanExporter(endpoint=otlp_endpoint, insecure=use_insecure))
34-
)
29+
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint=otlp_endpoint)))
3530
trace.set_tracer_provider(tracer_provider)
3631

3732
# Configure Metrics
38-
metric_reader = PeriodicExportingMetricReader(
39-
OTLPMetricExporter(endpoint=otlp_endpoint, insecure=use_insecure)
40-
)
33+
metric_reader = PeriodicExportingMetricReader(OTLPMetricExporter(endpoint=otlp_endpoint))
4134
meter_provider = MeterProvider(resource=resource, metric_readers=[metric_reader])
4235
metrics.set_meter_provider(meter_provider)
4336

4437
# Configure Logging
4538
logger_provider = LoggerProvider(resource=resource)
46-
logger_provider.add_log_record_processor(
47-
BatchLogRecordProcessor(OTLPLogExporter(endpoint=otlp_endpoint, insecure=use_insecure))
48-
)
39+
logger_provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter(endpoint=otlp_endpoint)))
4940
set_logger_provider(logger_provider)
5041

5142
# Add logging handler to send Python logs to OTLP
5243
root_logger = logging.getLogger()
5344
handler_exists = any(
54-
isinstance(existing, LoggingHandler)
55-
and getattr(existing, "logger_provider", None) is logger_provider
45+
isinstance(existing, LoggingHandler) and getattr(existing, "logger_provider", None) is logger_provider
5646
for existing in root_logger.handlers
5747
)
5848

0 commit comments

Comments
 (0)