Use DescriptionAttribute and HasDefaultValue in server builder extensions (#46)
This commit is contained in:
parent
e187ebacc4
commit
33d2b0d762
6 changed files with 27 additions and 61 deletions
|
|
@ -1,12 +1,13 @@
|
||||||
using McpDotNet.Server;
|
using McpDotNet.Server;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace TestServerWithHosting.Tools;
|
namespace TestServerWithHosting.Tools;
|
||||||
|
|
||||||
[McpToolType]
|
[McpToolType]
|
||||||
public static class EchoTool
|
public static class EchoTool
|
||||||
{
|
{
|
||||||
[McpTool(description: "Echoes the input back to the client.")]
|
[McpTool, Description("Echoes the input back to the client.")]
|
||||||
public static string Echo([McpParameter(true)] string message)
|
public static string Echo(string message)
|
||||||
{
|
{
|
||||||
return "hello " + message;
|
return "hello " + message;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using McpDotNet.Protocol.Types;
|
using McpDotNet.Protocol.Types;
|
||||||
using McpDotNet.Server;
|
using McpDotNet.Server;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace TestServerWithHosting.Tools;
|
namespace TestServerWithHosting.Tools;
|
||||||
|
|
||||||
|
|
@ -16,10 +17,10 @@ public class SampleLlmTool
|
||||||
_server = server ?? throw new ArgumentNullException(nameof(server));
|
_server = server ?? throw new ArgumentNullException(nameof(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpTool(name: "sampleLLM", description: "Samples from an LLM using MCP's sampling feature")]
|
[McpTool("sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")]
|
||||||
public async Task<string> SampleLLM(
|
public async Task<string> SampleLLM(
|
||||||
[McpParameter(true, description: "The prompt to send to the LLM")] string prompt,
|
[Description("The prompt to send to the LLM")] string prompt,
|
||||||
[McpParameter(true, description: "Maximum number of tokens to generate")] int maxTokens,
|
[Description("Maximum number of tokens to generate")] int maxTokens,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var samplingParams = CreateRequestSamplingParams(prompt ?? string.Empty, "sampleLLM", maxTokens);
|
var samplingParams = CreateRequestSamplingParams(prompt ?? string.Empty, "sampleLLM", maxTokens);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Globalization;
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using McpDotNet.Configuration;
|
using McpDotNet.Configuration;
|
||||||
|
|
@ -117,7 +118,7 @@ public static partial class McpServerBuilderExtensions
|
||||||
return WithTools(builder, toolTypes.ToArray());
|
return WithTools(builder, toolTypes.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Tool CreateTool(MethodInfo method, McpToolAttribute attribute)
|
private static Tool CreateTool(MethodInfo method, McpToolAttribute mcpAttribute)
|
||||||
{
|
{
|
||||||
Dictionary<string, JsonSchemaProperty> properties = [];
|
Dictionary<string, JsonSchemaProperty> properties = [];
|
||||||
List<string>? requiredProperties = null;
|
List<string>? requiredProperties = null;
|
||||||
|
|
@ -127,15 +128,15 @@ public static partial class McpServerBuilderExtensions
|
||||||
if (parameter.ParameterType == typeof(CancellationToken))
|
if (parameter.ParameterType == typeof(CancellationToken))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var parameterAttribute = parameter.GetCustomAttribute<McpParameterAttribute>();
|
var parameterDescriptionAttr = parameter.GetCustomAttribute<DescriptionAttribute>();
|
||||||
|
|
||||||
properties.Add(parameter.Name ?? "NoName", new JsonSchemaProperty()
|
properties.Add(parameter.Name ?? "NoName", new JsonSchemaProperty()
|
||||||
{
|
{
|
||||||
Type = GetParameterType(parameter.ParameterType),
|
Type = GetParameterType(parameter.ParameterType),
|
||||||
Description = parameterAttribute?.Description
|
Description = parameterDescriptionAttr?.Description,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (parameterAttribute?.Required == true)
|
if (!parameter.HasDefaultValue)
|
||||||
{
|
{
|
||||||
requiredProperties ??= [];
|
requiredProperties ??= [];
|
||||||
requiredProperties.Add(parameter.Name ?? "NoName");
|
requiredProperties.Add(parameter.Name ?? "NoName");
|
||||||
|
|
@ -144,8 +145,8 @@ public static partial class McpServerBuilderExtensions
|
||||||
|
|
||||||
return new Tool()
|
return new Tool()
|
||||||
{
|
{
|
||||||
Name = attribute.Name ?? method.Name,
|
Name = mcpAttribute.Name ?? method.Name,
|
||||||
Description = attribute.Description,
|
Description = method.GetCustomAttribute<DescriptionAttribute>()?.Description,
|
||||||
InputSchema = new JsonSchema()
|
InputSchema = new JsonSchema()
|
||||||
{
|
{
|
||||||
Type = "object",
|
Type = "object",
|
||||||
|
|
@ -229,12 +230,10 @@ public static partial class McpServerBuilderExtensions
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var parameterAttribute = parameter.GetCustomAttribute<McpParameterAttribute>();
|
if (!parameter.HasDefaultValue)
|
||||||
|
|
||||||
if (parameterAttribute?.Required == true)
|
|
||||||
throw new McpServerException($"Missing required argument '{parameter.Name}'.");
|
throw new McpServerException($"Missing required argument '{parameter.Name}'.");
|
||||||
|
|
||||||
parameters.Add(parameter.HasDefaultValue ? parameter.DefaultValue : null);
|
parameters.Add(parameter.DefaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
namespace McpDotNet.Server;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute to mark a method parameter
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Parameter)]
|
|
||||||
public sealed class McpParameterAttribute : Attribute
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Defines if the parameter is required.
|
|
||||||
/// </summary>
|
|
||||||
public bool Required { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A description of the parameter.
|
|
||||||
/// </summary>
|
|
||||||
public string? Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute to mark a method as an MCP tool.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="required">True if the parameter is mandatory.</param>
|
|
||||||
/// <param name="description">A description of the tool.</param>
|
|
||||||
public McpParameterAttribute(bool required = false, string? description = null)
|
|
||||||
{
|
|
||||||
Required = required;
|
|
||||||
Description = description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,22 +6,15 @@
|
||||||
[AttributeUsage(AttributeTargets.Method)]
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
public sealed class McpToolAttribute : Attribute
|
public sealed class McpToolAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// The name of the tool. If not provided, the class name will be used.
|
/// <summary>Gets the name of the tool.</summary>
|
||||||
|
/// <remarks>If not provided, the method name will be used.</remarks>
|
||||||
public string? Name { get; }
|
public string? Name { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A description of the tool.
|
|
||||||
/// </summary>
|
|
||||||
public string? Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attribute to mark a method as an MCP tool.
|
/// Attribute to mark a method as an MCP tool.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the tool. If not provided, the class name will be used.</param>
|
/// <param name="name">The name of the tool. If not provided, the class name will be used.</param>
|
||||||
/// <param name="description">A description of the tool.</param>
|
public McpToolAttribute(string? name = null)
|
||||||
public McpToolAttribute(string? name = null, string? description = null)
|
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using McpDotNet.Server;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace McpDotNet.Tests;
|
namespace McpDotNet.Tests;
|
||||||
|
|
||||||
|
|
@ -131,14 +132,14 @@ public class McpServerBuilderExtensionsToolsTests
|
||||||
|
|
||||||
private static class EchoTool
|
private static class EchoTool
|
||||||
{
|
{
|
||||||
[McpTool(description: "Echoes the input back to the client.")]
|
[McpTool, Description("Echoes the input back to the client.")]
|
||||||
public static string Echo([McpParameter(true, description: "the echoes message")] string message)
|
public static string Echo([Description("the echoes message")] string message)
|
||||||
{
|
{
|
||||||
return "hello " + message;
|
return "hello " + message;
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpTool(name: "double_echo", description: "Echoes the input back to the client.")]
|
[McpTool("double_echo"), Description("Echoes the input back to the client.")]
|
||||||
public static string Echo2([McpParameter(true)] string message)
|
public static string Echo2(string message)
|
||||||
{
|
{
|
||||||
return "hello hello" + message;
|
return "hello hello" + message;
|
||||||
}
|
}
|
||||||
|
|
@ -154,8 +155,8 @@ public class McpServerBuilderExtensionsToolsTests
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[McpTool(description: "Echoes the input back to the client.")]
|
[McpTool, Description("Echoes the input back to the client.")]
|
||||||
public Task<string> Echo([McpParameter(true)] string message)
|
public Task<string> Echo(string message)
|
||||||
{
|
{
|
||||||
return Task.FromResult("hello " + message);
|
return Task.FromResult("hello " + message);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue