Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public enum CalculatorOperation
Add,
Subtract,
Multiply,
Divide
Divide,
}

[JsonSerializable(typeof(CalculatorParameters))]
Expand All @@ -44,14 +44,12 @@ public class CalculatorToolHandler(
ILogger<CalculatorToolHandler> logger
) : ToolHandlerBase<CalculatorParameters>(tool, serverContext, sessionFacade)
{
private static readonly Tool tool =
new()
{
Name = "Calculator",
Description = "Performs basic arithmetic operations",
InputSchema =
CalculatorParametersJsonContext.Default.CalculatorParameters.GetToolSchema()!
};
private static readonly Tool tool = new()
{
Name = "Calculator",
Description = "Performs basic arithmetic operations",
InputSchema = CalculatorParametersJsonContext.Default.CalculatorParameters.GetToolSchema()!,
};

public override JsonTypeInfo JsonTypeInfo =>
CalculatorParametersJsonContext.Default.CalculatorParameters;
Expand All @@ -68,7 +66,7 @@ protected override Task<CallToolResult> HandleAsync(
CalculatorOperation.Multiply => parameters.A * parameters.B,
CalculatorOperation.Divide when parameters.B != 0 => parameters.A / parameters.B,
CalculatorOperation.Divide => throw new DivideByZeroException("Cannot divide by zero"),
_ => throw new ArgumentException($"Unknown operation: {parameters.Operation}")
_ => throw new ArgumentException($"Unknown operation: {parameters.Operation}"),
};

var content = new TextContent { Text = result.ToString() };
Expand Down
26 changes: 16 additions & 10 deletions src/ModelContextProtocol.NET.Demo.Calculator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,17 @@
CalculatorOperation.Add => parameters.A + parameters.B,
CalculatorOperation.Subtract => parameters.A - parameters.B,
CalculatorOperation.Multiply => parameters.A * parameters.B,
CalculatorOperation.Divide when parameters.B != 0
=> parameters.A / parameters.B,
CalculatorOperation.Divide
=> throw new DivideByZeroException("Cannot divide by zero"),
_
=> throw new ArgumentException(
$"Unknown operation: {parameters.Operation}"
),
CalculatorOperation.Divide when parameters.B != 0 => parameters.A
/ parameters.B,
CalculatorOperation.Divide => throw new DivideByZeroException(
"Cannot divide by zero"
),
_ => throw new ArgumentException(
$"Unknown operation: {parameters.Operation}"
),
}
)
).ToString()
).ToString(),
}
)
);
Expand All @@ -58,11 +58,17 @@

try
{
// You can either use Start/Stop pattern:
/*
server.Start();
await Task.Delay(-1); // Wait indefinitely
server.Stop();
*/

// Or use the more convenient RunAsync pattern:
await server.RunAsync(); // Runs until cancelled
}
finally
{
server.Stop();
await server.DisposeAsync();
}
8 changes: 8 additions & 0 deletions src/ModelContextProtocol.NET.Server/IMcpServer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ModelContextProtocol.NET.Core.Models.Protocol.Common;

namespace ModelContextProtocol.NET.Server;
Expand All @@ -23,4 +24,11 @@ public interface IMcpServer : IAsyncDisposable
/// Stops the server.
/// </summary>
void Stop(CancellationToken cancellationToken = default);

/// <summary>
/// Runs the server and blocks until the cancellation token is triggered.
/// This is a convenience method that combines Start(), waiting for cancellation, and Stop().
/// </summary>
/// <param name="cancellationToken">Optional token to cancel server execution</param>
Task RunAsync(CancellationToken cancellationToken = default);
}
21 changes: 21 additions & 0 deletions src/ModelContextProtocol.NET.Server/McpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,27 @@ public void Stop(CancellationToken cancellationToken = default)
logger.LogInformation("MCP server stopped");
}

public async Task RunAsync(CancellationToken cancellationToken = default)
{
try
{
// Start the server
Start(cancellationToken);

// Create a TaskCompletionSource to wait for cancellation
var tcs = new TaskCompletionSource();
using var registration = cancellationToken.Register(() => tcs.SetResult());

// Wait for cancellation
await tcs.Task;
}
finally
{
// Stop the server
Stop(cancellationToken);
}
}

public async ValueTask DisposeAsync()
{
if (!isDisposed)
Expand Down