增强异常捕获能力,减少闪退
This commit is contained in:
parent
c61938383b
commit
660ba2ad53
375
host/Gateway.cs
375
host/Gateway.cs
@ -239,17 +239,25 @@ public class Gateway
|
||||
api_key = "sk-db177155677e438f832860e7f4da6afc"
|
||||
};
|
||||
List<Message> messages = new List<Message>();
|
||||
string toolInfos = await GetToolInfos(new McpServerList());
|
||||
messages.Add(new Message
|
||||
string toolInfos = "";
|
||||
try
|
||||
{
|
||||
Role = "system",
|
||||
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos)
|
||||
});
|
||||
messages.Add(new Message
|
||||
toolInfos = await GetToolInfos(new McpServerList());
|
||||
messages.Add(new Message
|
||||
{
|
||||
Role = "system",
|
||||
Content = SystemPrompt.SysPrompt(gdbPath, toolInfos)
|
||||
});
|
||||
messages.Add(new Message
|
||||
{
|
||||
Role = "user",
|
||||
Content = message
|
||||
});
|
||||
}catch (Exception ex)
|
||||
{
|
||||
Role = "user",
|
||||
Content = message
|
||||
});
|
||||
log.Error(ex);
|
||||
MessageBox.Show(ex.Message,"获取MCP列表失败");
|
||||
}
|
||||
goOn = true;
|
||||
string toolPattern = "<tool_use>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/tool_use>";
|
||||
string promptPattern = "<prompt>([\\s\\S]*?)<name>([\\s\\S]*?)<\\/name>([\\s\\S]*?)<arguments>([\\s\\S]*?)<\\/arguments>([\\s\\S]*?)<\\/prompt>";
|
||||
@ -282,56 +290,106 @@ public class Gateway
|
||||
{
|
||||
//如果本次回复不包含任何工具的调用或提示词的调用,则不再请求
|
||||
goOn = false;
|
||||
MessageListItem endMessageListItem1 = new ChatMessageItem
|
||||
MessageListItem endMessageListItem1 = new ChatMessageItem
|
||||
{
|
||||
type = MessageType.END_TAG,
|
||||
content = "",
|
||||
id = (timestamp+3).ToString(),
|
||||
id = (timestamp + 3).ToString(),
|
||||
role = "assistant"
|
||||
};
|
||||
callback?.Invoke(endMessageListItem1);
|
||||
break;
|
||||
}
|
||||
await foreach(LlmStreamChat llmStreamChat in bailian.SendChatStreamAsync(jsonContent))
|
||||
{
|
||||
if (!goOn)
|
||||
{
|
||||
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||
{
|
||||
type = MessageType.END_TAG,
|
||||
content = "",
|
||||
id = (timestamp+3).ToString(),
|
||||
role = "assistant"
|
||||
};
|
||||
callback?.Invoke(endMessageListItem2);
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
await foreach(LlmStreamChat llmStreamChat in bailian.SendChatStreamAsync(jsonContent))
|
||||
{
|
||||
string chunk = llmStreamChat.Choices[0].Delta.Content;
|
||||
MessageListItem reasonMessageListItem = new ChatMessageItem()
|
||||
if (!goOn)
|
||||
{
|
||||
content = llmStreamChat.Choices[0].Delta.ResoningContent,
|
||||
role = "assistant",
|
||||
type = MessageType.REASON_MESSAGE,
|
||||
id = (timestamp+2).ToString()
|
||||
};
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
callback?.Invoke(reasonMessageListItem);
|
||||
});
|
||||
messageContent = chunk;
|
||||
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
|
||||
if (matched == "")
|
||||
{
|
||||
var (matchedPrompt, remainingPrompt) = ExtractMatchedPart(chunk, promptPattern);
|
||||
if (matchedPrompt == "")
|
||||
MessageListItem endMessageListItem2 = new ChatMessageItem
|
||||
{
|
||||
//普通消息文本
|
||||
type = MessageType.END_TAG,
|
||||
content = "",
|
||||
id = (timestamp+3).ToString(),
|
||||
role = "assistant"
|
||||
};
|
||||
callback?.Invoke(endMessageListItem2);
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string chunk = llmStreamChat.Choices[0].Delta.Content;
|
||||
MessageListItem reasonMessageListItem = new ChatMessageItem()
|
||||
{
|
||||
content = llmStreamChat.Choices[0].Delta.ResoningContent,
|
||||
role = "assistant",
|
||||
type = MessageType.REASON_MESSAGE,
|
||||
id = (timestamp+2).ToString()
|
||||
};
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
callback?.Invoke(reasonMessageListItem);
|
||||
});
|
||||
messageContent = chunk;
|
||||
var (matched, remaining) = ExtractMatchedPart(chunk, toolPattern);
|
||||
if (matched == "")
|
||||
{
|
||||
var (matchedPrompt, remainingPrompt) = ExtractMatchedPart(chunk, promptPattern);
|
||||
if (matchedPrompt == "")
|
||||
{
|
||||
//普通消息文本
|
||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||
{
|
||||
content = remainingPrompt,
|
||||
role = "assistant",
|
||||
type = MessageType.CHAT_MESSAGE,
|
||||
id = timestamp.ToString()
|
||||
};
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
callback?.Invoke(chatMessageListItem);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
//包含Prompt调用请求的消息
|
||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||
{
|
||||
content = remainingPrompt,
|
||||
role = "assistant",
|
||||
type = MessageType.CHAT_MESSAGE,
|
||||
id = timestamp.ToString()
|
||||
};
|
||||
callback?.Invoke(chatMessageListItem);
|
||||
XElement promptUse = XElement.Parse(matchedPrompt);
|
||||
string promptKey = promptUse.Element("name")?.Value;
|
||||
string promptArgs = promptUse.Element("arguments")?.Value;
|
||||
Dictionary<string, string> promptParams = JsonConvert.DeserializeObject<Dictionary<string, string>>(promptArgs);
|
||||
promptRequests = new List<PromptRequest>();
|
||||
promptRequests.Add(new PromptRequest()
|
||||
{
|
||||
PromptName = promptKey,
|
||||
PromptArgs = promptParams,
|
||||
PromptServer = promptServerList.GetPromptServer(promptKey)
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//包含工具调用请求的消息
|
||||
XElement toolUse = XElement.Parse(matched);
|
||||
string fullToolName = toolUse.Element("name")?.Value;
|
||||
string toolArgs = toolUse.Element("arguments")?.Value;
|
||||
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
|
||||
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
|
||||
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
|
||||
McpServer mcpServer = mcpServerList.GetServer(serverName);
|
||||
//将工具调用请求添加至列表中待一次回答完整后再统一进行调用
|
||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||
{
|
||||
content = remainingPrompt,
|
||||
content = remaining,
|
||||
role = "assistant",
|
||||
type = MessageType.CHAT_MESSAGE,
|
||||
id = timestamp.ToString()
|
||||
@ -340,84 +398,43 @@ public class Gateway
|
||||
{
|
||||
callback?.Invoke(chatMessageListItem);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
//包含Prompt调用请求的消息
|
||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||
MessageListItem toolMessageListItem = new ToolMessageItem()
|
||||
{
|
||||
content = remainingPrompt,
|
||||
role = "assistant",
|
||||
type = MessageType.CHAT_MESSAGE,
|
||||
id = timestamp.ToString()
|
||||
content = "",
|
||||
result = "",
|
||||
toolName = toolName,
|
||||
toolParams = toolParams,
|
||||
role = "user",
|
||||
type = MessageType.TOOL_MESSAGE,
|
||||
id = (timestamp+1).ToString(),
|
||||
status = "loading"
|
||||
};
|
||||
callback?.Invoke(chatMessageListItem);
|
||||
XElement promptUse = XElement.Parse(matchedPrompt);
|
||||
string promptKey = promptUse.Element("name")?.Value;
|
||||
string promptArgs = promptUse.Element("arguments")?.Value;
|
||||
Dictionary<string, string> promptParams = JsonConvert.DeserializeObject<Dictionary<string, string>>(promptArgs);
|
||||
promptRequests = new List<PromptRequest>();
|
||||
promptRequests.Add(new PromptRequest()
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
PromptName = promptKey,
|
||||
PromptArgs = promptParams,
|
||||
PromptServer = promptServerList.GetPromptServer(promptKey)
|
||||
callback?.Invoke(toolMessageListItem);
|
||||
});
|
||||
mcpToolRequests = new List<McpToolRequest>();
|
||||
McpToolRequest mcpToolRequest = new McpToolRequest()
|
||||
{
|
||||
McpServer = mcpServer,
|
||||
ToolName = toolName,
|
||||
ToolArgs = toolParams,
|
||||
};
|
||||
mcpToolRequests.Add(mcpToolRequest);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
//包含工具调用请求的消息
|
||||
XElement toolUse = XElement.Parse(matched);
|
||||
string fullToolName = toolUse.Element("name")?.Value;
|
||||
string toolArgs = toolUse.Element("arguments")?.Value;
|
||||
Dictionary<string, object> toolParams = JsonConvert.DeserializeObject<Dictionary<string, object>>(toolArgs);
|
||||
string serverName = fullToolName.Contains(":") ? fullToolName.Split(':')[0] : fullToolName;
|
||||
string toolName = fullToolName.Contains(":") ? fullToolName.Split(':')[1] : fullToolName;
|
||||
McpServer mcpServer = mcpServerList.GetServer(serverName);
|
||||
//将工具调用请求添加至列表中待一次回答完整后再统一进行调用
|
||||
MessageListItem chatMessageListItem = new ChatMessageItem()
|
||||
{
|
||||
content = remaining,
|
||||
role = "assistant",
|
||||
type = MessageType.CHAT_MESSAGE,
|
||||
id = timestamp.ToString()
|
||||
};
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
callback?.Invoke(chatMessageListItem);
|
||||
});
|
||||
MessageListItem toolMessageListItem = new ToolMessageItem()
|
||||
{
|
||||
content = "",
|
||||
result = "",
|
||||
toolName = toolName,
|
||||
toolParams = toolParams,
|
||||
role = "user",
|
||||
type = MessageType.TOOL_MESSAGE,
|
||||
id = (timestamp+1).ToString(),
|
||||
status = "loading"
|
||||
};
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
callback?.Invoke(toolMessageListItem);
|
||||
});
|
||||
mcpToolRequests = new List<McpToolRequest>();
|
||||
McpToolRequest mcpToolRequest = new McpToolRequest()
|
||||
{
|
||||
McpServer = mcpServer,
|
||||
ToolName = toolName,
|
||||
ToolArgs = toolParams,
|
||||
};
|
||||
mcpToolRequests.Add(mcpToolRequest);
|
||||
Console.WriteLine(e);
|
||||
log.Error(e.Message);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
log.Error(e.Message);
|
||||
}
|
||||
}catch (Exception e)
|
||||
{
|
||||
log.Error(e.Message);
|
||||
MessageBox.Show(e.Message, "请求大模型出错");
|
||||
}
|
||||
|
||||
if (messageContent != "")
|
||||
{
|
||||
messages.Add(new Message
|
||||
@ -616,85 +633,97 @@ public class Gateway
|
||||
StringBuilder toolInfos = new StringBuilder();
|
||||
foreach (McpServer mcpServer in mcpServerList.GetAllServers())
|
||||
{
|
||||
log.Info($"正在列出{mcpServer.Name}中的工具");
|
||||
if (mcpServer is InnerMcpServer)
|
||||
try
|
||||
{
|
||||
InnerMcpServer innerMcpServer = (InnerMcpServer)mcpServer;
|
||||
Type type = Type.GetType("LinkToolAddin.client.tool." + innerMcpServer.Name);
|
||||
MethodInfo[] methods = type.GetMethods();
|
||||
foreach (MethodInfo method in methods)
|
||||
if (mcpServer is InnerMcpServer)
|
||||
{
|
||||
if (method.IsPublic && method.IsStatic)
|
||||
InnerMcpServer innerMcpServer = (InnerMcpServer)mcpServer;
|
||||
Type type = Type.GetType("LinkToolAddin.client.tool." + innerMcpServer.Name);
|
||||
MethodInfo[] methods = type.GetMethods();
|
||||
foreach (MethodInfo method in methods)
|
||||
{
|
||||
string methodName = method.Name;
|
||||
string methodDescription = method.GetCustomAttribute<DescriptionAttribute>()?.Description;
|
||||
string methodParamSchema = LinkToolAddin.common.JsonSchemaGenerator.GenerateJsonSchema(method);
|
||||
if (method.IsPublic && method.IsStatic)
|
||||
{
|
||||
string methodName = method.Name;
|
||||
string methodDescription = method.GetCustomAttribute<DescriptionAttribute>()?.Description;
|
||||
string methodParamSchema = LinkToolAddin.common.JsonSchemaGenerator.GenerateJsonSchema(method);
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
{
|
||||
Tool = new Tool
|
||||
{
|
||||
Name = innerMcpServer.Name + ":" + methodName,
|
||||
Description = methodDescription,
|
||||
Arguments = methodParamSchema
|
||||
}
|
||||
};
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition));
|
||||
toolInfos.AppendLine(node.ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mcpServer is SseMcpServer)
|
||||
{
|
||||
SseMcpClient client = new SseMcpClient((mcpServer as SseMcpServer).BaseUrl);
|
||||
IList<McpClientTool> tools = await client.GetToolListAsync();
|
||||
foreach (McpClientTool tool in tools)
|
||||
{
|
||||
string toolName = (mcpServer as SseMcpServer).Name + ":" + tool.Name;
|
||||
string toolDescription = tool.Description;
|
||||
string toolParamSchema = tool.JsonSchema.ToString();
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
{
|
||||
Tool = new Tool
|
||||
{
|
||||
Name = innerMcpServer.Name + ":" + methodName,
|
||||
Description = methodDescription,
|
||||
Arguments = methodParamSchema
|
||||
Name = toolName,
|
||||
Description = toolDescription,
|
||||
Arguments = toolParamSchema
|
||||
}
|
||||
};
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition));
|
||||
toolInfos.AppendLine(node.ToString());
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}else if (mcpServer is StdioMcpServer)
|
||||
{
|
||||
StdioMcpClient client = new StdioMcpClient((mcpServer as StdioMcpServer).Command, (mcpServer as StdioMcpServer).Args);
|
||||
IList<McpClientTool> tools = await client.GetToolListAsync();
|
||||
foreach (McpClientTool tool in tools)
|
||||
{
|
||||
string toolName = (mcpServer as StdioMcpServer).Name + ":" + tool.Name;;
|
||||
string toolDescription = tool.Description;
|
||||
string toolParamSchema = tool.JsonSchema.ToString();
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
{
|
||||
Tool = new Tool
|
||||
{
|
||||
Name = toolName,
|
||||
Description = toolDescription,
|
||||
Arguments = CompressJson(toolParamSchema)
|
||||
}
|
||||
};
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mcpServer is SseMcpServer)
|
||||
}catch (Exception e)
|
||||
{
|
||||
SseMcpClient client = new SseMcpClient((mcpServer as SseMcpServer).BaseUrl);
|
||||
IList<McpClientTool> tools = await client.GetToolListAsync();
|
||||
foreach (McpClientTool tool in tools)
|
||||
{
|
||||
string toolName = (mcpServer as SseMcpServer).Name + ":" + tool.Name;
|
||||
string toolDescription = tool.Description;
|
||||
string toolParamSchema = tool.JsonSchema.ToString();
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
{
|
||||
Tool = new Tool
|
||||
{
|
||||
Name = toolName,
|
||||
Description = toolDescription,
|
||||
Arguments = toolParamSchema
|
||||
}
|
||||
};
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
}else if (mcpServer is StdioMcpServer)
|
||||
{
|
||||
StdioMcpClient client = new StdioMcpClient((mcpServer as StdioMcpServer).Command, (mcpServer as StdioMcpServer).Args);
|
||||
IList<McpClientTool> tools = await client.GetToolListAsync();
|
||||
foreach (McpClientTool tool in tools)
|
||||
{
|
||||
string toolName = (mcpServer as StdioMcpServer).Name + ":" + tool.Name;;
|
||||
string toolDescription = tool.Description;
|
||||
string toolParamSchema = tool.JsonSchema.ToString();
|
||||
McpToolDefinition toolDefinition = new McpToolDefinition
|
||||
{
|
||||
Tool = new Tool
|
||||
{
|
||||
Name = toolName,
|
||||
Description = toolDescription,
|
||||
Arguments = CompressJson(toolParamSchema)
|
||||
}
|
||||
};
|
||||
toolInfos.AppendLine(JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(toolDefinition)).ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
log.Error(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
List<UserPrompt> prompts = DynamicPrompt.GetAllPrompts();
|
||||
foreach (UserPrompt userPrompt in prompts)
|
||||
{
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(new PromptDefinition(){UserPrompt = userPrompt}));
|
||||
toolInfos.AppendLine(node.ToString());
|
||||
toolInfos.AppendLine();
|
||||
try
|
||||
{
|
||||
XNode node = JsonConvert.DeserializeXNode(JsonConvert.SerializeObject(new PromptDefinition(){UserPrompt = userPrompt}));
|
||||
toolInfos.AppendLine(node.ToString());
|
||||
toolInfos.AppendLine();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error(e.Message);
|
||||
}
|
||||
}
|
||||
return toolInfos.ToString();
|
||||
}
|
||||
|
||||
@ -35,53 +35,53 @@ public class McpServerList
|
||||
Description = "可以调用进行查询知识库,获取相关参考信息。",
|
||||
IsActive = true
|
||||
});
|
||||
//servers.Add("filesystem", new StdioMcpServer()
|
||||
//{
|
||||
// Name = "filesystem",
|
||||
// Type = "stdio",
|
||||
// Command = "npx",
|
||||
// Args = new List<string>()
|
||||
// {
|
||||
// "-y",
|
||||
// "@modelcontextprotocol/server-filesystem",
|
||||
// "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData"
|
||||
// }
|
||||
//});
|
||||
//servers.Add("fetch", new StdioMcpServer()
|
||||
//{
|
||||
// Name = "fetch",
|
||||
// Type = "stdio",
|
||||
// Command = "uvx",
|
||||
// Args = new List<string>()
|
||||
// {
|
||||
// "mcp-server-fetch"
|
||||
// }
|
||||
//});
|
||||
//servers.Add("bing-search", new StdioMcpServer()
|
||||
//{
|
||||
// Name = "bing-search",
|
||||
// Type = "stdio",
|
||||
// Command = "npx",
|
||||
// Args = new List<string>()
|
||||
// {
|
||||
// "bing-cn-mcp"
|
||||
// }
|
||||
//});
|
||||
//servers.Add("mcp-python-interpreter", new StdioMcpServer()
|
||||
//{
|
||||
// Name = "mcp-python-interpreter",
|
||||
// Type = "stdio",
|
||||
// Command = "uvx",
|
||||
// Args = new List<string>()
|
||||
// {
|
||||
// "--native-tls",
|
||||
// "mcp-python-interpreter",
|
||||
// "--dir",
|
||||
// "D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData",
|
||||
// "--python-path",
|
||||
// "C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe"
|
||||
// }
|
||||
//});
|
||||
servers.Add("filesystem", new StdioMcpServer()
|
||||
{
|
||||
Name = "filesystem",
|
||||
Type = "stdio",
|
||||
Command = "npxh",
|
||||
Args = new List<string>()
|
||||
{
|
||||
"-y",
|
||||
"@modelcontextprotocol/server-filesystem",
|
||||
"D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData"
|
||||
}
|
||||
});
|
||||
servers.Add("fetch", new StdioMcpServer()
|
||||
{
|
||||
Name = "fetch",
|
||||
Type = "stdio",
|
||||
Command = "uvx",
|
||||
Args = new List<string>()
|
||||
{
|
||||
"mcp-server-fetch"
|
||||
}
|
||||
});
|
||||
servers.Add("bing-search", new StdioMcpServer()
|
||||
{
|
||||
Name = "bing-search",
|
||||
Type = "stdio",
|
||||
Command = "npx",
|
||||
Args = new List<string>()
|
||||
{
|
||||
"bing-cn-mcp"
|
||||
}
|
||||
});
|
||||
servers.Add("mcp-python-interpreter", new StdioMcpServer()
|
||||
{
|
||||
Name = "mcp-python-interpreter",
|
||||
Type = "stdio",
|
||||
Command = "uvx",
|
||||
Args = new List<string>()
|
||||
{
|
||||
"--native-tls",
|
||||
"mcp-python-interpreter",
|
||||
"--dir",
|
||||
"D:\\01_Project\\20250305_LinkTool\\20250420_AiDemoProject\\TestData",
|
||||
"--python-path",
|
||||
"C:\\Program Files\\ArcGIS\\Pro\\bin\\Python\\envs\\custom\\python.exe"
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public McpServer GetServer(string name)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user