Skip to content

Commit 533eab7

Browse files
committed
update conventions and address feedback
1 parent df5a243 commit 533eab7

File tree

9 files changed

+245
-167
lines changed

9 files changed

+245
-167
lines changed

Directory.Packages.props

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@
5858
<PackageVersion Include="Moq" Version="4.20.72" />
5959
<PackageVersion Include="OpenTelemetry" Version="1.11.2" />
6060
<PackageVersion Include="OpenTelemetry.Exporter.InMemory" Version="1.11.2" />
61+
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.2" />
62+
<PackageVersion Include="OpenTelemetry.Instrumentation.Http " Version="1.11.0" />
63+
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.11.2" />
64+
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.11.1" />
6165
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />
6266
<PackageVersion Include="Serilog.Extensions.Logging" Version="9.0.0" />
6367
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
@@ -67,10 +71,5 @@
6771
<PackageVersion Include="xunit.v3" Version="2.0.1" />
6872
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.2" />
6973
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
70-
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.2" />
71-
<PackageVersion Include="OpenTelemetry.Instrumentation.Http " Version="1.11.0" />
72-
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.11.2" />
73-
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.11.1" />
74-
7574
</ItemGroup>
7675
</Project>

samples/AspNetCoreSseServer/Program.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,22 @@
11
using TestServerWithHosting.Tools;
2-
using OpenTelemetry.Logs;
32
using OpenTelemetry.Metrics;
4-
using OpenTelemetry.Resources;
53
using OpenTelemetry.Trace;
6-
using AspNetCoreSseServer.Tools;
4+
using OpenTelemetry;
75

86
var builder = WebApplication.CreateBuilder(args);
97
builder.Services.AddMcpServer()
108
.WithTools<EchoTool>()
11-
.WithTools<SampleLlmTool>()
12-
.WithTools<LongRunningTool>();
9+
.WithTools<SampleLlmTool>();
1310

14-
var resource = ResourceBuilder.CreateEmpty().AddService("mcp.server");
1511
builder.Services.AddOpenTelemetry()
16-
.WithTracing(b => b.SetResourceBuilder(resource)
17-
.AddOtlpExporter()
18-
.AddSource("*")
12+
.WithTracing(b => b.AddSource("*")
1913
.AddAspNetCoreInstrumentation()
2014
.AddHttpClientInstrumentation())
21-
.WithMetrics(b => b.SetResourceBuilder(resource)
22-
.AddMeter("*")
23-
.AddOtlpExporter()
15+
.WithMetrics(b => b.AddMeter("*")
2416
.AddAspNetCoreInstrumentation()
2517
.AddHttpClientInstrumentation())
26-
.WithLogging(b => b.SetResourceBuilder(resource)
27-
.AddOtlpExporter());
18+
.WithLogging()
19+
.UseOtlpExporter();
2820

2921
var app = builder.Build();
3022

samples/AspNetCoreSseServer/Properties/launchSettings.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66
"dotnetRunMessages": true,
77
"applicationUrl": "http://localhost:3001",
88
"environmentVariables": {
9-
"ASPNETCORE_ENVIRONMENT": "Development"
9+
"ASPNETCORE_ENVIRONMENT": "Development",
10+
"OTEL_SERVICE_NAME": "sse-server",
1011
}
1112
},
1213
"https": {
1314
"commandName": "Project",
1415
"dotnetRunMessages": true,
1516
"applicationUrl": "https://localhost:7133;http://localhost:3001",
1617
"environmentVariables": {
17-
"ASPNETCORE_ENVIRONMENT": "Development"
18+
"ASPNETCORE_ENVIRONMENT": "Development",
19+
"OTEL_SERVICE_NAME": "sse-server",
1820
}
1921
}
2022
}

samples/ChatWithTools/Program.cs

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@
55

66
using OpenTelemetry;
77
using OpenTelemetry.Trace;
8-
using System.Diagnostics;
98
using Microsoft.Extensions.Logging;
109
using OpenTelemetry.Logs;
1110
using OpenTelemetry.Metrics;
12-
using ModelContextProtocol.Protocol.Messages;
1311
using ModelContextProtocol.Protocol.Types;
1412

