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:
@@ -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 = () => {
|
||||
|
||||
@@ -13,6 +13,57 @@ export function formatJSON(value: string): string {
|
||||
return JSON.stringify(parsed, null, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 智能解析 MCP JSON 配置
|
||||
* 支持两种格式:
|
||||
* 1. 纯配置对象:{ "command": "npx", "args": [...], ... }
|
||||
* 2. 带键名包装: "server-name": { "command": "npx", ... } 或 { "server-name": {...} }
|
||||
*
|
||||
* @param jsonText - JSON 字符串
|
||||
* @returns { id?: string, config: object, formattedConfig: string }
|
||||
* @throws 如果 JSON 格式无效
|
||||
*/
|
||||
export function parseSmartMcpJson(jsonText: string): {
|
||||
id?: string;
|
||||
config: any;
|
||||
formattedConfig: string;
|
||||
} {
|
||||
let trimmed = jsonText.trim();
|
||||
if (!trimmed) {
|
||||
return { config: {}, formattedConfig: "" };
|
||||
}
|
||||
|
||||
// 如果是键值对片段("key": {...}),包装成完整对象
|
||||
if (trimmed.startsWith('"') && !trimmed.startsWith('{')) {
|
||||
trimmed = `{${trimmed}}`;
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(trimmed);
|
||||
|
||||
// 如果是单键对象且值是对象,提取键名和配置
|
||||
const keys = Object.keys(parsed);
|
||||
if (
|
||||
keys.length === 1 &&
|
||||
parsed[keys[0]] &&
|
||||
typeof parsed[keys[0]] === "object" &&
|
||||
!Array.isArray(parsed[keys[0]])
|
||||
) {
|
||||
const id = keys[0];
|
||||
const config = parsed[id];
|
||||
return {
|
||||
id,
|
||||
config,
|
||||
formattedConfig: JSON.stringify(config, null, 2),
|
||||
};
|
||||
}
|
||||
|
||||
// 否则直接使用
|
||||
return {
|
||||
config: parsed,
|
||||
formattedConfig: JSON.stringify(parsed, null, 2),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TOML 格式化功能已禁用
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user