refactor(mcp): improve data structure with metadata/spec separation

- Separate MCP server metadata from connection spec for cleaner architecture
- Add comprehensive server entry fields: name, description, tags, homepage, docs
- Remove legacy format compatibility logic from extract_server_spec
- Implement data validation and filtering in get_servers_snapshot_for
- Add strict id consistency check in upsert_in_config_for
- Enhance import logic with defensive programming for corrupted data
- Simplify frontend by removing normalization logic (moved to backend)
- Improve error messages with contextual information
- Add comprehensive i18n support for new metadata fields
This commit is contained in:
Jason
2025-10-12 00:08:37 +08:00
parent 668ab710c6
commit fb137c4a78
14 changed files with 477 additions and 115 deletions

View File

@@ -55,9 +55,19 @@ export const translateMcpBackendError = (
}
if (
msg.includes("MCP 服务器定义必须为 JSON 对象") ||
msg.includes("MCP 服务器条目必须为 JSON 对象") ||
msg.includes("MCP 服务器条目缺少 server 字段") ||
msg.includes("MCP 服务器 server 字段必须为 JSON 对象") ||
msg.includes("MCP 服务器连接定义必须为 JSON 对象") ||
msg.includes("MCP 服务器 '" /* 不是对象 */) ||
msg.includes("不是对象") ||
msg.includes("服务器配置必须是对象")
msg.includes("服务器配置必须是对象") ||
msg.includes("MCP 服务器 name 必须为字符串") ||
msg.includes("MCP 服务器 description 必须为字符串") ||
msg.includes("MCP 服务器 homepage 必须为字符串") ||
msg.includes("MCP 服务器 docs 必须为字符串") ||
msg.includes("MCP 服务器 tags 必须为字符串数组") ||
msg.includes("MCP 服务器 enabled 必须为布尔值")
) {
return t("mcp.error.jsonInvalid");
}

View File

@@ -1,5 +1,5 @@
import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
import { McpServer } from "../types";
import { McpServerSpec } from "../types";
/**
* 验证 TOML 格式并转换为 JSON 对象
@@ -21,10 +21,10 @@ export const validateToml = (text: string): string => {
};
/**
* 将 McpServer 对象转换为 TOML 字符串
* 将 McpServerSpec 对象转换为 TOML 字符串
* 使用 @iarna/toml 的 stringify自动处理转义与嵌套表
*/
export const mcpServerToToml = (server: McpServer): string => {
export const mcpServerToToml = (server: McpServerSpec): string => {
const obj: any = {};
if (server.type) obj.type = server.type;
@@ -49,7 +49,7 @@ export const mcpServerToToml = (server: McpServer): string => {
};
/**
* 将 TOML 文本转换为 McpServer 对象(单个服务器配置)
* 将 TOML 文本转换为 McpServerSpec 对象(单个服务器配置)
* 支持两种格式:
* 1. 直接的服务器配置type, command, args 等)
* 2. [mcp.servers.<id>] 或 [mcp_servers.<id>] 格式(取第一个服务器)
@@ -57,7 +57,7 @@ export const mcpServerToToml = (server: McpServer): string => {
* @returns McpServer 对象
* @throws 解析或转换失败时抛出错误
*/
export const tomlToMcpServer = (tomlText: string): McpServer => {
export const tomlToMcpServer = (tomlText: string): McpServerSpec => {
if (!tomlText.trim()) {
throw new Error("TOML 内容不能为空");
}
@@ -104,7 +104,7 @@ export const tomlToMcpServer = (tomlText: string): McpServer => {
/**
* 规范化服务器配置对象为 McpServer 格式
*/
function normalizeServerConfig(config: any): McpServer {
function normalizeServerConfig(config: any): McpServerSpec {
if (!config || typeof config !== "object") {
throw new Error("服务器配置必须是对象");
}
@@ -116,7 +116,7 @@ function normalizeServerConfig(config: any): McpServer {
throw new Error("stdio 类型的 MCP 服务器必须包含 command 字段");
}
const server: McpServer = {
const server: McpServerSpec = {
type: "stdio",
command: config.command,
};
@@ -142,7 +142,7 @@ function normalizeServerConfig(config: any): McpServer {
throw new Error("http 类型的 MCP 服务器必须包含 url 字段");
}
const server: McpServer = {
const server: McpServerSpec = {
type: "http",
url: config.url,
};