1513
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
@@ -22,32 +20,21 @@
2220
.AddMeter("*")
2321
.AddOtlpExporter()
2422
.Build();
25-
26-
using var loggerFactory = LoggerFactory.Create(builder =>
27-
{
28-
builder.AddOpenTelemetry(opt =>
29-
{
30-
opt.IncludeFormattedMessage = true;
31-
opt.IncludeScopes = true;
32-
opt.AddOtlpExporter();
33-
});
34-
});
23+
using var loggerFactory = LoggerFactory.Create(builder => builder.AddOpenTelemetry(opt => opt.AddOtlpExporter()));
3524

3625
// Connect to an MCP server
37-
Console.WriteLine("Connecting client to MCP 'aspnetcore' server");
26+
Console.WriteLine("Connecting client to MCP 'everything' server");
3827

39-
40-
// Create an IChatClient. (This shows using OpenAIClient, but it could be any other IChatClient implementation.)
28+
// Create OpenAI client (or any other compatible with IChatClient)
4129
// Provide your own OPENAI_API_KEY via an environment variable.
42-
using IChatClient chatClient =
43-
new OpenAIClient(Environment.GetEnvironmentVariable("OPENAI_API_KEY")).GetChatClient("gpt-4o-mini").AsIChatClient()
30+
var openAIClient = new OpenAIClient(Environment.GetEnvironmentVariable("OPENAI_API_KEY")).GetChatClient("gpt-4o-mini");
31+
32+
// Create a sampling client.
33+
using IChatClient samplingClient = openAIClient.AsIChatClient()
4434
.AsBuilder()
45-
.UseFunctionInvocation()
4635
.UseOpenTelemetry(loggerFactory: loggerFactory, configure: o => o.EnableSensitiveData = true)
4736
.Build();
4837

