Skip to content

Feat/mcp integration #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions Examples/Examples/Mcp/McpAgentsExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Examples.Utils;
using MaIN.Core.Hub;
using MaIN.Core.Hub.Utils;
using MaIN.Domain.Configuration;
using MaIN.Domain.Entities;

namespace Examples;

public class McpAgentsExample : IExample
{
public async Task Start()
{
Console.WriteLine("McpClientExample is running!");

AIHub.Extensions.DisableLLamaLogs();
var contextSecond = await AIHub.Agent()
.WithModel("qwq:7b")
.WithInitialPrompt("Your main role is to provide opinions about facts that you are given in a conversation.")
.CreateAsync(interactiveResponse: true);

var context = await AIHub.Agent()
.WithBackend(BackendType.OpenAi)
.WithMcpConfig(new Mcp
{
Name = "GitHub",
Arguments = ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
EnvironmentVariables = new Dictionary<string, string>()
{
{"GITHUB_PERSONAL_ACCESS_TOKEN", "<YOUR_GITHUB_TOKEN>"}
},
Command = "docker",
Model = "gpt-4o-mini"
})
.WithModel("gpt-4o-mini")
.WithSteps(StepBuilder.Instance
.Mcp()
.Redirect(agentId: contextSecond.GetAgentId())
.Build())
.CreateAsync();

await context.ProcessAsync("What are recently added features in https://github.com/wisedev-code/MaIN.NET (based on recently closed issues)", translate: true);
}
}
29 changes: 29 additions & 0 deletions Examples/Examples/Mcp/McpExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Examples.Utils;
using MaIN.Core.Hub;
using MaIN.Domain.Configuration;
using MaIN.Domain.Entities;

namespace Examples;

