diff --git a/BotSharp.sln b/BotSharp.sln
index b176747f..c6c75391 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -127,7 +127,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Rules", "src\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.DeepSeekAI", "src\Plugins\BotSharp.Plugin.DeepSeekAI\BotSharp.Plugin.DeepSeekAI.csproj", "{AF329442-B48E-4B48-A18A-1C869D1BA6F5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Realtime", "src\Infrastructure\BotSharp.Core.Realtime\BotSharp.Core.Realtime.csproj", "{7ACD8C95-C66B-436A-80E7-541A57D8C3F4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.MCP", "src\Infrastructure\BotSharp.MCP\BotSharp.MCP.csproj", "{8ED8EEF4-06DD-45F5-AA91-BD2395E901B5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.PizzaBot.MCPServer", "tests\BotSharp.PizzaBot.MCPServer\BotSharp.PizzaBot.MCPServer.csproj", "{AD91B4ED-0623-4710-913E-6D7C893E76EF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -521,14 +523,6 @@ Global
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|Any CPU.Build.0 = Release|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x64.ActiveCfg = Release|Any CPU
{AF329442-B48E-4B48-A18A-1C869D1BA6F5}.Release|x64.Build.0 = Release|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Debug|x64.Build.0 = Debug|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Release|Any CPU.Build.0 = Release|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Release|x64.ActiveCfg = Release|Any CPU
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -590,7 +584,6 @@ Global
{F812BAAE-5A7D-4DF7-8E71-70696B51C61F} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{AFD64412-4D6A-452E-82A2-79E5D8842E29} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{AF329442-B48E-4B48-A18A-1C869D1BA6F5} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
- {7ACD8C95-C66B-436A-80E7-541A57D8C3F4} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs
index bec14b85..1103f2f5 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs
@@ -57,5 +57,11 @@ public abstract class AgentHookBase : IAgentHook
public virtual void OnAgentUtilityLoaded(Agent agent)
{
+
+ }
+
+ public virtual void OnAgentMCPToolLoaded(Agent agent)
+ {
+
}
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
index 0c39a960..413f9eb8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs
@@ -19,6 +19,7 @@ public enum AgentField
Sample,
LlmConfig,
Utility,
+ Acp,
KnowledgeBase,
Rule,
MaxMessageCount
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
index a3f53fb6..624616d7 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
@@ -27,6 +27,8 @@ public interface IAgentHook
void OnAgentUtilityLoaded(Agent agent);
+ void OnAgentMCPToolLoaded(Agent agent);
+
///
/// Triggered when agent is loaded completely.
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
index 085b0f9d..fc28e571 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs
@@ -95,15 +95,20 @@ public class Agent
public List Labels { get; set; } = new();
///
- /// Merge utilities from entry agent
+ /// Merge Utility from entry agent
///
public bool MergeUtility { get; set; }
///
- /// Agent utilities
+ /// Agent Utility
///
public List Utilities { get; set; } = new();
+ ///
+ /// Agent MCP Tools
+ ///
+ public List McpTools { get; set; } = new();
+
///
/// Agent rules
///
@@ -157,6 +162,7 @@ public class Agent
Responses = agent.Responses,
Samples = agent.Samples,
Utilities = agent.Utilities,
+ McpTools = agent.McpTools,
Knowledges = agent.Knowledges,
IsPublic = agent.IsPublic,
Disabled = agent.Disabled,
@@ -298,4 +304,10 @@ public class Agent
LlmConfig = llmConfig;
return this;
}
+
+ public Agent SetMcps(List mcps)
+ {
+ McpTools = mcps ?? [];
+ return this;
+ }
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs
new file mode 100644
index 00000000..a555a7e5
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/MCPTool.cs
@@ -0,0 +1,37 @@
+namespace BotSharp.Abstraction.Agents.Models;
+
+public class MCPTool
+{
+ public string ServerId { get; set; }
+
+ public bool Disabled { get; set; }
+
+ public IEnumerable Functions { get; set; } = [];
+
+ public MCPTool()
+ {
+
+ }
+
+ public MCPTool(
+ IEnumerable? functions = null)
+ {
+ Functions = functions ?? [];
+ }
+
+ public override string ToString()
+ {
+ return ServerId;
+ }
+}
+
+
+public class MCPFunction
+{
+ public string Name { get; set; }
+
+ public MCPFunction(string name)
+ {
+ this.Name = name;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
index 1101f160..5ab0ea03 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs
@@ -38,6 +38,7 @@ public class BasicAgentHook : AgentHookBase
agent.SecondaryInstructions.Add(prompt);
}
}
+
private (IEnumerable, IEnumerable) GetUtilityContent(Agent agent)
{
@@ -81,5 +82,5 @@ public class BasicAgentHook : AgentHookBase
.Distinct().ToList();
return (functionNames, templateNames);
- }
+ }
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
index 15ba26a1..c8f97206 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
@@ -71,6 +71,11 @@ public partial class AgentService
{
hook.OnAgentUtilityLoaded(agent);
}
+
+ if(agent.McpTools != null && agent.McpTools.Count >0)
+ {
+ hook.OnAgentMCPToolLoaded(agent);
+ }
hook.OnAgentLoaded(agent);
}
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
index a9cc58d9..7e9da19c 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs
@@ -40,6 +40,7 @@ public partial class AgentService
record.Responses = agent.Responses ?? [];
record.Samples = agent.Samples ?? [];
record.Utilities = agent.Utilities ?? [];
+ record.McpTools = agent.McpTools ?? [];
record.KnowledgeBases = agent.KnowledgeBases ?? [];
record.Rules = agent.Rules ?? [];
if (agent.LlmConfig != null && !agent.LlmConfig.IsInherit)
@@ -106,6 +107,7 @@ public partial class AgentService
.SetResponses(foundAgent.Responses)
.SetSamples(foundAgent.Samples)
.SetUtilities(foundAgent.Utilities)
+ .SetMcps(foundAgent.McpTools)
.SetKnowledgeBases(foundAgent.KnowledgeBases)
.SetRules(foundAgent.Rules)
.SetLlmConfig(foundAgent.LlmConfig);
diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
index d7a6d121..ae401508 100644
--- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
+++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs
@@ -60,6 +60,9 @@ namespace BotSharp.Core.Repository
case AgentField.Utility:
UpdateAgentUtilities(agent.Id, agent.MergeUtility, agent.Utilities);
break;
+ case AgentField.Acp:
+ UpdateAgentMcpTools(agent.Id, agent.McpTools);
+ break;
case AgentField.KnowledgeBase:
UpdateAgentKnowledgeBases(agent.Id, agent.KnowledgeBases);
break;
@@ -191,6 +194,20 @@ namespace BotSharp.Core.Repository
File.WriteAllText(agentFile, json);
}
+ private void UpdateAgentMcpTools(string agentId, List mcptools)
+ {
+ if (mcptools == null) return;
+
+ var (agent, agentFile) = GetAgentFromFile(agentId);
+ if (agent == null) return;
+
+
+ agent.McpTools = mcptools;
+ agent.UpdatedDateTime = DateTime.UtcNow;
+ var json = JsonSerializer.Serialize(agent, _options);
+ File.WriteAllText(agentFile, json);
+ }
+
private void UpdateAgentKnowledgeBases(string agentId, List knowledgeBases)
{
if (knowledgeBases == null) return;
@@ -360,6 +377,7 @@ namespace BotSharp.Core.Repository
agent.Profiles = inputAgent.Profiles;
agent.Labels = inputAgent.Labels;
agent.Utilities = inputAgent.Utilities;
+ agent.McpTools = inputAgent.McpTools;
agent.KnowledgeBases = inputAgent.KnowledgeBases;
agent.RoutingRules = inputAgent.RoutingRules;
agent.Rules = inputAgent.Rules;
diff --git a/src/Infrastructure/BotSharp.MCP/AIFunctionUtilities.cs b/src/Infrastructure/BotSharp.MCP/AIFunctionUtilities.cs
new file mode 100644
index 00000000..e86cbf92
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/AIFunctionUtilities.cs
@@ -0,0 +1,37 @@
+using BotSharp.Abstraction.Functions.Models;
+using McpDotNet.Protocol.Types;
+using System;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace BotSharp.Core.MCP;
+
+internal static class AIFunctionUtilities
+{
+ public static FunctionDef MapToFunctionDef(Tool tool)
+ {
+ if (tool == null)
+ {
+ throw new ArgumentNullException(nameof(tool));
+ }
+
+ var properties = tool.InputSchema?.Properties;
+ var required = tool.InputSchema?.Required ?? new List();
+
+ FunctionDef funDef = new FunctionDef
+ {
+ Name = tool.Name,
+ Description = tool.Description?? string.Empty,
+ Type = "function",
+ Parameters = new FunctionParametersDef
+ {
+ Type = "object",
+ Properties = properties != null ? JsonSerializer.SerializeToDocument(properties) : JsonDocument.Parse("{}"),
+ Required = required
+ }
+ };
+
+ return funDef;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.MCP/BotSharp.MCP.csproj b/src/Infrastructure/BotSharp.MCP/BotSharp.MCP.csproj
new file mode 100644
index 00000000..e9727f7f
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/BotSharp.MCP.csproj
@@ -0,0 +1,18 @@
+
+
+
+ $(TargetFramework)
+ $(LangVersion)
+ $(BotSharpVersion)
+ $(GeneratePackageOnBuild)
+ $(SolutionDir)packages
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Infrastructure/BotSharp.MCP/Functions/McpToolFunction.cs b/src/Infrastructure/BotSharp.MCP/Functions/McpToolFunction.cs
new file mode 100644
index 00000000..97ec724f
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/Functions/McpToolFunction.cs
@@ -0,0 +1,107 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Conversations.Models;
+using BotSharp.Abstraction.Functions;
+using McpDotNet.Client;
+using McpDotNet.Protocol.Types;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace BotSharp.Core.Mcp.Functions;
+
+public class McpToolFunction : IFunctionCallback
+{
+ private readonly Tool _tool;
+ private readonly MCPClientManager _clientManager;
+ private readonly IServiceProvider _serviceProvider;
+
+ public McpToolFunction(IServiceProvider provider, Tool tool, MCPClientManager client)
+ {
+ _serviceProvider = provider ?? throw new ArgumentNullException(nameof(provider));
+ _tool = tool ?? throw new ArgumentNullException(nameof(tool));
+ _clientManager = client ?? throw new ArgumentNullException(nameof(client));
+ }
+
+ public string Name => _tool.Name;
+
+ public async Task Execute(RoleDialogModel message)
+ {
+ // Convert arguments to dictionary format expected by mcpdotnet
+ Dictionary argDict = JsonToDictionary(message.FunctionArgs);
+ var currentAgentId = message.CurrentAgentId;
+ var agentService = _serviceProvider.GetRequiredService();
+ var agent = await agentService.LoadAgent(currentAgentId);
+ var serverId = agent.McpTools.Where(t => t.Functions.Any(f => f.Name == Name)).FirstOrDefault().ServerId;
+
+ var client = await _clientManager.Factory.GetClientAsync(serverId);
+ // Call the tool through mcpdotnet
+ var result = await client.CallToolAsync(
+ _tool.Name,
+ argDict.Count == 0 ? new() : argDict
+ );
+
+ // Extract the text content from the result
+ var json = string.Join("\n", result.Content
+ .Where(c => c.Type == "text")
+ .Select(c => c.Text));
+ message.Content = json;
+ message.Data = JsonSerializer.Deserialize(json,typeof(object));
+ return true;
+ }
+
+ private static Dictionary JsonToDictionary(string? json)
+ {
+ if (string.IsNullOrEmpty(json))
+ return [];
+
+ using JsonDocument doc = JsonDocument.Parse(json);
+ JsonElement root = doc.RootElement;
+ return JsonElementToDictionary(root);
+ }
+
+ private static Dictionary JsonElementToDictionary(JsonElement element)
+ {
+ Dictionary dictionary = [];
+
+ if (element.ValueKind == JsonValueKind.Object)
+ {
+ foreach (JsonProperty property in element.EnumerateObject())
+ {
+ dictionary[property.Name] = JsonElementToValue(property.Value);
+ }
+ }
+
+ return dictionary;
+ }
+
+ private static object? JsonElementToValue(JsonElement element) => element.ValueKind switch
+ {
+ JsonValueKind.Object => JsonElementToDictionary(element),
+ JsonValueKind.Array => element.EnumerateArray().Select(JsonElementToValue).ToList(),
+ JsonValueKind.String => element.GetString(),
+ JsonValueKind.Number when element.TryGetInt32(out int intValue) => intValue,
+ JsonValueKind.Number when element.TryGetInt64(out long longValue) => longValue,
+ JsonValueKind.Number when element.TryGetDouble(out double doubleValue) => doubleValue,
+ JsonValueKind.Number when element.TryGetDecimal(out decimal decimalValue) => decimalValue,
+ JsonValueKind.Number when element.TryGetByte(out byte byteValue) => byteValue,
+ JsonValueKind.Number when element.TryGetSByte(out sbyte sbyteValue) => sbyteValue,
+ JsonValueKind.Number when element.TryGetUInt16(out ushort uint16Value) => uint16Value,
+ JsonValueKind.Number when element.TryGetUInt32(out uint uint32Value) => uint32Value,
+ JsonValueKind.Number when element.TryGetUInt64(out ulong uint64Value) => uint64Value,
+ JsonValueKind.Number when element.TryGetDateTime(out DateTime dateTimeValue) => dateTimeValue,
+ JsonValueKind.Number when element.TryGetDateTimeOffset(out DateTimeOffset dateTimeOffsetValue) => dateTimeOffsetValue,
+ JsonValueKind.Number when element.TryGetGuid(out Guid guidValue) => guidValue,
+ JsonValueKind.Number => element.GetRawText(),
+ JsonValueKind.True => true,
+ JsonValueKind.False => false,
+ JsonValueKind.Null => null,
+ JsonValueKind.Undefined => string.Empty, // JsonElement is undefined (there is no value).
+ _ => throw new ArgumentOutOfRangeException(nameof(element.ValueKind), element.ValueKind, "Unexpected JsonValueKind encountered.")
+ };
+
+}
diff --git a/src/Infrastructure/BotSharp.MCP/Hooks/MCPToolAgentHook.cs b/src/Infrastructure/BotSharp.MCP/Hooks/MCPToolAgentHook.cs
new file mode 100644
index 00000000..32b10d0a
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/Hooks/MCPToolAgentHook.cs
@@ -0,0 +1,69 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Agents.Enums;
+using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Agents.Settings;
+using BotSharp.Abstraction.Conversations;
+using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Core.Mcp;
+using BotSharp.Core.MCP;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace BotSharp.MCP.Hooks;
+
+public class MCPToolAgentHook : AgentHookBase
+{
+ public override string SelfId => string.Empty;
+
+ public MCPToolAgentHook(IServiceProvider services, AgentSettings settings)
+ : base(services, settings)
+ {
+ }
+
+ public override void OnAgentMCPToolLoaded(Agent agent)
+ {
+ if (agent.Type == AgentType.Routing)
+ return;
+ var conv = _services.GetRequiredService();
+ var isConvMode = conv.IsConversationMode();
+ if (!isConvMode) return;
+
+ agent.SecondaryFunctions ??= [];
+
+ var functions = GetMCPContent(agent).Result;
+
+ foreach (var fn in functions)
+ {
+ if (!agent.SecondaryFunctions.Any(x => x.Name.Equals(fn.Name, StringComparison.OrdinalIgnoreCase)))
+ {
+ agent.SecondaryFunctions.Add(fn);
+ }
+ }
+ }
+
+ private async Task> GetMCPContent(Agent agent)
+ {
+ List functionDefs = new List();
+ var mcpClientManager = _services.GetRequiredService();
+ var mcps = agent.McpTools;
+ foreach (var item in mcps)
+ {
+ var mcpClient = await mcpClientManager.Factory.GetClientAsync(item.ServerId);
+ if (mcpClient != null)
+ {
+ var tools = await mcpClient.ListToolsAsync();
+ var funcnames = item.Functions.Select(x => x.Name).ToList();
+ foreach (var tool in tools.Tools.Where(x => funcnames.Contains(x.Name, StringComparer.OrdinalIgnoreCase)))
+ {
+ var funDef = AIFunctionUtilities.MapToFunctionDef(tool);
+ functionDefs.Add(funDef);
+ }
+ }
+ }
+
+ return functionDefs;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.MCP/MCPClientManager.cs b/src/Infrastructure/BotSharp.MCP/MCPClientManager.cs
new file mode 100644
index 00000000..bbe70205
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/MCPClientManager.cs
@@ -0,0 +1,33 @@
+using BotSharp.Core.Mcp.Settings;
+using McpDotNet.Client;
+using Microsoft.Extensions.Logging;
+using System;
+
+namespace BotSharp.Core.Mcp;
+
+public class MCPClientManager : IDisposable
+{
+ public ILoggerFactory LoggerFactory { get; }
+ public McpClientFactory Factory { get; }
+
+
+ private readonly MCPSettings mcpSettings;
+
+ public MCPClientManager(MCPSettings settings, ILoggerFactory loggerFactory)
+ {
+ mcpSettings = settings;
+ LoggerFactory = loggerFactory;
+
+ // Inject the mock transport into the factory
+ Factory = new McpClientFactory(
+ settings.McpServerConfigs,
+ settings.McpClientOptions,
+ LoggerFactory
+ );
+ }
+
+ public void Dispose()
+ {
+ LoggerFactory?.Dispose();
+ }
+}
diff --git a/src/Infrastructure/BotSharp.MCP/McpPlugin.cs b/src/Infrastructure/BotSharp.MCP/McpPlugin.cs
new file mode 100644
index 00000000..3d8ec0c8
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/McpPlugin.cs
@@ -0,0 +1,50 @@
+using BotSharp.Abstraction.Agents;
+using BotSharp.Abstraction.Conversations;
+using BotSharp.Abstraction.Functions;
+using BotSharp.Abstraction.Plugins;
+using BotSharp.Core.Mcp.Functions;
+using BotSharp.Core.Mcp.Settings;
+using BotSharp.MCP.Hooks;
+using McpDotNet.Protocol.Types;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+
+namespace BotSharp.Core.Mcp;
+
+public class McpPlugin : IBotSharpPlugin
+{
+ public string Id => "5d779611-0012-46cb-a754-4ca4770e88ac";
+ public string Name => "MCP Plugin";
+ public string Description => "Integrated MCP tools";
+
+ private MCPClientManager clientManager;
+
+ public void RegisterDI(IServiceCollection services, IConfiguration config)
+ {
+ var settings = config.GetSection("MCPSettings").Get();
+ services.AddScoped(provider => { return settings; });
+
+ clientManager = new MCPClientManager(settings, NullLoggerFactory.Instance);
+ services.AddSingleton(clientManager);
+
+ foreach (var server in settings.McpServerConfigs)
+ {
+ var client = clientManager.Factory.GetClientAsync(server.Id).Result;
+ var tools = client.ListToolsAsync().Result;
+
+ foreach (var tool in tools.Tools)
+ {
+ services.AddScoped( provider => { return tool; });
+
+ services.AddScoped( provider => {
+ var funcTool = new McpToolFunction( provider, tool, clientManager);
+ return funcTool;
+ });
+ }
+ }
+ // Register hooks
+ services.AddScoped();
+ }
+ }
diff --git a/src/Infrastructure/BotSharp.MCP/Settings/MCPSettings.cs b/src/Infrastructure/BotSharp.MCP/Settings/MCPSettings.cs
new file mode 100644
index 00000000..34e408e3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.MCP/Settings/MCPSettings.cs
@@ -0,0 +1,13 @@
+using McpDotNet.Client;
+using McpDotNet.Configuration;
+using System.Collections.Generic;
+
+namespace BotSharp.Core.Mcp.Settings;
+
+public class MCPSettings
+{
+ public McpClientOptions McpClientOptions { get; set; }
+
+ public List McpServerConfigs { get; set; }
+
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentCreationModel.cs
index 8e4d915d..81ec1bc7 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentCreationModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentCreationModel.cs
@@ -55,6 +55,7 @@ public class AgentCreationModel
public int? MaxMessageCount { get; set; }
public List Utilities { get; set; } = new();
+ public List McpTools { get; set; } = new();
public List RoutingRules { get; set; } = new();
public List KnowledgeBases { get; set; } = new();
public List Rules { get; set; } = new();
@@ -73,6 +74,7 @@ public class AgentCreationModel
Responses = Responses,
Samples = Samples,
Utilities = Utilities,
+ McpTools = McpTools,
IsPublic = IsPublic,
Type = Type,
Disabled = Disabled,
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentUpdateModel.cs
index ac2749b5..9f2925e5 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentUpdateModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/Request/AgentUpdateModel.cs
@@ -39,6 +39,11 @@ public class AgentUpdateModel
///
public List? Utilities { get; set; }
+ ///
+ /// McpTools
+ ///
+ public List? McpTools { get; set; }
+
///
/// knowledge bases
///
@@ -103,6 +108,7 @@ public class AgentUpdateModel
Functions = Functions ?? [],
Responses = Responses ?? [],
Utilities = Utilities ?? [],
+ McpTools = McpTools ?? [],
KnowledgeBases = KnowledgeBases ?? [],
Rules = Rules ?? [],
LlmConfig = LlmConfig ?? new()
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/View/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/View/AgentViewModel.cs
index b4ba1e08..db3af34c 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/View/AgentViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/View/AgentViewModel.cs
@@ -24,6 +24,7 @@ public class AgentViewModel
[JsonPropertyName("merge_utility")]
public bool MergeUtility { get; set; }
public List Utilities { get; set; }
+ public List Acps { get; set; }
[JsonPropertyName("knowledge_bases")]
public List KnowledgeBases { get; set; }
@@ -86,6 +87,7 @@ public class AgentViewModel
Responses = agent.Responses ?? [],
Samples = agent.Samples ?? [],
Utilities = agent.Utilities ?? [],
+ Acps = agent.McpTools ?? [],
KnowledgeBases = agent.KnowledgeBases ?? [],
IsPublic= agent.IsPublic,
Disabled = agent.Disabled,
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
index bdfdbe80..a0d99e0d 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs
@@ -12,17 +12,18 @@ public class AgentDocument : MongoBase
public bool Disabled { get; set; }
public bool MergeUtility { get; set; }
public int? MaxMessageCount { get; set; }
- public List ChannelInstructions { get; set; } = [];
- public List Templates { get; set; } = [];
- public List Functions { get; set; } = [];
- public List Responses { get; set; } = [];
- public List Samples { get; set; } = [];
- public List Utilities { get; set; } = [];
- public List KnowledgeBases { get; set; } = [];
- public List Profiles { get; set; } = [];
- public List Labels { get; set; } = [];
- public List RoutingRules { get; set; } = [];
- public List Rules { get; set; } = [];
+ public List ChannelInstructions { get; set; }
+ public List Templates { get; set; }
+ public List Functions { get; set; }
+ public List Responses { get; set; }
+ public List Samples { get; set; }
+ public List Utilities { get; set; }
+ public List McpTools { get; set; }
+ public List KnowledgeBases { get; set; }
+ public List Profiles { get; set; }
+ public List Labels { get; set; }
+ public List RoutingRules { get; set; }
+ public List Rules { get; set; }
public AgentLlmConfigMongoElement? LlmConfig { get; set; }
public DateTime CreatedTime { get; set; }
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentMCPToolMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentMCPToolMongoElement.cs
new file mode 100644
index 00000000..ecad71f3
--- /dev/null
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/AgentMCPToolMongoElement.cs
@@ -0,0 +1,69 @@
+using BotSharp.Abstraction.Agents.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BotSharp.Plugin.MongoStorage.Models;
+
+[BsonIgnoreExtraElements(Inherited = true)]
+public class AgentMCPToolMongoElement
+{
+ public string Name { get; set; }
+
+ public string ServerId { get; set; }
+
+ public bool Disabled { get; set; }
+ public List Functions { get; set; } = [];
+ public List Templates { get; set; } = [];
+
+ public static AgentMCPToolMongoElement ToMongoElement(MCPTool utility)
+ {
+ return new AgentMCPToolMongoElement
+ {
+ Disabled = utility.Disabled,
+ Functions = utility.Functions?.Select(x => new McpFunctionMongoElement(x.Name))?.ToList() ?? [],
+ };
+ }
+
+ public static MCPTool ToDomainElement(AgentMCPToolMongoElement utility)
+ {
+ return new MCPTool
+ {
+ Disabled = utility.Disabled,
+ Functions = utility.Functions?.Select(x => new MCPFunction(x.Name))?.ToList() ?? [],
+ };
+ }
+}
+
+public class McpFunctionMongoElement
+{
+ public string Name { get; set; }
+
+ public McpFunctionMongoElement()
+ {
+
+ }
+
+ public McpFunctionMongoElement(string name)
+ {
+ Name = name;
+ }
+}
+
+public class McpTemplateMongoElement
+{
+ public string Name { get; set; }
+
+ public McpTemplateMongoElement()
+ {
+
+ }
+
+ public McpTemplateMongoElement(string name)
+ {
+ Name = name;
+ }
+}
+
diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
index 90dd9cdf..069845ef 100644
--- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
+++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs
@@ -61,6 +61,9 @@ public partial class MongoRepository
case AgentField.Utility:
UpdateAgentUtilities(agent.Id, agent.MergeUtility, agent.Utilities);
break;
+ case AgentField.Acp:
+ UpdateAgentMcps(agent.Id, agent.McpTools);
+ break;
case AgentField.KnowledgeBase:
UpdateAgentKnowledgeBases(agent.Id, agent.KnowledgeBases);
break;
@@ -261,6 +264,19 @@ public partial class MongoRepository
_dc.Agents.UpdateOne(filter, update);
}
+ private void UpdateAgentMcps(string agentId, List mcps)
+ {
+ if (mcps == null) return;
+
+ var elements = mcps?.Select(x => AgentMCPToolMongoElement.ToMongoElement(x))?.ToList() ?? [];
+
+ var filter = Builders.Filter.Eq(x => x.Id, agentId);
+ var update = Builders.Update
+ .Set(x => x.McpTools, elements)
+ .Set(x => x.UpdatedTime, DateTime.UtcNow);
+
+ _dc.Agents.UpdateOne(filter, update);
+ }
private void UpdateAgentKnowledgeBases(string agentId, List knowledgeBases)
{
if (knowledgeBases == null) return;
@@ -330,6 +346,7 @@ public partial class MongoRepository
.Set(x => x.Responses, agent.Responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList())
.Set(x => x.Samples, agent.Samples)
.Set(x => x.Utilities, agent.Utilities.Select(u => AgentUtilityMongoElement.ToMongoElement(u)).ToList())
+ .Set(x => x.McpTools, agent.McpTools.Select(u => AgentMCPToolMongoElement.ToMongoElement(u)).ToList())
.Set(x => x.KnowledgeBases, agent.KnowledgeBases.Select(u => AgentKnowledgeBaseMongoElement.ToMongoElement(u)).ToList())
.Set(x => x.Rules, agent.Rules.Select(e => AgentRuleMongoElement.ToMongoElement(e)).ToList())
.Set(x => x.LlmConfig, AgentLlmConfigMongoElement.ToMongoElement(agent.LlmConfig))
@@ -510,6 +527,7 @@ public partial class MongoRepository
Responses = x.Responses?.Select(r => AgentResponseMongoElement.ToMongoElement(r))?.ToList() ?? [],
RoutingRules = x.RoutingRules?.Select(r => RoutingRuleMongoElement.ToMongoElement(r))?.ToList() ?? [],
Utilities = x.Utilities?.Select(u => AgentUtilityMongoElement.ToMongoElement(u))?.ToList() ?? [],
+ McpTools = x.McpTools?.Select(u => AgentMCPToolMongoElement.ToMongoElement(u))?.ToList() ?? [],
KnowledgeBases = x.KnowledgeBases?.Select(k => AgentKnowledgeBaseMongoElement.ToMongoElement(k))?.ToList() ?? [],
Rules = x.Rules?.Select(e => AgentRuleMongoElement.ToMongoElement(e))?.ToList() ?? [],
CreatedTime = x.CreatedDateTime,
@@ -604,6 +622,7 @@ public partial class MongoRepository
Responses = agentDoc.Responses?.Select(r => AgentResponseMongoElement.ToDomainElement(r))?.ToList() ?? [],
RoutingRules = agentDoc.RoutingRules?.Select(r => RoutingRuleMongoElement.ToDomainElement(agentDoc.Id, agentDoc.Name, r))?.ToList() ?? [],
Utilities = agentDoc.Utilities?.Select(u => AgentUtilityMongoElement.ToDomainElement(u))?.ToList() ?? [],
+ McpTools = agentDoc.McpTools?.Select(u => AgentMCPToolMongoElement.ToDomainElement(u))?.ToList() ?? [],
KnowledgeBases = agentDoc.KnowledgeBases?.Select(x => AgentKnowledgeBaseMongoElement.ToDomainElement(x))?.ToList() ?? [],
Rules = agentDoc.Rules?.Select(e => AgentRuleMongoElement.ToDomainElement(e))?.ToList() ?? []
};
diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj
index 78c4537c..d06fa30a 100644
--- a/src/WebStarter/WebStarter.csproj
+++ b/src/WebStarter/WebStarter.csproj
@@ -27,8 +27,10 @@
+
+
diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json
index 9d8afd80..2582a8ae 100644
--- a/src/WebStarter/appsettings.json
+++ b/src/WebStarter/appsettings.json
@@ -50,10 +50,7 @@
"Name": "gpt-35-turbo",
"Version": "1106",
"ApiKey": "",
- "Endpoint": "https://gpt-35-turbo-instruct.openai.azure.com/",
- "Type": "chat",
- "PromptCost": 0.0015,
- "CompletionCost": 0.002
+ "Endpoint": "https://gpt-35-turbo-instruct.openai.azure.com/"
},
{
"Name": "gpt-35-turbo-instruct",
@@ -170,11 +167,29 @@
"HostAgentId": "01e2fc5c-2c89-4ec7-8470-7688608b496c",
"EnableTranslator": false,
"LlmConfig": {
- "Provider": "openai",
+ "Provider": "azure-openai",
"Model": "gpt-4o-mini"
}
},
-
+ "MCPSettings": {
+ "McpClientOptions": {
+ "ClientInfo": {
+ "Name": "SimpleToolsBotsharp",
+ "Version": "1.0.0"
+ }
+ },
+ "McpServerConfigs": [
+ {
+ "Id": "PizzaServer",
+ "Name": "PizzaServer",
+ "TransportType": "stdio",
+ "TransportOptions": {
+ "command": "BotSharp.PizzaBot.MCPServer.exe",
+ "workingDirectory": "E:\\GitHub\\BotSharp\\src\\WebStarter\\bin\\Debug\\net8.0"
+ }
+ }
+ ]
+ },
"Conversation": {
"DataDir": "conversations",
"ShowVerboseLog": false,
@@ -397,6 +412,7 @@
"BotSharp.Core.Crontab",
"BotSharp.Core.Realtime",
"BotSharp.Logger",
+ "BotSharp.MCP",
"BotSharp.Plugin.MongoStorage",
"BotSharp.Plugin.Dashboard",
"BotSharp.Plugin.OpenAI",
diff --git a/tests/BotSharp.PizzaBot.MCPServer/BotSharp.PizzaBot.MCPServer.csproj b/tests/BotSharp.PizzaBot.MCPServer/BotSharp.PizzaBot.MCPServer.csproj
new file mode 100644
index 00000000..1158e06a
--- /dev/null
+++ b/tests/BotSharp.PizzaBot.MCPServer/BotSharp.PizzaBot.MCPServer.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ 12.0
+ enable
+
+
+
+
+
+
+
+
diff --git a/tests/BotSharp.PizzaBot.MCPServer/Program.cs b/tests/BotSharp.PizzaBot.MCPServer/Program.cs
new file mode 100644
index 00000000..5e8633f8
--- /dev/null
+++ b/tests/BotSharp.PizzaBot.MCPServer/Program.cs
@@ -0,0 +1,204 @@
+using McpDotNet.Protocol.Transport;
+using McpDotNet.Protocol.Types;
+using McpDotNet.Server;
+using Microsoft.Extensions.Logging;
+using Serilog;
+using System.Dynamic;
+using System.Text;
+using System.Text.Json;
+
+namespace BotSharp.PizzaBot.MCPServer
+{
+ internal class Program
+ {
+ private static async Task Main(string[] args)
+ {
+ Console.WriteLine("Starting server...");
+
+ McpServerOptions options = new McpServerOptions()
+ {
+ ServerInfo = new Implementation() { Name = "PizzaServer", Version = "1.0.0" },
+ Capabilities = new ServerCapabilities()
+ {
+ Tools = new(),
+ Resources = new(),
+ Prompts = new(),
+ },
+ ProtocolVersion = "2024-11-05"
+ };
+ var loggerFactory = CreateLoggerFactory();
+ McpServerFactory factory = new McpServerFactory(new StdioServerTransport("PizzaServer", loggerFactory), options, loggerFactory,
+ "This is a test server with only stub functionality");
+ IMcpServer server = factory.CreateServer();
+
+ Console.WriteLine("Server object created, registering handlers.");
+
+ #region Tools
+ server.ListToolsHandler = (request, cancellationToken) =>
+ {
+ return Task.FromResult(new ListToolsResult()
+ {
+ Tools =
+ [
+ new Tool()
+ {
+ Name = "make_payment",
+ Description = "call this function to make payment",
+ InputSchema = new JsonSchema()
+ {
+ Type = "object",
+ Properties = new Dictionary()
+ {
+ ["order_number"] = new JsonSchemaProperty() { Type = "string", Description = "order number." },
+ ["total_amount"] = new JsonSchemaProperty() { Type = "string", Description = "total amount." },
+ },
+ Required = new List() { "order_number", "total_amount" }
+ },
+ },
+ new Tool()
+ {
+ Name = "get_pizza_prices",
+ Description = "call this function to get pizza prices",
+ InputSchema = new JsonSchema()
+ {
+ Type = "object",
+ Properties = new Dictionary()
+ {
+ ["pizza_type"] = new JsonSchemaProperty() { Type = "string", Description = "The pizza type." },
+ ["quantity"] = new JsonSchemaProperty() { Type = "string", Description = "quantity of pizza." },
+
+ },
+ Required = new List(){ "pizza_type", "quantity" }
+ }
+ },
+ new Tool()
+ {
+ Name = "place_an_order",
+ Description = "Place an order when user has confirmed the pizza type and quantity.",
+ InputSchema = new JsonSchema()
+ {
+ Type = "object",
+ Properties = new Dictionary()
+ {
+ ["pizza_type"] = new JsonSchemaProperty() { Type = "string", Description = "The pizza type." },
+ ["quantity"] = new JsonSchemaProperty() { Type = "number", Description = "quantity of pizza." },
+ ["unit_price"] = new JsonSchemaProperty() { Type = "number", Description = "unit price" },
+
+ },
+ Required = new List(){"pizza_type", "quantity", "unit_price" }
+ }
+ }
+ ]
+ });
+ };
+
+ server.CallToolHandler = async (request, cancellationToken) =>
+ {
+ if (request.Name == "make_payment")
+ {
+ if (request.Arguments is null || !request.Arguments.TryGetValue("order_number", out var order_number))
+ {
+ throw new McpServerException("Missing required argument 'order_number'");
+ }
+ if (request.Arguments is null || !request.Arguments.TryGetValue("total_amount", out var total_amount))
+ {
+ throw new McpServerException("Missing required argument 'total_amount'");
+ }
+ dynamic message = new ExpandoObject();
+ message.Transaction = Guid.NewGuid().ToString();
+ message.Status = "Success";
+
+ // Serialize the message to JSON
+ var jso = new JsonSerializerOptions() { WriteIndented = true };
+ var jsonMessage = JsonSerializer.Serialize(message, jso);
+
+ return new CallToolResponse()
+ {
+ Content = [new Content() { Text = jsonMessage , Type = "text" }]
+ };
+ }
+ else if(request.Name == "get_pizza_prices")
+ {
+ if (request.Arguments is null || !request.Arguments.TryGetValue("pizza_type", out var pizza_type))
+ {
+ throw new McpServerException("Missing required argument 'pizza_type'");
+ }
+ if (request.Arguments is null || !request.Arguments.TryGetValue("quantity", out var quantity))
+ {
+ throw new McpServerException("Missing required argument 'quantity'");
+ }
+ dynamic message = new ExpandoObject();
+ message.pepperoni_unit_price = 3.2;
+ message.cheese_unit_price = 3.5;
+ message.margherita_unit_price = 3.8;
+ // Serialize the message to JSON
+ var jso = new JsonSerializerOptions() { WriteIndented = true };
+ var jsonMessage = JsonSerializer.Serialize(message, jso);
+ return new CallToolResponse()
+ {
+ Content = [new Content() { Text = jsonMessage, Type = "text" }]
+ };
+ }
+ else if (request.Name == "place_an_order")
+ {
+ if (request.Arguments is null || !request.Arguments.TryGetValue("pizza_type", out var pizza_type))
+ {
+ throw new McpServerException("Missing required argument 'pizza_type'");
+ }
+ if (request.Arguments is null || !request.Arguments.TryGetValue("quantity", out var quantity))
+ {
+ throw new McpServerException("Missing required argument 'quantity'");
+ }
+ if (request.Arguments is null || !request.Arguments.TryGetValue("unit_price", out var unit_price))
+ {
+ throw new McpServerException("Missing required argument 'unit_price'");
+ }
+ dynamic message = new ExpandoObject();
+ message.order_number = "P123-01";
+ message.Content = "The order number is P123-01";
+ // Serialize the message to JSON
+ var jso = new JsonSerializerOptions() { WriteIndented = true };
+ var jsonMessage = JsonSerializer.Serialize(message, jso);
+ return new CallToolResponse()
+ {
+ Content = [new Content() { Text = jsonMessage, Type = "text" }]
+ };
+ }
+ else
+ {
+ throw new McpServerException($"Unknown tool: {request.Name}");
+ }
+ };
+ #endregion
+
+ Console.WriteLine("Server initialized.");
+
+ await server.StartAsync();
+
+ Console.WriteLine("Server started.");
+
+ // Run until process is stopped by the client (parent process)
+ while (true)
+ {
+ await Task.Delay(1000);
+ }
+ }
+
+ private static ILoggerFactory CreateLoggerFactory()
+ {
+ // Use serilog
+ Log.Logger = new LoggerConfiguration()
+ .MinimumLevel.Verbose() // Capture all log levels
+ .WriteTo.File(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "TestServer_.log"),
+ rollingInterval: RollingInterval.Day,
+ outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
+ .CreateLogger();
+
+ var logsPath = Path.Combine(AppContext.BaseDirectory, "testserver.log");
+ return LoggerFactory.Create(builder =>
+ {
+ builder.AddSerilog();
+ });
+ }
+ }
+}
diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs
index 4fa39c7c..9433c6a8 100644
--- a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs
+++ b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs
@@ -1,21 +1,21 @@
-using BotSharp.Abstraction.Conversations.Models;
-using System.Text.Json;
+//using BotSharp.Abstraction.Conversations.Models;
+//using System.Text.Json;
-namespace BotSharp.Plugin.PizzaBot.Functions;
+//namespace BotSharp.Plugin.PizzaBot.Functions;
-public class GetPizzaPricesFn : IFunctionCallback
-{
- public string Name => "get_pizza_price";
+//public class GetPizzaPricesFn : IFunctionCallback
+//{
+// public string Name => "get_pizza_price";
- public async Task Execute(RoleDialogModel message)
- {
- message.Data = new
- {
- pepperoni_unit_price = 3.2,
- cheese_unit_price = 3.5,
- margherita_unit_price = 3.8,
- };
- message.Content = JsonSerializer.Serialize(message.Data);
- return true;
- }
-}
+// public async Task Execute(RoleDialogModel message)
+// {
+// message.Data = new
+// {
+// pepperoni_unit_price = 3.2,
+// cheese_unit_price = 3.5,
+// margherita_unit_price = 3.8,
+// };
+// message.Content = JsonSerializer.Serialize(message.Data);
+// return true;
+// }
+//}
diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs
index 9a239fd2..1ce3aac3 100644
--- a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs
+++ b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs
@@ -46,7 +46,7 @@ public class GetPizzaTypesFn : IFunctionCallback
}).ToArray()
}
};
-
+
return true;
}
}
diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/MakePaymentFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/MakePaymentFn.cs
index 144eb05a..5a34a6ce 100644
--- a/tests/BotSharp.Plugin.PizzaBot/Functions/MakePaymentFn.cs
+++ b/tests/BotSharp.Plugin.PizzaBot/Functions/MakePaymentFn.cs
@@ -1,19 +1,19 @@
-using BotSharp.Abstraction.Conversations.Models;
+//using BotSharp.Abstraction.Conversations.Models;
-namespace BotSharp.Plugin.PizzaBot.Functions;
+//namespace BotSharp.Plugin.PizzaBot.Functions;
-public class MakePaymentFn : IFunctionCallback
-{
- public string Name => "make_payment";
+//public class MakePaymentFn : IFunctionCallback
+//{
+// public string Name => "make_payment";
- public async Task Execute(RoleDialogModel message)
- {
- message.Content = "Payment proceed successfully. Thank you for your business. Have a great day!";
- message.Data = new
- {
- Transaction = Guid.NewGuid().ToString(),
- Status = "Success"
- };
- return true;
- }
-}
+// public async Task Execute(RoleDialogModel message)
+// {
+// message.Content = "Payment proceed successfully. Thank you for your business. Have a great day!";
+// message.Data = new
+// {
+// Transaction = Guid.NewGuid().ToString(),
+// Status = "Success"
+// };
+// return true;
+// }
+//}
diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs
index 87466956..47d27363 100644
--- a/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs
+++ b/tests/BotSharp.Plugin.PizzaBot/Functions/PlaceOrderFn.cs
@@ -1,24 +1,24 @@
-using BotSharp.Abstraction.Conversations;
-using BotSharp.Abstraction.Conversations.Models;
+//using BotSharp.Abstraction.Conversations;
+//using BotSharp.Abstraction.Conversations.Models;
-namespace BotSharp.Plugin.PizzaBot.Functions;
+//namespace BotSharp.Plugin.PizzaBot.Functions;
-public class PlaceOrderFn : IFunctionCallback
-{
- public string Name => "place_an_order";
+//public class PlaceOrderFn : IFunctionCallback
+//{
+// public string Name => "place_an_order";
- private readonly IServiceProvider _service;
- public PlaceOrderFn(IServiceProvider service)
- {
- _service = service;
- }
+// private readonly IServiceProvider _service;
+// public PlaceOrderFn(IServiceProvider service)
+// {
+// _service = service;
+// }
- public async Task Execute(RoleDialogModel message)
- {
- message.Content = "The order number is P123-01";
- var state = _service.GetRequiredService();
- state.SetState("order_number", "P123-01");
+// public async Task Execute(RoleDialogModel message)
+// {
+// message.Content = "The order number is P123-01";
+// var state = _service.GetRequiredService();
+// state.SetState("order_number", "P123-01");
- return true;
- }
-}
+// return true;
+// }
+//}
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
index 40988cb2..7ec18d46 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/agent.json
@@ -7,5 +7,19 @@
"disabled": false,
"isPublic": true,
"profiles": [ "pizza" ],
+ "mcptools": [
+ {
+ "serverid": "PizzaServer",
+ "disabled": false,
+ "functions": [
+ {
+ "Name": "get_pizza_price"
+ },
+ {
+ "Name": "place_an_order"
+ }
+ ]
+ }
+ ]
"labels": [ "experiment" ]
}
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/get_pizza_price.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/get_pizza_price.json
index e2eaac31..1ecdbb65 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/get_pizza_price.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/get_pizza_price.json
@@ -1,18 +1,18 @@
-{
- "name": "get_pizza_price",
- "description": "call this function to get the pizza price",
- "parameters": {
- "type": "object",
- "properties": {
- "pizza_type": {
- "type": "string",
- "description": "The pizza type."
- },
- "quantity": {
- "type": "string",
- "description": "quantity of pizza."
- }
- },
- "required": [ "pizza_type", "quantity" ]
- }
-}
\ No newline at end of file
+//{
+// "name": "get_pizza_price",
+// "description": "call this function to get the pizza price",
+// "parameters": {
+// "type": "object",
+// "properties": {
+// "pizza_type": {
+// "type": "string",
+// "description": "The pizza type."
+// },
+// "quantity": {
+// "type": "string",
+// "description": "quantity of pizza."
+// }
+// },
+// "required": [ "pizza_type", "quantity" ]
+// }
+//}
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json
index d5514fba..a01f0005 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd/functions/place_an_order.json
@@ -1,22 +1,22 @@
-{
- "name": "place_an_order",
- "description": "Place an order when user has confirmed the pizza type and quantity.",
- "parameters": {
- "type": "object",
- "properties": {
- "pizza_type": {
- "type": "string",
- "description": "The pizza type."
- },
- "quantity": {
- "type": "number",
- "description": "quantity of pizza."
- },
- "unit_price": {
- "type": "number",
- "description": "unit price"
- }
- },
- "required": [ "pizza_type", "quantity", "unit_price" ]
- }
-}
\ No newline at end of file
+//{
+// "name": "place_an_order",
+// "description": "Place an order when user has confirmed the pizza type and quantity.",
+// "parameters": {
+// "type": "object",
+// "properties": {
+// "pizza_type": {
+// "type": "string",
+// "description": "The pizza type."
+// },
+// "quantity": {
+// "type": "number",
+// "description": "quantity of pizza."
+// },
+// "unit_price": {
+// "type": "number",
+// "description": "unit price"
+// }
+// },
+// "required": [ "pizza_type", "quantity", "unit_price" ]
+// }
+//}
\ No newline at end of file
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json
index ef47f34d..f34ffb76 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/agent.json
@@ -7,6 +7,17 @@
"disabled": false,
"isPublic": true,
"profiles": [ "pizza" ],
+ "mcptools": [
+ {
+ "serverid": "PizzaServer",
+ "disabled": false,
+ "functions": [
+ {
+ "Name": "make_payment"
+ }
+ ]
+ }
+ ],
"labels": [ "experiment" ],
"routingRules": [
{
diff --git a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/functions/make_payment.json b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/functions/make_payment.json
index 82782c94..914f215e 100644
--- a/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/functions/make_payment.json
+++ b/tests/BotSharp.Plugin.PizzaBot/data/agents/fe8c60aa-b114-4ef3-93cb-a8efeac80f75/functions/make_payment.json
@@ -1,18 +1,18 @@
-{
- "name": "make_payment",
- "description": "call this function to make payment",
- "parameters": {
- "type": "object",
- "properties": {
- "order_number": {
- "type": "string",
- "description": "order number."
- },
- "total_amount": {
- "type": "string",
- "description": "total amount."
- }
- },
- "required": [ "order_number", "total_amount" ]
- }
-}
\ No newline at end of file
+//{
+// "name": "make_payment",
+// "description": "call this function to make payment",
+// "parameters": {
+// "type": "object",
+// "properties": {
+// "order_number": {
+// "type": "string",
+// "description": "order number."
+// },
+// "total_amount": {
+// "type": "string",
+// "description": "total amount."
+// }
+// },
+// "required": [ "order_number", "total_amount" ]
+// }
+//}
\ No newline at end of file