feat(mcp): add smart JSON parser for flexible input formats

Support multiple MCP configuration input formats:
- Pure config object: { "command": "npx", ... }
- Key-value pair fragment: "server-name": { "command": "npx", ... }
- Wrapped object: { "server-name": { "command": "npx", ... } }

The parser automatically:
- Detects and wraps JSON fragments into complete objects
- Extracts server name from single-key objects
- Auto-fills ID and Name fields when applicable
- Formats the config for display

This improves UX by allowing users to paste configs directly from
.claude.json or .codex/config.toml without manual editing.
This commit is contained in:
Jason
2025-11-16 20:08:04 +08:00
parent f79efb86cd
commit 98a1305684
2 changed files with 85 additions and 8 deletions

View File

@@ -27,7 +27,7 @@ import {
mcpServerToToml,
} from "@/utils/tomlUtils";
import { normalizeTomlText } from "@/utils/textNormalization";
import { formatJSON } from "@/utils/formatters";
import { formatJSON, parseSmartMcpJson } from "@/utils/formatters";
import { useMcpValidation } from "./useMcpValidation";
import { useUpsertMcpServer } from "@/hooks/useMcp";
@@ -241,15 +241,41 @@ const McpFormModal: React.FC<McpFormModalProps> = ({
}
}
} else {
// JSON validation (use hook's complete validation)
const err = validateJsonConfig(value);
if (err) {
setConfigError(err);
return;
// JSON validation with smart parsing
try {
const result = parseSmartMcpJson(value);
// 验证解析后的配置对象
const configJson = JSON.stringify(result.config);
const validationErr = validateJsonConfig(configJson);
if (validationErr) {
setConfigError(validationErr);
return;
}
// 自动填充提取的 id仅当表单 id 为空且不在编辑模式时)
if (result.id && !formId.trim() && !isEditing) {
const uniqueId = ensureUniqueId(result.id);
setFormId(uniqueId);
// 如果 name 也为空,同时填充 name
if (!formName.trim()) {
setFormName(result.id);
}
}
// 如果智能解析提取了配置(格式转换),自动格式化输入框内容
if (result.id && result.formattedConfig !== value.trim()) {
setFormConfig(result.formattedConfig);
}
setConfigError("");
} catch (err: any) {
const errorMessage = err?.message || String(err);
setConfigError(t("mcp.error.jsonInvalid") + ": " + errorMessage);
}
}
setConfigError("");
};
const handleFormatJson = () => {