actions.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. "use server";
  2. import {
  3. createClient,
  4. executeRequest,
  5. listTools,
  6. removeClient,
  7. } from "./client";
  8. import { MCPClientLogger } from "./logger";
  9. import {
  10. DEFAULT_MCP_CONFIG,
  11. McpClientData,
  12. McpConfigData,
  13. McpRequestMessage,
  14. ServerConfig,
  15. } from "./types";
  16. import fs from "fs/promises";
  17. import path from "path";
  18. const logger = new MCPClientLogger("MCP Actions");
  19. const CONFIG_PATH = path.join(process.cwd(), "app/mcp/mcp_config.json");
  20. const clientsMap = new Map<string, McpClientData>();
  21. // 获取客户端状态
  22. export async function getClientStatus(clientId: string) {
  23. const status = clientsMap.get(clientId);
  24. if (!status) return { status: "undefined" as const, errorMsg: null };
  25. return {
  26. status: status.errorMsg ? ("error" as const) : ("active" as const),
  27. errorMsg: status.errorMsg,
  28. };
  29. }
  30. // 获取客户端工具
  31. export async function getClientTools(clientId: string) {
  32. return clientsMap.get(clientId)?.tools ?? null;
  33. }
  34. // 获取可用客户端数量
  35. export async function getAvailableClientsCount() {
  36. let count = 0;
  37. clientsMap.forEach((map) => {
  38. if (!map.errorMsg) {
  39. count += map?.tools?.tools?.length ?? 0;
  40. }
  41. });
  42. return count;
  43. }
  44. // 获取所有客户端工具
  45. export async function getAllTools() {
  46. const result = [];
  47. for (const [clientId, status] of clientsMap.entries()) {
  48. result.push({
  49. clientId,
  50. tools: status.tools,
  51. });
  52. }
  53. return result;
  54. }
  55. // 初始化单个客户端
  56. async function initializeSingleClient(
  57. clientId: string,
  58. serverConfig: ServerConfig,
  59. ) {
  60. logger.info(`Initializing client [${clientId}]...`);
  61. try {
  62. const client = await createClient(clientId, serverConfig);
  63. const tools = await listTools(client);
  64. clientsMap.set(clientId, { client, tools, errorMsg: null });
  65. logger.success(`Client [${clientId}] initialized successfully`);
  66. } catch (error) {
  67. clientsMap.set(clientId, {
  68. client: null,
  69. tools: null,
  70. errorMsg: error instanceof Error ? error.message : String(error),
  71. });
  72. logger.error(`Failed to initialize client [${clientId}]: ${error}`);
  73. }
  74. }
  75. // 初始化系统
  76. export async function initializeMcpSystem() {
  77. logger.info("MCP Actions starting...");
  78. try {
  79. const config = await getMcpConfigFromFile();
  80. // 初始化所有客户端
  81. for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
  82. await initializeSingleClient(clientId, serverConfig);
  83. }
  84. return config;
  85. } catch (error) {
  86. logger.error(`Failed to initialize MCP system: ${error}`);
  87. throw error;
  88. }
  89. }
  90. // 添加服务器
  91. export async function addMcpServer(clientId: string, config: ServerConfig) {
  92. try {
  93. const currentConfig = await getMcpConfigFromFile();
  94. const newConfig = {
  95. ...currentConfig,
  96. mcpServers: {
  97. ...currentConfig.mcpServers,
  98. [clientId]: config,
  99. },
  100. };
  101. await updateMcpConfig(newConfig);
  102. // 只初始化新添加的服务器
  103. await initializeSingleClient(clientId, config);
  104. return newConfig;
  105. } catch (error) {
  106. logger.error(`Failed to add server [${clientId}]: ${error}`);
  107. throw error;
  108. }
  109. }
  110. // 移除服务器
  111. export async function removeMcpServer(clientId: string) {
  112. try {
  113. const currentConfig = await getMcpConfigFromFile();
  114. const { [clientId]: _, ...rest } = currentConfig.mcpServers;
  115. const newConfig = {
  116. ...currentConfig,
  117. mcpServers: rest,
  118. };
  119. await updateMcpConfig(newConfig);
  120. // 关闭并移除客户端
  121. const client = clientsMap.get(clientId);
  122. if (client?.client) {
  123. await removeClient(client.client);
  124. }
  125. clientsMap.delete(clientId);
  126. return newConfig;
  127. } catch (error) {
  128. logger.error(`Failed to remove server [${clientId}]: ${error}`);
  129. throw error;
  130. }
  131. }
  132. // 重启所有客户端
  133. export async function restartAllClients() {
  134. logger.info("Restarting all clients...");
  135. try {
  136. // 关闭所有客户端
  137. for (const client of clientsMap.values()) {
  138. if (client.client) {
  139. await removeClient(client.client);
  140. }
  141. }
  142. // 清空状态
  143. clientsMap.clear();
  144. // 重新初始化
  145. const config = await getMcpConfigFromFile();
  146. for (const [clientId, serverConfig] of Object.entries(config.mcpServers)) {
  147. await initializeSingleClient(clientId, serverConfig);
  148. }
  149. return config;
  150. } catch (error) {
  151. logger.error(`Failed to restart clients: ${error}`);
  152. throw error;
  153. }
  154. }
  155. // 执行 MCP 请求
  156. export async function executeMcpAction(
  157. clientId: string,
  158. request: McpRequestMessage,
  159. ) {
  160. try {
  161. const client = clientsMap.get(clientId);
  162. if (!client?.client) {
  163. throw new Error(`Client ${clientId} not found`);
  164. }
  165. logger.info(`Executing request for [${clientId}]`);
  166. return await executeRequest(client.client, request);
  167. } catch (error) {
  168. logger.error(`Failed to execute request for [${clientId}]: ${error}`);
  169. throw error;
  170. }
  171. }
  172. // 获取 MCP 配置文件
  173. export async function getMcpConfigFromFile(): Promise<McpConfigData> {
  174. try {
  175. const configStr = await fs.readFile(CONFIG_PATH, "utf-8");
  176. return JSON.parse(configStr);
  177. } catch (error) {
  178. logger.error(`Failed to load MCP config, using default config: ${error}`);
  179. return DEFAULT_MCP_CONFIG;
  180. }
  181. }
  182. // 更新 MCP 配置文件
  183. async function updateMcpConfig(config: McpConfigData): Promise<void> {
  184. try {
  185. await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
  186. } catch (error) {
  187. throw error;
  188. }
  189. }
  190. // 重新初始化单个客户端
  191. export async function reinitializeClient(clientId: string) {
  192. const config = await getMcpConfigFromFile();
  193. const serverConfig = config.mcpServers[clientId];
  194. if (!serverConfig) {
  195. throw new Error(`Server config not found for client ${clientId}`);
  196. }
  197. await initializeSingleClient(clientId, serverConfig);
  198. }