49-
var samplingHandler = chatClient.CreateSamplingHandler();
50-
5138
var mcpClient = await McpClientFactory.CreateAsync(
5239
new StdioClientTransport(new()
5340
{
@@ -59,10 +46,7 @@
5946
{
6047
Capabilities = new ClientCapabilities()
6148
{
62-
Sampling = new SamplingCapability() { SamplingHandler = (param, progress, ct) => {
63-
Console.WriteLine(param?.Meta?.ProgressToken);
64-
return samplingHandler(param, progress, ct);
65-
} }
49+
Sampling = new SamplingCapability() { SamplingHandler = samplingClient.CreateSamplingHandler() }
6650
},
6751
},
6852
loggerFactory: loggerFactory);
@@ -77,6 +61,13 @@
7761

7862
Console.WriteLine();
7963

64+
// Create an IChatClient that can use the tools.
65+
using IChatClient chatClient = openAIClient.AsIChatClient()
66+
.AsBuilder()
67+
.UseFunctionInvocation()
68+
.UseOpenTelemetry(loggerFactory: loggerFactory, configure: o => o.EnableSensitiveData = true)
69+
.Build();
70+
8071
// Have a conversation, making all tools available to the LLM.
8172
List<ChatMessage> messages = [];
8273
while (true)

samples/EverythingServer/EverythingServer.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
<PackageReference Include="Microsoft.Extensions.Hosting" />
1212
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
1313
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
14-
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
1514
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
1615
</ItemGroup>
1716

samples/EverythingServer/Program.cs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using ModelContextProtocol;
99
using ModelContextProtocol.Protocol.Types;
1010
using ModelContextProtocol.Server;
11+
using OpenTelemetry;
1112
using OpenTelemetry.Logs;
1213
using OpenTelemetry.Metrics;
1314
using OpenTelemetry.Resources;
@@ -190,21 +191,12 @@ await ctx.Server.RequestSamplingAsync([
190191
return new EmptyResult();
191192
});
192193

193-
194-
var resource = ResourceBuilder.CreateEmpty().AddService("mcp.server");
194+
ResourceBuilder resource = ResourceBuilder.CreateDefault().AddService("everything-server");
195195
builder.Services.AddOpenTelemetry()
196-
.WithTracing(b => b.SetResourceBuilder(resource)
197-
.AddOtlpExporter()
198-
.AddSource("*")
199-
.AddAspNetCoreInstrumentation()
200-
.AddHttpClientInstrumentation())
201-
.WithMetrics(b => b.SetResourceBuilder(resource)
202-
.AddMeter("*")
203-
.AddOtlpExporter()
204-
.AddAspNetCoreInstrumentation()
205-
.AddHttpClientInstrumentation())
206-
.WithLogging(b => b.SetResourceBuilder(resource)
207-
.AddOtlpExporter());
196+
.WithTracing(b => b.AddSource("*").AddHttpClientInstrumentation().SetResourceBuilder(resource))
197+
.WithMetrics(b => b.AddMeter("*").AddHttpClientInstrumentation().SetResourceBuilder(resource))
198+
.WithLogging(b => b.SetResourceBuilder(resource))
199+
.UseOtlpExporter();
208200

209201
builder.Services.AddSingleton(subscriptions);
210202
builder.Services.AddHostedService<SubscriptionMessageSender>();

src/ModelContextProtocol/Diagnostics.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
using System.Diagnostics;
22
using System.Diagnostics.Metrics;
3+
using System.Text.Json;
4+
using System.Text.Json.Nodes;
5+
using ModelContextProtocol.Protocol.Messages;
36

47
namespace ModelContextProtocol;
58

@@ -34,4 +37,79 @@ internal static Histogram<double> CreateDurationHistogram(string name, string de
3437
HistogramBucketBoundaries = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300],
3538
};
3639
#endif
40+
41+
internal static ActivityContext ExtractActivityContext(this DistributedContextPropagator propagator, IJsonRpcMessage message)
42+
{
43+
string? traceparent = null;
44+
string? tracestate = null;
45+
propagator?.ExtractTraceIdAndState(message, ExtractContext, out traceparent, out tracestate);
46+
ActivityContext.TryParse(traceparent, tracestate, true, out var activityContext);
47+
return activityContext;
48+
}
49+
50+
private static void ExtractContext(object? message, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues)
51+
{
52+
fieldValues = null;
53+
fieldValue = null;
54+
55+
JsonNode? parameters = null;
56+
switch (message)
57+
{
58+
case JsonRpcRequest request:
59+
parameters = request.Params;
60+
break;
61+
62+
case JsonRpcNotification notification:
63+
parameters = notification.Params;
64+
break;
65+
66+
default:
67+
break;
68+
}
69+
70+
if (parameters?[fieldName] is JsonValue value && value.GetValueKind() == JsonValueKind.String)
71+
{
72+
fieldValue = value.GetValue<string>();
73+
}
74+
}
75+
76+
internal static void InjectActivityContext(this DistributedContextPropagator propagator, Activity? activity, IJsonRpcMessage message)
77+
{
78+
// noop if activity is null
79+
propagator?.Inject(activity, message, InjectContext);
80+
}
81+
82+
private static void InjectContext(object? message, string key, string value)
83+
{
84+
JsonNode? parameters = null;
85+
switch (message)
86+
{
87+
case JsonRpcRequest request:
88+
parameters = request.Params;
89+
break;
90+
91+
case JsonRpcNotification notification:
92+
parameters = notification.Params;
93+
break;
94+
95+
default:
96+
break;
97+
}
98+
99+
if (parameters is JsonObject jsonObject && jsonObject[key] == null)
100+
{
101+
jsonObject[key] = value;
102+
}
103+
}
104+
105+
internal static bool ShouldInstrumentMessage(IJsonRpcMessage message) =>
106+
ActivitySource.HasListeners() &&
107+
message switch
108+
{
109+
JsonRpcRequest => true,
110+
JsonRpcNotification notification => notification.Method != NotificationMethods.LoggingMessageNotification,
111+
_ => false
112+
};
113+
114+
internal static ActivityLink[] ActivityLinkFromCurrent() => Activity.Current is null ? [] : [new ActivityLink(Activity.Current.Context)];
37115
}

0 commit comments

Comments
 (0)