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))