-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathBSOChatBot_MCP.cs
More file actions
141 lines (124 loc) · 5.15 KB
/
BSOChatBot_MCP.cs
File metadata and controls
141 lines (124 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
[ACMethodInfo("MCP", "en{'Connect MCP'}de{'MCP verbinden'}", 102,
Description = @"A connection is established to the configured MCP servers.
This method is asynchronous and must wait until the connections are established, which is signaled by the McpConnected property.
This method mustn't be called explicitly. It is called implicitly with the first call of SendMessage.")]
public async Task ConnectMCP()
{
try
{
// Initialize MCP clients dictionary if needed
if (_McpClients == null)
_McpClients = new Dictionary<string, IMcpClient>();
// Parse the JSON configuration
McpServerConfig config;
try
{
string configJson = !string.IsNullOrEmpty(MCPServerConfigFromFile) ? MCPServerConfigFromFile : MCPServerConfig;
config = JsonSerializer.Deserialize<McpServerConfig>(configJson);
if (config?.mcpServers == null || config.mcpServers.Count == 0)
{
ChatOutput = "No MCP servers configured in JSON config";
return;
}
}
catch (JsonException ex)
{
ChatOutput = $"Error parsing MCP server configuration JSON: {ex.Message}";
return;
}
// Clear existing connections properly
await DisconnectMCP().ConfigureAwait(false);
// Ensure AI clients are initialized
if (_CurrentChatClient == null)
EnsureAIClientsInitialized();
int totalTools = 0;
var connectedServers = new List<string>();
// Create MCP client with sampling capability
var samplingHandler = _CurrentChatClient?.CreateSamplingHandler();
var clientOptions = new McpClientOptions
{
Capabilities = new ClientCapabilities
{
Sampling = samplingHandler != null ? new SamplingCapability { SamplingHandler = samplingHandler } : null
}
};
// Connect to each MCP server with proper error handling
var connectionTasks = new List<Task>();
var connectionResults = new ConcurrentBag<(string serverName, IMcpClient client, List<AITool> tools, Exception error)>();
foreach (var serverEntry in config.mcpServers)
{
string serverName = serverEntry.Key;
McpServerInfo serverInfo = serverEntry.Value;
var connectionTask = ConnectToSingleServer(serverName, serverInfo, clientOptions, connectionResults);
connectionTasks.Add(connectionTask);
}
// Wait for all connections to complete
await Task.WhenAll(connectionTasks).ConfigureAwait(false);
// Process results
foreach (var result in connectionResults)
{
if (result.error == null && result.client != null)
{
_McpClients[result.serverName] = result.client;
AvailableTools.AddRange(result.tools);
totalTools += result.tools.Count;
connectedServers.Add($"{result.serverName} ({result.tools.Count} tools)");
}
else
{
ChatOutput += $"Failed to connect to MCP server '{result.serverName}': {result.error?.Message}\n";
}
}
// Update connection status
if (_McpClients.Count > 0)
{
McpConnected = true;
ChatOutput = $"Connected to {_McpClients.Count} MCP server(s): {string.Join(", ", connectedServers)}. Total {totalTools} tools available.";
// Populate the AvailableToolsWithSelection list after loading tools
PopulateToolsWithSelection();
}
else
{
McpConnected = false;
ChatOutput = "Failed to connect to any MCP servers.";
}
OnPropertyChanged(nameof(AvailableTools));
OnPropertyChanged(nameof(AvailableToolsNames));
}
catch (Exception ex)
{
McpConnected = false;
ChatOutput = $"Error connecting MCP clients: {ex.Message}";
}
}
private async Task ConnectToSingleServer(
string serverName,
McpServerInfo serverInfo,
McpClientOptions clientOptions,
ConcurrentBag<(string serverName, IMcpClient client, List<AITool> tools, Exception error)> results)
{
try
{
// Create stdio transport for MCP server
var transport = new StdioClientTransport(new StdioClientTransportOptions
{
Command = serverInfo.command,
Arguments = serverInfo.args ?? new string[0],
Name = serverName,
}, _LoggerFactory);
// Connect to MCP server with timeout
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); // 30-second timeout
var mcpClient = await McpClientFactory.CreateAsync(
transport,
clientOptions,
_LoggerFactory,
cts.Token).ConfigureAwait(false);
// Get available tools from this server
var tools = await mcpClient.ListToolsAsync(cts.Token).ConfigureAwait(false);
results.Add((serverName, mcpClient, tools.ToList(), null));
}
catch (Exception ex)
{
results.Add((serverName, null, new List<AITool>(), ex));
}
}