Open
Description
Is your feature request related to a problem? Please describe.
I would like to map a collection of dynamic tools to a single class handler (see example below).
Describe the solution you'd like
I would like a single handler to be mapped to multiple tools. These tools will be dynamically mapped and available at runtime and may be on other servers. The core of this would be a base class DynamicTools
builder.Services.AddMcpServer()
.WithStdioServerTransport()
.WithTools<EchoTools>() // support with static tools side by side
.WithTools<MyDynamicTools>(
[
new Tool { Name = "echo_a", Description = "Echoes the input back to the user.", InputSchema = "..." },
new Tool { Name = "echo_b", Description = "Echoes the input back to the user.", InputSchema = "..." },
]);
public class MyDynamicTools : DynamicTools
{
private readonly HttpClient _client;
public MyDynamicTools(HttpClient client) // also other scoped services should be able to be injected here
{
_client = client;
}
public override async Task<IMcpActionResult> Invoke(CallToolRequestParams requestParams)
{
// just an example other routing logic may apply here
var result = await _client.PostAsJsonAsync($"/service/{requestParams.Name}", requestParams.Arguments);
// could also return error
return Ok(result);
}
}
The rest would be optional, only the Invoke(CallToolRequestParams params)
is important.
Maybe make it similar to MVC.
public interface IMcpActionResult
{
Task Invoke(ITransport transport, CancellationToken cancellationToken);
}
public class OkObjectResult : IMcpActionResult
{
private readonly object _value;
public OkObjectResult(object value)
{
_value = value;
}
public Task Invoke(ITransport transport, CancellationToken cancellationToken)
{
return transport.SendMessageAsync(new JsonRpcResponse { Result = _value}, cancellationToken);
}
}
public abstract class DynamicTools
{
public abstract async Task<IMcpActionResult> Invoke(CallToolRequestParams requestParams);
protected IMcpActionResult Ok(object value)
{
return new OkObjectResult(value);
}
}
Describe alternatives you've considered
Create a custom a CallToolHandler
Additional context
Add any other context or screenshots about the feature request here.