feat:Data with Json
1、Json Data Save to State 2、mcpdotnet with source ref
This commit is contained in:
parent
bf6b30d3ce
commit
35358f20b9
11
BotSharp.sln
11
BotSharp.sln
|
|
@ -133,6 +133,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.PizzaBot.MCPServer
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Realtime", "src\Infrastructure\BotSharp.Core.Realtime\BotSharp.Core.Realtime.csproj", "{781F1465-365C-0F22-1775-25025DAFA4C7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Realtime", "src\Infrastructure\BotSharp.Core.Realtime\BotSharp.Core.Realtime.csproj", "{781F1465-365C-0F22-1775-25025DAFA4C7}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mcpdotnet", "..\mcpdotnet\src\mcpdotnet\mcpdotnet.csproj", "{32D455C9-C7CF-928B-F878-8EAF0198328E}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -549,6 +551,14 @@ Global
|
||||||
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x64.ActiveCfg = Release|Any CPU
|
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x64.Build.0 = Release|Any CPU
|
{781F1465-365C-0F22-1775-25025DAFA4C7}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -613,6 +623,7 @@ Global
|
||||||
{684781D5-3DD4-6A0B-B53F-0A362CD6BB0C} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
|
{684781D5-3DD4-6A0B-B53F-0A362CD6BB0C} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
|
||||||
{8D2AD45F-836A-516F-DE6A-71443CEBB18A} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
|
{8D2AD45F-836A-516F-DE6A-71443CEBB18A} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
|
||||||
{781F1465-365C-0F22-1775-25025DAFA4C7} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
|
{781F1465-365C-0F22-1775-25025DAFA4C7} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
|
||||||
|
{32D455C9-C7CF-928B-F878-8EAF0198328E} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
|
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<MSExtensionsVersion>8.0.0</MSExtensionsVersion>
|
<MSExtensionsVersion>8.0.0</MSExtensionsVersion>
|
||||||
<AspNetCoreVersion>2.3.0</AspNetCoreVersion>
|
<AspNetCoreVersion>2.3.0</AspNetCoreVersion>
|
||||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -15,10 +15,11 @@
|
||||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.1" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
|
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
|
||||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.0.0" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.0.0" />
|
||||||
|
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="10.0.0-preview.1.25080.5" />
|
||||||
<PackageVersion Include="System.Memory.Data" Version="8.0.0" />
|
<PackageVersion Include="System.Memory.Data" Version="8.0.0" />
|
||||||
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
|
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
|
||||||
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
|
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||||
|
|
@ -131,7 +132,6 @@
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.5" />
|
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.5" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.5" />
|
<PackageVersion Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="8.0.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.27" />
|
<PackageVersion Include="Microsoft.AspNetCore.Authentication.Google" Version="6.0.27" />
|
||||||
<PackageVersion Include="AspNet.Security.OAuth.GitHub" Version="6.0.15" />
|
<PackageVersion Include="AspNet.Security.OAuth.GitHub" Version="6.0.15" />
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,11 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="mcpdotnet" />
|
<PackageReference Include="System.Linq.AsyncEnumerable" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\mcpdotnet\src\mcpdotnet\mcpdotnet.csproj" />
|
||||||
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ public class McpToolFunction : IFunctionCallback
|
||||||
var agent = await agentService.LoadAgent(currentAgentId);
|
var agent = await agentService.LoadAgent(currentAgentId);
|
||||||
var serverId = agent.McpTools.Where(t => t.Functions.Any(f => f.Name == Name)).FirstOrDefault().ServerId;
|
var serverId = agent.McpTools.Where(t => t.Functions.Any(f => f.Name == Name)).FirstOrDefault().ServerId;
|
||||||
|
|
||||||
var client = await _clientManager.Factory.GetClientAsync(serverId);
|
var client = await _clientManager.GetMcpClientAsync(serverId);
|
||||||
// Call the tool through mcpdotnet
|
// Call the tool through mcpdotnet
|
||||||
var result = await client.CallToolAsync(
|
var result = await client.CallToolAsync(
|
||||||
_tool.Name,
|
_tool.Name,
|
||||||
|
|
@ -50,8 +50,8 @@ public class McpToolFunction : IFunctionCallback
|
||||||
var json = string.Join("\n", result.Content
|
var json = string.Join("\n", result.Content
|
||||||
.Where(c => c.Type == "text")
|
.Where(c => c.Type == "text")
|
||||||
.Select(c => c.Text));
|
.Select(c => c.Text));
|
||||||
message.Content = json.JsonContent();
|
message.Content = json;
|
||||||
|
message.Data = json.JsonContent();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,12 @@ public class MCPResponseHook : ConversationHookBase
|
||||||
public override async Task OnResponseGenerated(RoleDialogModel message)
|
public override async Task OnResponseGenerated(RoleDialogModel message)
|
||||||
{
|
{
|
||||||
var agentService = _services.GetRequiredService<IAgentService>();
|
var agentService = _services.GetRequiredService<IAgentService>();
|
||||||
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
var agent = await agentService.LoadAgent(message.CurrentAgentId);
|
var agent = await agentService.LoadAgent(message.CurrentAgentId);
|
||||||
if(agent.McpTools.Any(item => item.Functions.Any(x=> x.Name == message.FunctionName)))
|
if(agent.McpTools.Any(item => item.Functions.Any(x=> x.Name == message.FunctionName)))
|
||||||
{
|
{
|
||||||
message.Data = JsonSerializer.Deserialize(message.Content, typeof(object));
|
var data = JsonDocument.Parse(JsonSerializer.Serialize(message.Data));
|
||||||
|
state.SaveStateByArgs(data);
|
||||||
}
|
}
|
||||||
await base.OnResponseGenerated(message);
|
await base.OnResponseGenerated(message);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using BotSharp.Abstraction.Conversations;
|
||||||
using BotSharp.Abstraction.Functions.Models;
|
using BotSharp.Abstraction.Functions.Models;
|
||||||
using BotSharp.Core.Mcp;
|
using BotSharp.Core.Mcp;
|
||||||
using BotSharp.Core.MCP;
|
using BotSharp.Core.MCP;
|
||||||
|
using McpDotNet.Client;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -51,12 +52,12 @@ public class MCPToolAgentHook : AgentHookBase
|
||||||
var mcps = agent.McpTools;
|
var mcps = agent.McpTools;
|
||||||
foreach (var item in mcps)
|
foreach (var item in mcps)
|
||||||
{
|
{
|
||||||
var mcpClient = await mcpClientManager.Factory.GetClientAsync(item.ServerId);
|
var mcpClient = await mcpClientManager.GetMcpClientAsync(item.ServerId);
|
||||||
if (mcpClient != null)
|
if (mcpClient != null)
|
||||||
{
|
{
|
||||||
var tools = await mcpClient.ListToolsAsync();
|
var tools = await mcpClient.ListToolsAsync().ToListAsync();
|
||||||
var funcnames = item.Functions.Select(x => x.Name).ToList();
|
var funcnames = item.Functions.Select(x => x.Name).ToList();
|
||||||
foreach (var tool in tools.Tools.Where(x => funcnames.Contains(x.Name, StringComparer.OrdinalIgnoreCase)))
|
foreach (var tool in tools.Where(x => funcnames.Contains(x.Name, StringComparer.OrdinalIgnoreCase)))
|
||||||
{
|
{
|
||||||
var funDef = AIFunctionUtilities.MapToFunctionDef(tool);
|
var funDef = AIFunctionUtilities.MapToFunctionDef(tool);
|
||||||
functionDefs.Add(funDef);
|
functionDefs.Add(funDef);
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,27 @@ using BotSharp.Core.Mcp.Settings;
|
||||||
using McpDotNet.Client;
|
using McpDotNet.Client;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace BotSharp.Core.Mcp;
|
namespace BotSharp.Core.Mcp;
|
||||||
|
|
||||||
public class MCPClientManager : IDisposable
|
public class MCPClientManager : IDisposable
|
||||||
{
|
{
|
||||||
public ILoggerFactory LoggerFactory { get; }
|
public ILoggerFactory LoggerFactory { get; }
|
||||||
public McpClientFactory Factory { get; }
|
|
||||||
|
|
||||||
|
|
||||||
private readonly MCPSettings mcpSettings;
|
private readonly MCPSettings mcpSettings;
|
||||||
|
|
||||||
public MCPClientManager(MCPSettings settings, ILoggerFactory loggerFactory)
|
public MCPClientManager(MCPSettings settings, ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
mcpSettings = settings;
|
mcpSettings = settings;
|
||||||
LoggerFactory = loggerFactory;
|
LoggerFactory = loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
// Inject the mock transport into the factory
|
public async Task<IMcpClient> GetMcpClientAsync(string serverId)
|
||||||
Factory = new McpClientFactory(
|
{
|
||||||
settings.McpServerConfigs,
|
return await McpClientFactory.CreateAsync(mcpSettings.McpServerConfigs
|
||||||
settings.McpClientOptions,
|
.Where(x=> x.Name == serverId).First(), mcpSettings.McpClientOptions);
|
||||||
LoggerFactory
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,14 @@ using BotSharp.Abstraction.Plugins;
|
||||||
using BotSharp.Core.Mcp.Functions;
|
using BotSharp.Core.Mcp.Functions;
|
||||||
using BotSharp.Core.Mcp.Settings;
|
using BotSharp.Core.Mcp.Settings;
|
||||||
using BotSharp.MCP.Hooks;
|
using BotSharp.MCP.Hooks;
|
||||||
|
using McpDotNet.Client;
|
||||||
using McpDotNet.Protocol.Types;
|
using McpDotNet.Protocol.Types;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace BotSharp.Core.Mcp;
|
namespace BotSharp.Core.Mcp;
|
||||||
|
|
||||||
|
|
@ -31,20 +34,30 @@ public class McpPlugin : IBotSharpPlugin
|
||||||
|
|
||||||
foreach (var server in settings.McpServerConfigs)
|
foreach (var server in settings.McpServerConfigs)
|
||||||
{
|
{
|
||||||
var client = clientManager.Factory.GetClientAsync(server.Id).Result;
|
RegisterFunctionCall(services, server)
|
||||||
var tools = client.ListToolsAsync().Result;
|
.ConfigureAwait(false)
|
||||||
|
.GetAwaiter()
|
||||||
foreach (var tool in tools.Tools)
|
.GetResult();
|
||||||
{
|
|
||||||
services.AddScoped( provider => { return tool; });
|
|
||||||
|
|
||||||
services.AddScoped<IFunctionCallback>( provider => {
|
|
||||||
var funcTool = new McpToolFunction( provider, tool, clientManager);
|
|
||||||
return funcTool;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Register hooks
|
// Register hooks
|
||||||
services.AddScoped<IAgentHook, MCPToolAgentHook>();
|
services.AddScoped<IAgentHook, MCPToolAgentHook>();
|
||||||
|
services.AddScoped<IConversationHook, MCPResponseHook>();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private async Task RegisterFunctionCall(IServiceCollection services, McpDotNet.Configuration.McpServerConfig server)
|
||||||
|
{
|
||||||
|
var client = await clientManager.GetMcpClientAsync(server.Id);
|
||||||
|
var tools = await client.ListToolsAsync().ToListAsync();
|
||||||
|
|
||||||
|
foreach (var tool in tools)
|
||||||
|
{
|
||||||
|
services.AddScoped(provider => { return tool; });
|
||||||
|
|
||||||
|
services.AddScoped<IFunctionCallback>(provider =>
|
||||||
|
{
|
||||||
|
var funcTool = new McpToolFunction(provider, tool, clientManager);
|
||||||
|
return funcTool;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,11 +46,15 @@
|
||||||
"Provider": "azure-openai",
|
"Provider": "azure-openai",
|
||||||
"Models": [
|
"Models": [
|
||||||
{
|
{
|
||||||
"Id": "gpt-3.5-turbo",
|
"Id": "gpt-4o-mini",
|
||||||
"Name": "gpt-35-turbo",
|
"Name": "gpt-4o-mini",
|
||||||
"Version": "1106",
|
"ApiKey": "c1cee6ddfb3d4f469587789efe7a2ba9",
|
||||||
"ApiKey": "",
|
"Endpoint": "https://ai4c-demo.openai.azure.com/",
|
||||||
"Endpoint": "https://gpt-35-turbo-instruct.openai.azure.com/"
|
"Type": "chat",
|
||||||
|
"PromptCost": 0.0015,
|
||||||
|
"CompletionCost": 0.002,
|
||||||
|
"MaxTokens": null,
|
||||||
|
"Temperature": 1.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "gpt-35-turbo-instruct",
|
"Name": "gpt-35-turbo-instruct",
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="mcpdotnet" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting"/>
|
<PackageReference Include="Microsoft.Extensions.Logging" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" />
|
<PackageReference Include="Serilog.Extensions.Logging" />
|
||||||
<PackageReference Include="Serilog.Extensions.Logging" />
|
<PackageReference Include="Serilog.Sinks.File" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" />
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\mcpdotnet\src\mcpdotnet\mcpdotnet.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ namespace BotSharp.PizzaBot.MCPServer
|
||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
private static HashSet<string> _subscribedResources = new();
|
||||||
|
private static readonly object _subscribedResourcesLock = new();
|
||||||
|
|
||||||
private static async Task Main(string[] args)
|
private static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Starting server...");
|
Console.WriteLine("Starting server...");
|
||||||
|
|
@ -21,34 +24,48 @@ namespace BotSharp.PizzaBot.MCPServer
|
||||||
ServerInfo = new Implementation() { Name = "PizzaServer", Version = "1.0.0" },
|
ServerInfo = new Implementation() { Name = "PizzaServer", Version = "1.0.0" },
|
||||||
Capabilities = new ServerCapabilities()
|
Capabilities = new ServerCapabilities()
|
||||||
{
|
{
|
||||||
//Tools = ConfigureTools(),
|
Tools = ConfigureTools(),
|
||||||
},
|
},
|
||||||
ProtocolVersion = "2024-11-05",
|
ProtocolVersion = "2024-11-05",
|
||||||
ServerInstructions = "This is a test server with only stub functionality"
|
ServerInstructions = "This is a test server with only stub functionality"
|
||||||
};
|
};
|
||||||
var loggerFactory = CreateLoggerFactory();
|
var loggerFactory = CreateLoggerFactory();
|
||||||
McpServerFactory factory = new McpServerFactory(new StdioServerTransport("PizzaServer", loggerFactory), options, loggerFactory);
|
await using IMcpServer server = McpServerFactory.Create(new StdioServerTransport("TestServer", loggerFactory), options, loggerFactory);
|
||||||
IMcpServer server = factory.CreateServer();
|
Log.Logger.Information("Server initialized.");
|
||||||
ConfigureTools(server);
|
|
||||||
|
|
||||||
Console.WriteLine("Server object created, registering handlers.");
|
|
||||||
|
|
||||||
Console.WriteLine("Server initialized.");
|
|
||||||
|
|
||||||
await server.StartAsync();
|
await server.StartAsync();
|
||||||
|
|
||||||
Console.WriteLine("Server started.");
|
Log.Logger.Information("Server started.");
|
||||||
|
|
||||||
// Run until process is stopped by the client (parent process)
|
// Run until process is stopped by the client (parent process)
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
await Task.Delay(1000);
|
await Task.Delay(5000);
|
||||||
|
|
||||||
|
// Snapshot the subscribed resources, rather than locking while sending notifications
|
||||||
|
List<string> resources;
|
||||||
|
lock (_subscribedResourcesLock)
|
||||||
|
{
|
||||||
|
resources = _subscribedResources.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var resource in resources)
|
||||||
|
{
|
||||||
|
ResourceUpdatedNotificationParams notificationParams = new() { Uri = resource };
|
||||||
|
await server.SendMessageAsync(new JsonRpcNotification()
|
||||||
|
{
|
||||||
|
Method = NotificationMethods.ResourceUpdatedNotification,
|
||||||
|
Params = notificationParams
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ConfigureTools(IMcpServer server)
|
private static ToolsCapability ConfigureTools()
|
||||||
{
|
{
|
||||||
server.ListToolsHandler = (request, cancellationToken) =>
|
return new()
|
||||||
|
{
|
||||||
|
ListToolsHandler = (request, cancellationToken) =>
|
||||||
{
|
{
|
||||||
return Task.FromResult(new ListToolsResult()
|
return Task.FromResult(new ListToolsResult()
|
||||||
{
|
{
|
||||||
|
|
@ -71,7 +88,7 @@ namespace BotSharp.PizzaBot.MCPServer
|
||||||
new Tool()
|
new Tool()
|
||||||
{
|
{
|
||||||
Name = "get_pizza_prices",
|
Name = "get_pizza_prices",
|
||||||
Description = "call this function to get pizza prices",
|
Description = "call this function to get pizza unit price",
|
||||||
InputSchema = new JsonSchema()
|
InputSchema = new JsonSchema()
|
||||||
{
|
{
|
||||||
Type = "object",
|
Type = "object",
|
||||||
|
|
@ -95,7 +112,7 @@ namespace BotSharp.PizzaBot.MCPServer
|
||||||
{
|
{
|
||||||
["pizza_type"] = new JsonSchemaProperty() { Type = "string", Description = "The pizza type." },
|
["pizza_type"] = new JsonSchemaProperty() { Type = "string", Description = "The pizza type." },
|
||||||
["quantity"] = new JsonSchemaProperty() { Type = "number", Description = "quantity of pizza." },
|
["quantity"] = new JsonSchemaProperty() { Type = "number", Description = "quantity of pizza." },
|
||||||
["unit_price"] = new JsonSchemaProperty() { Type = "number", Description = "unit price" },
|
["unit_price"] = new JsonSchemaProperty() { Type = "number", Description = "pizza unit price" },
|
||||||
|
|
||||||
},
|
},
|
||||||
Required = new List<string>(){"pizza_type", "quantity", "unit_price" }
|
Required = new List<string>(){"pizza_type", "quantity", "unit_price" }
|
||||||
|
|
@ -103,86 +120,98 @@ namespace BotSharp.PizzaBot.MCPServer
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
};
|
},
|
||||||
|
|
||||||
server.CallToolHandler = async (request, cancellationToken) =>
|
CallToolHandler = async (request, cancellationToken) =>
|
||||||
{
|
|
||||||
if (request.Params.Name == "make_payment")
|
|
||||||
{
|
{
|
||||||
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("order_number", out var order_number))
|
if (request.Params.Name == "make_payment")
|
||||||
{
|
{
|
||||||
throw new McpServerException("Missing required argument 'order_number'");
|
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("order_number", out var order_number))
|
||||||
}
|
{
|
||||||
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("total_amount", out var total_amount))
|
throw new McpServerException("Missing required argument 'order_number'");
|
||||||
{
|
}
|
||||||
throw new McpServerException("Missing required argument 'total_amount'");
|
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("total_amount", out var total_amount))
|
||||||
}
|
{
|
||||||
dynamic message = new ExpandoObject();
|
throw new McpServerException("Missing required argument 'total_amount'");
|
||||||
message.Transaction = Guid.NewGuid().ToString();
|
}
|
||||||
message.Status = "Success";
|
//dynamic message = new ExpandoObject();
|
||||||
|
//message.Transaction = Guid.NewGuid().ToString();
|
||||||
|
//message.Status = "Success";
|
||||||
|
|
||||||
// Serialize the message to JSON
|
//// Serialize the message to JSON
|
||||||
var jso = new JsonSerializerOptions() { WriteIndented = true };
|
//var jso = new JsonSerializerOptions() { WriteIndented = true };
|
||||||
var jsonMessage = JsonSerializer.Serialize(message, jso);
|
//var jsonMessage = JsonSerializer.Serialize(message, jso);
|
||||||
|
|
||||||
return new CallToolResponse()
|
return new CallToolResponse()
|
||||||
|
{
|
||||||
|
Content = [new Content() { Text = "Payment proceed successfully. Thank you for your business. Have a great day!", Type = "text" }]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (request.Params.Name == "get_pizza_prices")
|
||||||
{
|
{
|
||||||
Content = [new Content() { Text = jsonMessage, Type = "text" }]
|
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("pizza_type", out var pizza_type))
|
||||||
};
|
{
|
||||||
|
throw new McpServerException("Missing required argument 'pizza_type'");
|
||||||
|
}
|
||||||
|
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("quantity", out var quantity))
|
||||||
|
{
|
||||||
|
throw new McpServerException("Missing required argument 'quantity'");
|
||||||
|
}
|
||||||
|
double unit_price = 0;
|
||||||
|
if(pizza_type.ToString() == "Pepperoni Pizza")
|
||||||
|
{
|
||||||
|
unit_price = 3.2 * (int)quantity;
|
||||||
|
}
|
||||||
|
else if(pizza_type.ToString() == "Cheese Pizza")
|
||||||
|
{
|
||||||
|
unit_price = 3.5 * (int)quantity; ;
|
||||||
|
}
|
||||||
|
else if(pizza_type.ToString() == "Margherita Pizza")
|
||||||
|
{
|
||||||
|
unit_price = 3.8 * (int)quantity; ;
|
||||||
|
}
|
||||||
|
dynamic message = new ExpandoObject();
|
||||||
|
message.unit_price = unit_price;
|
||||||
|
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.Params.Name == "place_an_order")
|
||||||
|
{
|
||||||
|
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("pizza_type", out var pizza_type))
|
||||||
|
{
|
||||||
|
throw new McpServerException("Missing required argument 'pizza_type'");
|
||||||
|
}
|
||||||
|
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("quantity", out var quantity))
|
||||||
|
{
|
||||||
|
throw new McpServerException("Missing required argument 'quantity'");
|
||||||
|
}
|
||||||
|
if (request.Params.Arguments is null || !request.Params.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 = "The order number is P123-01: {order_number = \"P123-01\" }", Type = "text" }]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new McpServerException($"Unknown tool: {request.Params.Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (request.Params.Name == "get_pizza_prices")
|
};
|
||||||
{
|
|
||||||
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("pizza_type", out var pizza_type))
|
|
||||||
{
|
|
||||||
throw new McpServerException("Missing required argument 'pizza_type'");
|
|
||||||
}
|
|
||||||
if (request.Params.Arguments is null || !request.Params.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.Params.Name == "place_an_order")
|
|
||||||
{
|
|
||||||
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("pizza_type", out var pizza_type))
|
|
||||||
{
|
|
||||||
throw new McpServerException("Missing required argument 'pizza_type'");
|
|
||||||
}
|
|
||||||
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("quantity", out var quantity))
|
|
||||||
{
|
|
||||||
throw new McpServerException("Missing required argument 'quantity'");
|
|
||||||
}
|
|
||||||
if (request.Params.Arguments is null || !request.Params.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.Params.Name}");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static ILoggerFactory CreateLoggerFactory()
|
private static ILoggerFactory CreateLoggerFactory()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Ordering",
|
"name": "Ordering",
|
||||||
"description": "Provide types of pizza available, unit price, total cost and place the order.",
|
"description": "Provide types of pizza available, pizza unit price, total cost and place the order.",
|
||||||
"createdDateTime": "2023-07-26T02:29:25.123224Z",
|
"createdDateTime": "2023-07-26T02:29:25.123224Z",
|
||||||
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
|
"updatedDateTime": "2023-07-26T02:29:25.123274Z",
|
||||||
"id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd",
|
"id": "c2b57a74-ae4e-4c81-b3ad-9ac5bff982bd",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue