WIP-Run workflow as mcp tool.

This commit is contained in:
Shyju Krishnankutty
2026-01-21 15:28:24 -08:00
Unverified
parent 588e0bc0b2
commit d3bfbcbf52
4 changed files with 30 additions and 14 deletions
@@ -112,6 +112,11 @@ public static class ServiceCollectionExtensions
services.AddKeyedSingleton(factory.Key, (sp, _) => factory.Value(sp).AsDurableAgentProxy(sp));
}
// Register the agent factories dictionary for backward compatibility.
// This allows consumers to retrieve agents via services.GetService<IReadOnlyDictionary<string, Func<IServiceProvider, AIAgent>>>().
services.TryAddSingleton(
sp => sp.GetRequiredService<DurableAgentsOptions>().GetAgentFactories());
// A custom data converter is needed because the default chat client uses camel case for JSON properties,
// which is not the default behavior for the Durable Task SDK.
services.TryAddSingleton<DataConverter, DefaultDataConverter>();
@@ -154,6 +154,18 @@ internal sealed class BuiltInFunctionExecutor : IFunctionExecutor
return;
}
// Handle workflow MCP tool trigger
if (context.FunctionDefinition.EntryPoint == BuiltInFunctions.RunWorkflowMcpToolFunctionEntryPoint)
{
if (mcpToolInvocationContext is null)
{
throw new InvalidOperationException($"MCP tool invocation context binding is missing for the invocation {context.InvocationId}.");
}
context.GetInvocationResult().Value = await BuiltInFunctions.RunWorkflowMcpToolAsync(mcpToolInvocationContext, durableTaskClient, context);
return;
}
throw new InvalidOperationException($"Unsupported function entry point '{context.FunctionDefinition.EntryPoint}' for invocation {context.InvocationId}.");
}
}
@@ -72,6 +72,7 @@ internal static class CoreAgentConfigurationExtensions
{
return string.Equals(entryPoint, BuiltInFunctions.RunAgentHttpFunctionEntryPoint, StringComparison.Ordinal)
|| string.Equals(entryPoint, BuiltInFunctions.RunAgentMcpToolFunctionEntryPoint, StringComparison.Ordinal)
|| string.Equals(entryPoint, BuiltInFunctions.RunWorkflowMcpToolFunctionEntryPoint, StringComparison.Ordinal)
|| string.Equals(entryPoint, BuiltInFunctions.RunWorkflowOrechstrtationHttpFunctionEntryPoint, StringComparison.Ordinal)
|| string.Equals(entryPoint, BuiltInFunctions.InvokeWorkflowActivityFunctionEntryPoint, StringComparison.Ordinal)
|| string.Equals(entryPoint, BuiltInFunctions.RunAgentEntityFunctionEntryPoint, StringComparison.Ordinal);
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Diagnostics.CodeAnalysis;
using Microsoft.Agents.AI.DurableTask;
using Microsoft.Azure.Functions.Worker.Core.FunctionMetadata;
using Microsoft.Extensions.Logging.Abstractions;
@@ -21,10 +22,8 @@ public sealed class DurableAgentFunctionMetadataTransformerTests
int expectedMetadataCount)
{
// Arrange
Dictionary<string, Func<IServiceProvider, AIAgent>> agents = new()
{
{ "testAgent", _ => new TestAgent("testAgent", "Test agent description") }
};
DurableAgentsOptions durableAgentsOptions = new();
durableAgentsOptions.AddAIAgentFactory("testAgent", _ => new TestAgent("testAgent", "Test agent description"));
FunctionsAgentOptions options = new();
@@ -39,7 +38,7 @@ public sealed class DurableAgentFunctionMetadataTransformerTests
List<IFunctionMetadata> metadataList = BuildFunctionMetadataList(initialMetadataEntryCount);
DurableAgentFunctionMetadataTransformer transformer = new(
agents,
durableAgentsOptions,
NullLogger<DurableAgentFunctionMetadataTransformer>.Instance,
new FakeServiceProvider(),
agentOptionsProvider);
@@ -74,12 +73,11 @@ public sealed class DurableAgentFunctionMetadataTransformerTests
public void Transform_AddsTriggers_ForMultipleAgents()
{
// Arrange
Dictionary<string, Func<IServiceProvider, AIAgent>> agents = new()
{
{ "agentA", _ => new TestAgent("testAgentA", "Test agent description") },
{ "agentB", _ => new TestAgent("testAgentB", "Test agent description") },
{ "agentC", _ => new TestAgent("testAgentC", "Test agent description") }
};
string[] agentNames = ["agentA", "agentB", "agentC"];
DurableAgentsOptions durableAgentsOptions = new();
durableAgentsOptions.AddAIAgentFactory("agentA", _ => new TestAgent("testAgentA", "Test agent description"));
durableAgentsOptions.AddAIAgentFactory("agentB", _ => new TestAgent("testAgentB", "Test agent description"));
durableAgentsOptions.AddAIAgentFactory("agentC", _ => new TestAgent("testAgentC", "Test agent description"));
// Helper to create options with configurable triggers
static FunctionsAgentOptions CreateFunctionsAgentOptions(bool httpEnabled, bool mcpEnabled)
@@ -103,7 +101,7 @@ public sealed class DurableAgentFunctionMetadataTransformerTests
IFunctionsAgentOptionsProvider agentOptionsProvider = new FakeOptionsProvider(functionsAgentOptions);
DurableAgentFunctionMetadataTransformer transformer = new(
agents,
durableAgentsOptions,
NullLogger<DurableAgentFunctionMetadataTransformer>.Instance,
new FakeServiceProvider(),
agentOptionsProvider);
@@ -115,9 +113,9 @@ public sealed class DurableAgentFunctionMetadataTransformerTests
transformer.Transform(metadataList);
// Assert
Assert.Equal(InitialMetadataEntryCount + (agents.Count * 2) + 2, metadataList.Count);
Assert.Equal(InitialMetadataEntryCount + (agentNames.Length * 2) + 2, metadataList.Count);
foreach (string agentName in agents.Keys)
foreach (string agentName in agentNames)
{
// The agent's entity trigger name is prefixed with "dafx-"
DefaultFunctionMetadata entityMeta =