actions.ts 5.7 KB

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