public class McpExample : IExample
{
public async Task Start()
{
Console.WriteLine("McpClientExample is running!");
OpenAiExample.Setup();

var result = await AIHub.Mcp()
.WithBackend(BackendType.OpenAi)
.WithConfig(
new Mcp
{
Name = "McpEverythingDemo",
Arguments = ["-y", "@modelcontextprotocol/server-everything"],
Command = "npx",
Model = "gpt-4o-mini"
})
.PromptAsync("Provide me information about resource 21 and 37. Also explain how you get this data");

Console.WriteLine(result.Message.Content);
}
}
53 changes: 28 additions & 25 deletions Examples/Examples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
static void RegisterExamples(IServiceCollection services)
{
services.AddTransient<ExampleRegistry>();
services.AddTransient<McpExample>();
services.AddTransient<ChatExample>();
services.AddTransient<ChatWithFilesExample>();
services.AddTransient<ChatWithFilesFromStreamExample>();
Expand All @@ -51,6 +52,7 @@ static void RegisterExamples(IServiceCollection services)
services.AddTransient<AgentConversationExample>();
services.AddTransient<AgentWithRedirectExample>();
services.AddTransient<MultiBackendAgentWithRedirectExample>();
services.AddTransient<McpAgentsExample>();
services.AddTransient<AgentWithRedirectImageExample>();
services.AddTransient<AgentWithBecomeExample>();
services.AddTransient<AgentWithApiDataSourceExample>();
Expand Down Expand Up @@ -120,35 +122,36 @@ async Task RunSelectedExample(IServiceProvider serviceProvider)

public class ExampleRegistry(IServiceProvider serviceProvider)
{
private readonly IServiceProvider _serviceProvider = serviceProvider;

public List<(string Name, IExample Instance)> GetAvailableExamples()
{
return new List<(string, IExample)>
{
("\u25a0 Basic Chat", _serviceProvider.GetRequiredService<ChatExample>()),
("\u25a0 Chat with Files", _serviceProvider.GetRequiredService<ChatWithFilesExample>()),
("\u25a0 Chat with Files from stream", _serviceProvider.GetRequiredService<ChatWithFilesFromStreamExample>()),
("\u25a0 Chat with Vision", _serviceProvider.GetRequiredService<ChatWithVisionExample>()),
("\u25a0 Chat with Image Generation", _serviceProvider.GetRequiredService<ChatWithImageGenExample>()),
("\u25a0 Chat from Existing", _serviceProvider.GetRequiredService<ChatFromExistingExample>()),
("\u25a0 Chat with reasoning", _serviceProvider.GetRequiredService<ChatWithReasoningExample>()),
("\u25a0 Basic Agent", _serviceProvider.GetRequiredService<AgentExample>()),
("\u25a0 Conversation Agent", _serviceProvider.GetRequiredService<AgentConversationExample>()),
("\u25a0 Agent with Redirect", _serviceProvider.GetRequiredService<AgentWithRedirectExample>()),
("\u25a0 Agent with Redirect (Multi backends)", _serviceProvider.GetRequiredService<MultiBackendAgentWithRedirectExample>()),
("\u25a0 Agent with Redirect Image", _serviceProvider.GetRequiredService<AgentWithRedirectImageExample>()),
("\u25a0 Agent with Become", _serviceProvider.GetRequiredService<AgentWithBecomeExample>()),
("\u25a0 Agent with API Data Source", _serviceProvider.GetRequiredService<AgentWithApiDataSourceExample>()),
("\u25a0 Agents Talking to Each Other", _serviceProvider.GetRequiredService<AgentTalkingToEachOtherExample>()),
("\u25a0 Agents Composed as Flow", _serviceProvider.GetRequiredService<AgentsComposedAsFlowExample>()),
("\u25a0 Agents Flow Loaded", _serviceProvider.GetRequiredService<AgentsFlowLoadedExample>()),
("\u25a0 OpenAi Chat", _serviceProvider.GetRequiredService<ChatExampleOpenAi>()),
("\u25a0 OpenAi Chat with image", _serviceProvider.GetRequiredService<ChatWithImageGenOpenAiExample>()),
("\u25a0 OpenAi Agent with Web Data Source", _serviceProvider.GetRequiredService<AgentWithWebDataSourceOpenAiExample>()),
("\u25a0 Gemini Chat", _serviceProvider.GetRequiredService<ChatExampleGemini>()),
("\u25a0 Gemini Chat with image", _serviceProvider.GetRequiredService<ChatWithImageGenGeminiExample>()),
("\u25a0 Gemini Chat with files", _serviceProvider.GetRequiredService<ChatWithFilesExampleGemini>()),
("\u25a0 Basic Chat", serviceProvider.GetRequiredService<ChatExample>()),
("\u25a0 Chat with Files", serviceProvider.GetRequiredService<ChatWithFilesExample>()),
("\u25a0 Chat with Files from stream", serviceProvider.GetRequiredService<ChatWithFilesFromStreamExample>()),
("\u25a0 Chat with Vision", serviceProvider.GetRequiredService<ChatWithVisionExample>()),
("\u25a0 Chat with Image Generation", serviceProvider.GetRequiredService<ChatWithImageGenExample>()),
("\u25a0 Chat from Existing", serviceProvider.GetRequiredService<ChatFromExistingExample>()),
("\u25a0 Chat with reasoning", serviceProvider.GetRequiredService<ChatWithReasoningExample>()),
("\u25a0 Basic Agent", serviceProvider.GetRequiredService<AgentExample>()),
("\u25a0 Conversation Agent", serviceProvider.GetRequiredService<AgentConversationExample>()),
("\u25a0 Agent with Redirect", serviceProvider.GetRequiredService<AgentWithRedirectExample>()),
("\u25a0 Agent with Redirect (Multi backends)", serviceProvider.GetRequiredService<MultiBackendAgentWithRedirectExample>()),
("\u25a0 Agent with Redirect Image", serviceProvider.GetRequiredService<AgentWithRedirectImageExample>()),
("\u25a0 Agent with Become", serviceProvider.GetRequiredService<AgentWithBecomeExample>()),
("\u25a0 Agent with API Data Source", serviceProvider.GetRequiredService<AgentWithApiDataSourceExample>()),
("\u25a0 Agents Talking to Each Other", serviceProvider.GetRequiredService<AgentTalkingToEachOtherExample>()),
("\u25a0 Agents Composed as Flow", serviceProvider.GetRequiredService<AgentsComposedAsFlowExample>()),
("\u25a0 Agents Flow Loaded", serviceProvider.GetRequiredService<AgentsFlowLoadedExample>()),
("\u25a0 OpenAi Chat", serviceProvider.GetRequiredService<ChatExampleOpenAi>()),
("\u25a0 OpenAi Chat with image", serviceProvider.GetRequiredService<ChatWithImageGenOpenAiExample>()),
("\u25a0 OpenAi Agent with Web Data Source", serviceProvider.GetRequiredService<AgentWithWebDataSourceOpenAiExample>()),
("\u25a0 Gemini Chat", serviceProvider.GetRequiredService<ChatExampleGemini>()),
("\u25a0 Gemini Chat with image", serviceProvider.GetRequiredService<ChatWithImageGenGeminiExample>()),
("\u25a0 Gemini Chat with files", serviceProvider.GetRequiredService<ChatWithFilesExampleGemini>()),
("\u25a0 McpClient example", serviceProvider.GetRequiredService<McpExample>()),
("\u25a0 McpAgent example", serviceProvider.GetRequiredService<McpAgentsExample>())

};
}
}
6 changes: 6 additions & 0 deletions Releases/0.2.3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# 0.2.3 release

- Added Mcp integration
- Include examples and documentation
- McpContext for simple integration
- MCP as AgentStep to allow advanced workflows
2 changes: 1 addition & 1 deletion src/MaIN.Core/.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package>
<metadata>
<id>MaIN.NET</id>
<version>0.2.2</version>
<version>0.2.3</version>
<authors>Wisedev</authors>
<owners>Wisedev</owners>
<icon>favicon.png</icon>
Expand Down
6 changes: 4 additions & 2 deletions src/MaIN.Core/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ public static IServiceCollection AddAIHub(this IServiceCollection services)
services.AddSingleton<IChatService, ChatService>();
services.AddSingleton<IAgentService, AgentService>();
services.AddSingleton<IAgentFlowService, AgentFlowService>();

services.AddSingleton<IMcpService, McpService>();

// Register service provider for AIHub
services.AddSingleton<IAIHubServices>(sp =>
{
var aiServices = new AIHubServices(
sp.GetRequiredService<IChatService>(),
sp.GetRequiredService<IAgentService>(),
sp.GetRequiredService<IAgentFlowService>()
sp.GetRequiredService<IAgentFlowService>(),
sp.GetRequiredService<IMcpService>()
);

// Initialize AIHub with the services
Expand Down
1 change: 1 addition & 0 deletions src/MaIN.Core/Hub/AiHub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ internal static void Initialize(IAIHubServices services)
public static ChatContext Chat() => new(Services.ChatService);
public static AgentContext Agent() => new(Services.AgentService);
public static FlowContext Flow() => new(Services.FlowService, Services.AgentService);
public static McpContext Mcp() => new(Services.McpService);

public abstract class Extensions
{
Expand Down
10 changes: 10 additions & 0 deletions src/MaIN.Core/Hub/Contexts/AgentContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ public AgentContext WithModel(string model)
return this;
}

public AgentContext WithMcpConfig(Mcp mcpConfig)
{
if (_agent.Backend != null)
{
mcpConfig.Backend = _agent.Backend;
}
_agent.Context.McpConfig = mcpConfig;
return this;
}

public AgentContext WithInferenceParams(InferenceParams inferenceParams)
{
_inferenceParams = inferenceParams;
Expand Down
42 changes: 42 additions & 0 deletions src/MaIN.Core/Hub/Contexts/McpContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

using MaIN.Domain.Configuration;
using MaIN.Domain.Entities;
using MaIN.Services.Services;
using MaIN.Services.Services.Abstract;
using MaIN.Services.Services.Models;

namespace MaIN.Core.Hub.Contexts;

public class McpContext
{
private readonly IMcpService _mcpService;
private Mcp? _mcpConfig;

internal McpContext(IMcpService mcpService)
{
_mcpService = mcpService;
_mcpConfig = Mcp.NotSet;
}

public McpContext WithConfig(Mcp mcpConfig)
{
_mcpConfig = mcpConfig;
return this;
}

public McpContext WithBackend(BackendType backendType)
{
_mcpConfig!.Backend = backendType;
return this;
}

public async Task<McpResult> PromptAsync(string prompt)
{
if (_mcpConfig == null)
{
throw new InvalidOperationException("MCP config not found");
}

return await _mcpService.Prompt(_mcpConfig!, prompt);
}
}
7 changes: 7 additions & 0 deletions src/MaIN.Core/Hub/Utils/StepBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ public StepBuilder FetchData(FetchResponseType fetchResponseType = FetchResponse
Steps.Add(stepToAdd);
return this;
}

public StepBuilder Mcp()
{
var stepToAdd = "MCP";
Steps.Add(stepToAdd);
return this;
}

public StepBuilder Redirect(string agentId, string output = "AS_Output", string mode = "REPLACE")
{
Expand Down
2 changes: 2 additions & 0 deletions src/MaIN.Core/Interfaces/IAIHubService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using MaIN.Services.Services;
using MaIN.Services.Services.Abstract;

namespace MaIN.Core.Interfaces;
Expand All @@ -7,4 +8,5 @@ public interface IAIHubServices
IChatService ChatService { get; }
IAgentService AgentService { get; }
IAgentFlowService FlowService { get; }
IMcpService McpService { get; }
}
6 changes: 5 additions & 1 deletion src/MaIN.Core/Services/AIHubService.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
using MaIN.Core.Interfaces;
using MaIN.Services.Services;
using MaIN.Services.Services.Abstract;

namespace MaIN.Core.Services;

public class AIHubServices(
IChatService chatService,
IAgentService agentService,
IAgentFlowService flowService)
IAgentFlowService flowService,
IMcpService mcpService)
: IAIHubServices
{
public IChatService ChatService { get; } = chatService;
public IAgentService AgentService { get; } = agentService;
public IAgentFlowService FlowService { get; } = flowService;

public IMcpService McpService { get; } = mcpService;
}
1 change: 1 addition & 0 deletions src/MaIN.Domain/Entities/Agents/AgentData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public class AgentData
{
public string? Instruction { get; set; }
public AgentSource.AgentSource? Source { get; set; }
public Mcp? McpConfig { get; set; }
public List<string>? Steps { get; set; }
public List<string>? Relations { get; set; }

Expand Down
24 changes: 24 additions & 0 deletions src/MaIN.Domain/Entities/Mcp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using MaIN.Domain.Configuration;

namespace MaIN.Domain.Entities;

public class Mcp
{
public required string Name { get; init; }
public required List<string> Arguments { get; init; }
public required string Command { get; init; }
public required string Model { get; init; }
public Dictionary<string, string> Properties { get; set; } = [];
public BackendType? Backend { get; set; }
public Dictionary<string, string> EnvironmentVariables { get; set; } = [];

public static Mcp NotSet => new Mcp()
{
Arguments = [],
Command = string.Empty,
Model = string.Empty,
Properties = new Dictionary<string, string>(),
Name = string.Empty,
Backend = BackendType.Self
};
}
2 changes: 2 additions & 0 deletions src/MaIN.Infrastructure/Models/AgentContextDocument.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using MaIN.Domain.Entities;
using MaIN.Models.Rag;

namespace MaIN.Infrastructure.Models;
Expand All @@ -8,4 +9,5 @@ public class AgentContextDocument
public AgentSourceDocument? Source { get; init; }
public List<string>? Steps { get; init; }
public List<string>? Relations { get; init; }
public Mcp? McpConfig { get; set; }
}
4 changes: 4 additions & 0 deletions src/MaIN.Services/Bootstrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static IServiceCollection ConfigureMaIN(
serviceCollection.AddSingleton<IStepHandler, RedirectStepHandler>();
serviceCollection.AddSingleton<IStepHandler, FetchDataStepHandler>();
serviceCollection.AddSingleton<IStepHandler, AnswerStepHandler>();
serviceCollection.AddSingleton<IStepHandler, McpStepHandler>();
serviceCollection.AddSingleton<IStepHandler, BecomeStepHandler>();
serviceCollection.AddSingleton<IStepHandler, CleanupStepHandler>();
serviceCollection.AddCommandHandlers();
Expand All @@ -72,11 +73,13 @@ private static IServiceCollection AddCommandHandlers(this IServiceCollection ser
services.AddSingleton<ICommandHandler<RedirectCommand, Message?>, RedirectCommandHandler>();
services.AddSingleton<ICommandHandler<FetchCommand, Message?>, FetchCommandHandler>();
services.AddSingleton<ICommandHandler<AnswerCommand, Message?>, AnswerCommandHandler>();
services.AddSingleton<ICommandHandler<McpCommand, Message?>, McpCommandHandler>();

services.AddSingleton<ICommandDispatcher, CommandDispatcher>(provider =>
{
var dispatcher = new CommandDispatcher(provider);

dispatcher.RegisterNamedHandler<McpCommand, Message?, McpCommandHandler>("MCP");
dispatcher.RegisterNamedHandler<StartCommand, Message?, StartCommandHandler>("START");
dispatcher.RegisterNamedHandler<RedirectCommand, Message?, RedirectCommandHandler>("REDIRECT");
dispatcher.RegisterNamedHandler<FetchCommand, Message?, FetchCommandHandler>("FETCH_DATA");
Expand All @@ -90,6 +93,7 @@ private static IServiceCollection AddCommandHandlers(this IServiceCollection ser
services.AddSingleton<RedirectCommandHandler>();
services.AddSingleton<FetchCommandHandler>();
services.AddSingleton<AnswerCommandHandler>();
services.AddSingleton<McpCommandHandler>();

return services;
}
Expand Down
3 changes: 2 additions & 1 deletion src/MaIN.Services/MaIN.Services.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.3" />
<PackageReference Include="Microsoft.KernelMemory" Version="0.98.250324.1" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.49.0" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.48.0-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Google" Version="1.33.0-alpha" />
<PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.2.0-preview.1" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="Tesseract" Version="5.2.0" />
<PackageReference Include="Tesseract.Data.English" Version="4.0.0" />
Expand Down
Loading