Skip to content

Commit 4b38d3e

Browse files
authored
Add initial Activity / Metric support (#183)
1 parent 674cb15 commit 4b38d3e

File tree

13 files changed

+443
-61
lines changed

13 files changed

+443
-61
lines changed

Directory.Packages.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsVersion)" />
3434
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
3535
<PackageVersion Include="Moq" Version="4.20.72" />
36+
<PackageVersion Include="OpenTelemetry" Version="1.11.2" />
37+
<PackageVersion Include="OpenTelemetry.Exporter.InMemory" Version="1.11.2" />
3638
<PackageVersion Include="Serilog.Extensions.Hosting" Version="9.0.0" />
3739
<PackageVersion Include="Serilog.Extensions.Logging" Version="9.0.0" />
3840
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System.Diagnostics;
2+
using System.Diagnostics.Metrics;
3+
4+
namespace ModelContextProtocol;
5+
6+
internal static class Diagnostics
7+
{
8+
internal static ActivitySource ActivitySource { get; } = new("ModelContextProtocol");
9+
10+
/// <summary>
11+
/// Follows boundaries from http.server.request.duration/http.client.request.duration
12+
/// </summary>
13+
internal static InstrumentAdvice<double> ShortSecondsBucketBoundaries { get; } = new()
14+
{
15+
HistogramBucketBoundaries = [0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10],
16+
};
17+
18+
/// <summary>
19+
/// Not based on a standard. Larger bucket sizes for longer lasting operations, e.g. HTTP connection duration.
20+
/// See https://github.com/open-telemetry/semantic-conventions/issues/336
21+
/// </summary>
22+
internal static InstrumentAdvice<double> LongSecondsBucketBoundaries { get; } = new()
23+
{
24+
HistogramBucketBoundaries = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300],
25+
};
26+
27+
internal static Meter Meter { get; } = new("ModelContextProtocol");
28+
29+
}

src/ModelContextProtocol/Protocol/Messages/ProgressToken.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,44 +12,45 @@ namespace ModelContextProtocol.Protocol.Messages;
1212
[JsonConverter(typeof(Converter))]
1313
public readonly struct ProgressToken : IEquatable<ProgressToken>
1414
{
15-
/// <summary>The id, either a string or a boxed long or null.</summary>
16-
private readonly object? _id;
15+
/// <summary>The token, either a string or a boxed long or null.</summary>
16+
private readonly object? _token;
1717

1818
/// <summary>Initializes a new instance of the <see cref="ProgressToken"/> with a specified value.</summary>
1919
/// <param name="value">The required ID value.</param>
2020
public ProgressToken(string value)
2121
{
2222
Throw.IfNull(value);
23-
_id = value;
23+
_token = value;
2424
}
2525

2626
/// <summary>Initializes a new instance of the <see cref="ProgressToken"/> with a specified value.</summary>
2727
/// <param name="value">The required ID value.</param>
2828
public ProgressToken(long value)
2929
{
3030
// Box the long. Progress tokens are almost always strings in practice, so this should be rare.
31-
_id = value;
31+
_token = value;
3232
}
3333

34-
/// <summary>Gets whether the identifier is uninitialized.</summary>
35-
public bool IsDefault => _id is null;
34+
/// <summary>Gets the underlying object for this token.</summary>
35+
/// <remarks>This will either be a <see cref="string"/>, a boxed <see cref="long"/>, or <see langword="null"/>.</remarks>
36+
public object? Token => _token;
3637

3738
/// <inheritdoc />
3839
public override string? ToString() =>
39-
_id is string stringValue ? $"\"{stringValue}\"" :
40-
_id is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) :
40+
_token is string stringValue ? $"{stringValue}" :
41+
_token is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) :
4142
null;
4243

4344
/// <summary>
4445
/// Compares this ProgressToken to another ProgressToken.
4546
/// </summary>
46-
public bool Equals(ProgressToken other) => Equals(_id, other._id);
47+
public bool Equals(ProgressToken other) => Equals(_token, other._token);
4748

4849
/// <inheritdoc />
4950
public override bool Equals(object? obj) => obj is ProgressToken other && Equals(other);
5051

5152
/// <inheritdoc />
52-
public override int GetHashCode() => _id?.GetHashCode() ?? 0;
53+
public override int GetHashCode() => _token?.GetHashCode() ?? 0;
5354

5455
/// <summary>
5556
/// Compares two ProgressTokens for equality.
@@ -83,7 +84,7 @@ public override void Write(Utf8JsonWriter writer, ProgressToken value, JsonSeria
8384
{
8485
Throw.IfNull(writer);
8586

86-
switch (value._id)
87+
switch (value._token)
8788
{
8889
case string str:
8990
writer.WriteStringValue(str);

src/ModelContextProtocol/Protocol/Messages/RequestId.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ public RequestId(long value)
3131
_id = value;
3232
}
3333

34-
/// <summary>Gets whether the identifier is uninitialized.</summary>
35-
public bool IsDefault => _id is null;
34+
/// <summary>Gets the underlying object for this id.</summary>
35+
/// <remarks>This will either be a <see cref="string"/>, a boxed <see cref="long"/>, or <see langword="null"/>.</remarks>
36+
public object? Id => _id;
3637

3738
/// <inheritdoc />
3839
public override string ToString() =>
39-
_id is string stringValue ? $"\"{stringValue}\"" :
40+
_id is string stringValue ? stringValue :
4041
_id is long longValue ? longValue.ToString(CultureInfo.InvariantCulture) :
4142
string.Empty;
4243

src/ModelContextProtocol/Shared/McpJsonRpcEndpoint.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using ModelContextProtocol.Logging;
44
using ModelContextProtocol.Protocol.Messages;
55
using ModelContextProtocol.Protocol.Transport;
6+
using ModelContextProtocol.Server;
67
using ModelContextProtocol.Utils;
78
using System.Diagnostics.CodeAnalysis;
89

@@ -63,7 +64,7 @@ public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancella
6364
protected void StartSession(ITransport sessionTransport)
6465
{
6566
_sessionCts = new CancellationTokenSource();
66-
_session = new McpSession(sessionTransport, EndpointName, _requestHandlers, _notificationHandlers, _logger);
67+
_session = new McpSession(this is IMcpServer, sessionTransport, EndpointName, _requestHandlers, _notificationHandlers, _logger);
6768
MessageProcessingTask = _session.ProcessMessagesAsync(_sessionCts.Token);
6869
}
6970

0 commit comments

Comments
 (0)