Add [McpServerTool] support for instance methods (#100)
* Add [McpServerTool] support for instance methods By popular demand, enables [McpServerTool] on instance methods. The instance is constructed per invocation, using ActivatorUtilities.CreateInstance when possible so that constructor arguments are satisfied from DI. * Add disposal tests
This commit is contained in:
parent
6fa1443a6c
commit
b61cdef994
1 changed files with 391 additions and 38 deletions
|
|
@ -14,32 +14,51 @@ public static partial class McpServerBuilderExtensions
|
|||
{
|
||||
private const string RequiresUnreferencedCodeMessage = "This method requires dynamic lookup of method metadata and might not work in Native AOT.";
|
||||
|
||||
/// <summary>
|
||||
/// Adds a tool to the server.
|
||||
/// </summary>
|
||||
/// <summary>Adds <see cref="McpServerTool"/> instances to the service collection backing <paramref name="builder"/>.</summary>
|
||||
/// <typeparam name="TTool">The tool type.</typeparam>
|
||||
/// <param name="builder">The builder instance.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
|
||||
public static IMcpServerBuilder WithTools<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] TTool>(
|
||||
/// <remarks>
|
||||
/// This method discovers all instance and static methods (public and non-public) on the specified <typeparamref name="TTool"/>
|
||||
/// type, where the methods are attributed as <see cref="McpServerToolAttribute"/>, and adds an <see cref="McpServerTool"/>
|
||||
/// instance for each. For instance methods, an instance will be constructed for each invocation of the tool.
|
||||
/// </remarks>
|
||||
public static IMcpServerBuilder WithTools<[DynamicallyAccessedMembers(
|
||||
DynamicallyAccessedMemberTypes.PublicMethods |
|
||||
DynamicallyAccessedMemberTypes.NonPublicMethods |
|
||||
DynamicallyAccessedMemberTypes.PublicConstructors)] TTool>(
|
||||
this IMcpServerBuilder builder)
|
||||
{
|
||||
Throw.IfNull(builder);
|
||||
|
||||
foreach (var toolMethod in GetToolMethods(typeof(TTool)))
|
||||
foreach (var toolMethod in typeof(TTool).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
|
||||
{
|
||||
builder.Services.AddSingleton(services => McpServerTool.Create(toolMethod, services: services));
|
||||
if (toolMethod.GetCustomAttribute<McpServerToolAttribute>() is not null)
|
||||
{
|
||||
if (toolMethod.IsStatic)
|
||||
{
|
||||
builder.Services.AddSingleton(services => McpServerTool.Create(toolMethod, services: services));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddSingleton(services => McpServerTool.Create(toolMethod, typeof(TTool), services: services));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds tools to the server.
|
||||
/// </summary>
|
||||
/// <summary>Adds <see cref="McpServerTool"/> instances to the service collection backing <paramref name="builder"/>.</summary>
|
||||
/// <param name="builder">The builder instance.</param>
|
||||
/// <param name="toolTypes">Types with marked methods to add as tools to the server.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="toolTypes"/> is <see langword="null"/>.</exception>
|
||||
/// <remarks>
|
||||
/// This method discovers all instance and static methods (public and non-public) on the specified <paramref name="toolTypes"/>
|
||||
/// types, where the methods are attributed as <see cref="McpServerToolAttribute"/>, and adds an <see cref="McpServerTool"/>
|
||||
/// instance for each. For instance methods, an instance will be constructed for each invocation of the tool.
|
||||
/// </remarks>
|
||||
[RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)]
|
||||
public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params IEnumerable<Type> toolTypes)
|
||||
{
|
||||
|
|
@ -50,13 +69,23 @@ public static partial class McpServerBuilderExtensions
|
|||
{
|
||||
if (toolType is not null)
|
||||
{
|
||||
foreach (var toolMethod in GetToolMethods(toolType))
|
||||
foreach (var method in toolType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
|
||||
{
|
||||
builder.Services.AddSingleton(services => McpServerTool.Create(toolMethod, services: services));
|
||||
if (method.GetCustomAttribute<McpServerToolAttribute>() is not null)
|
||||
{
|
||||
if (method.IsStatic)
|
||||
{
|
||||
builder.Services.AddSingleton(services => McpServerTool.Create(method, services: services));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddSingleton(services => McpServerTool.Create(method, toolType, services: services));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
|
@ -78,10 +107,4 @@ public static partial class McpServerBuilderExtensions
|
|||
where t.GetCustomAttribute<McpServerToolTypeAttribute>() is not null
|
||||
select t);
|
||||
}
|
||||
|
||||
private static IEnumerable<MethodInfo> GetToolMethods(
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type toolType) =>
|
||||
from method in toolType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)
|
||||
where method.GetCustomAttribute<McpServerToolAttribute>() is not null
|
||||
select method;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue