diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/IMcpHttpFunctionRouter.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/IMcpHttpFunctionRouter.cs new file mode 100644 index 00000000..2461544b --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/IMcpHttpFunctionRouter.cs @@ -0,0 +1,21 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Routing.Executor; + +namespace BotSharp.Abstraction.Functions; + +/// +/// W4C extension point: resolves an for MCP tools served by +/// dynamically-configured Streamable HTTP servers (user custom MCP servers and the built-in +/// OpenPencil design server). BotSharp's stock McpClientManager only reaches SSE/Stdio +/// servers registered at startup, so hosts that talk to streamable-HTTP servers register an +/// implementation of this and consults it +/// before its own executors. Return null to let the stock executors handle the function. +/// +public interface IMcpHttpFunctionRouter +{ + /// + /// Returns an executor for when it belongs to a routed MCP server + /// the host can reach over streamable HTTP, otherwise null. + /// + IFunctionExecutor? Create(Agent agent, string functionName); +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs b/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs index 8a4a5486..93a93d6b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs @@ -13,6 +13,21 @@ internal class FunctionExecutorFactory return new FunctionCallbackExecutor(functionCall); } + // W4C: route MCP tools served by dynamically-configured Streamable HTTP servers (custom MCP + // servers and the OpenPencil design server) that the stock McpClientManager (SSE/Stdio only) + // cannot reach. The host's router resolves the owning server itself, so it also covers + // "all tools" (empty function list) entries. Returns null when the function is not an MCP + // tool, letting the stock executors below handle it. + var w4c = services.GetService(); + if (w4c != null) + { + var w4cExecutor = w4c.Create(agent, functionName); + if (w4cExecutor != null) + { + return w4cExecutor; + } + } + var functions = (agent?.Functions ?? []).Concat(agent?.SecondaryFunctions ?? []); var funcDef = functions.FirstOrDefault(x => x.Name == functionName); if (!string.IsNullOrWhiteSpace(funcDef?.Output))